What's next
An honest punch list of what would make zvuk better, ordered by impact. No promises on dates — this is intent, not a release schedule. PRs welcome on anything sized small.
Recently shipped
Roughly one feature per minor release. Most recent first.
- medium✓ Snapshot blend (v1.12)
engine.blendSnapshots(a, b, t) snaps the mix to a linear interpolation between two captured snapshots. Wire it through a Parameter and you get continuous "calm ↔ combat" or "menu ↔ game" mix automation driven by one knob. The Wwise primitive the roadmap pointed at.
related: /concepts/snapshot/ - large✓ Music source — stinger → loop → outro (v1.8)
engine.loadMusic(name, { intro, loop, outro }) + MusicVoice.skipToOutro({ at: "loop-end" | "now" }). The pattern every casino slot, action game, and rhythm game uses for combat/win/menu music. Click-free at the loop boundary via loopCrossfade.
related: /concepts/music/ - medium✓ voice.level() + bus.meter() — live amplitude readouts (v1.7)
Lazy AnalyserNode taps. Drove rhythm-metronome example, mixer dashboards, and the real "quietest" voice-stealing strategy.
related: /concepts/bus/ - medium✓ engine.preload(items, { signal, concurrency, onProgress }) (v1.6)
First-class bulk loader for loading screens. Per-item progress, concurrency cap, aggregated PreloadError.
related: /guides/loading/#first-class-preloader-engine-preload - medium✓ loopCrossfade play option (v1.5)
Off-by-default equal-power crossfade at the loop boundary so non-zero-crossing music regions don't click.
related: /concepts/voice/#loop-crossfade-off-by-default - small✓ Audit cleanups (v1.4)
Real Filter bypass, dead BankNotLoadedError removed, honest 'quietest' fallback warning until per-voice metering shipped in v1.7.
- medium✓ createEngine({ resolveAsset }) hook (v1.3)
Adopt buffers from Pixi Assets.cache, IndexedDB, or any external asset system without zvuk depending on it.
related: /guides/asset-resolution/ - medium✓ tickSource injection + autoPauseOnHidden (v1.2)
Wire the scheduler into a host's render loop (Pixi/GSAP) instead of setTimeout, and opt out of visibility-pause for music players.
related: /guides/runtime-timing/ - small✓ Click-free voice.stop() (v1.1)
Tiny gain ramp before source.stop() suppresses the click that fires when buffers are cut mid-waveform.
First stable release
The headline change was a unit normalization across the public API.
- medium✓ Normalize all time-valued options to seconds
Fades, crossfades, snapshot apply, Ducker/Sidechain attack/release — all in seconds now. Field renames: ms → duration, fadeMs → fade. Aligns with Web Audio (currentTime, AudioParam scheduling) and removes the *1000/÷1000 bug class. Breaking; migration table in CHANGELOG.
related: /changelog/#v1.0.0
Roadmap tier sweep
A roadmap-tier sweep — every actionable item from Tiers 1–4, end-to-end. Framework adapters remain out of scope.
- medium✓ Bus sends / aux
engine.bus(src).send(engine.bus(dest), { amount }) routes a copy of one bus into another (e.g. a verb-only bus).
related: /concepts/bus/ - small✓ Solo + busGroup
bus.solo() mutes everyone else; engine.busGroup(name, [...buses]) addresses several buses at once.
related: /concepts/bus/ - small✓ engine.masterMeter()
Live RMS + peak on the master output — same shape as bus.meter() / voice.level().
- medium✓ Spatializer distance config
refDistance / maxDistance / rolloffFactor / distanceModel per voice, tunable live via the Spatializer set* methods.
related: /concepts/spatializer/ - small✓ Variants helper
engine.loadVariants(name, urls) + engine.variants(name).play() with random / no-repeat / shuffle-bag strategies.
- small✓ play({ fadeIn })
Fade a voice up from 0 over fadeIn seconds at start — the dual of the click-free stop fade.
related: /concepts/voice/ - small✓ engine.unloadSound(name, { evictBuffer })
Drop a sound and evict its decoded buffer from the LRU — for hot-swapping themes.
- medium✓ Branded bus / sound names
createEngine({ buses }) infers the bus-name union so engine.bus("typo") fails at compile time.
- small✓ createEngine({ latencyHint })
Maps to AudioContext latencyHint — 'interactive' for reactive game audio, 'playback' for music players.
- small✓ Live spatializer control on Voice
voice.spatializer.setPan / setPosition during playback.
related: /concepts/spatializer/ - small
- small✓ Live voice.playbackRate setter
voice.setPlaybackRate(rate, { duration, curve }) with optional ramp.
related: /concepts/voice/ - medium✓ Audio sprites
engine.loadSprite(name, url, regions) → engine.sprite(name).play(region).
- medium✓ Stream source
engine.loadStream(name, url) — HTMLAudioElement + MediaElementAudioSource for long media.
- medium✓ Loudness normalization on load
loadSound(..., { normalize: true }) — RMS target with peak ceiling.
- small
- large✓ Realtime stretch via AudioWorklet
ensureStretchWorklet(ctx) + createStretchWorkletNode(ctx) with live `stretch` AudioParam.
related: /fx/pitch/ - small✓ Master limiter
master.limiter config wires a fast-attack DynamicsCompressor on master out.
related: /concepts/mixer/ - small✓ Crossfade helper
engine.crossfade(from, to, { duration, curve }) — equal-power by default.
- large✓ Examples directory
Vanilla deployable apps under /examples/ (slot-machine, match-3, fps-footsteps).
- small✓ npx zvuk transcode
ffmpeg ladder (webm/opus + m4a/aac) packaged as a CLI.
related: /guides/asset-formats/ - medium✓ npx zvuk gen bank.json
Typed sound-name module emitted from a manifest.
- medium✓ Bench suite
vitest bench/ for voice spawn, decode + cache, fade drift.
- medium✓ Auto-generated /api/ from TypeDoc
TypeDoc JSON → Astro pages, regenerated each build.
- small✓ Pagefind search
⌘K modal indexed at build time.
- small✓ Auto changelog page
/changelog/ built from .changeset/*.md.
- small✓ OG images
Per-page social cards via astro-og-canvas.
For "library people adopt"
Not just "library that works."
- largePer-voice FX
FX inserts are bus-level today. No way to put a flanger on one voice without dedicating a bus to it.
Polish
Can wait, but on the list.
- mediumengine.recordOutput()
Capture the master to a Blob via MediaStreamDestination. Casino "show-mode" replays — niche but specific.
- mediumAndroid focus / interruption tracking
iOS 'interrupted' state is handled. Android focus loss is similar and we currently lean on visibilitychange only.
Pick one and PR it
Items sized small are usually a single file plus a test. Items sized medium typically touch 2–4 files. Items sized large are worth opening an issue first to align on shape.
Open an issue