Public roadmap

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.

Status
Shipped in v1.13.0
Runtime + lazy AudioContext, mixer + buses + click-free fades, FX chain (compressor / filter / reverb / ducker / pitch-preserving stretch), spatializer (2D + 3D), parameters, snapshots, concurrency policies, codec ladder, voice jitter, scheduler.
Not on this roadmap
Framework adapters (React/Vue/Svelte). Visual node-graph editor. WASM DSP. Native bridge for React Native or Electron-specific paths. HRTF spatializer beyond stock PannerNode HRTF. These remain out-of-scope for the foreseeable.
v1.1 → v1.12

Recently shipped

Roughly one feature per minor release. Most recent first.

  1. 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/
    medium
  2. 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/
    large
  3. 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
  4. 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
  5. 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
    medium
  6. Audit cleanups (v1.4)

    Real Filter bypass, dead BankNotLoadedError removed, honest 'quietest' fallback warning until per-voice metering shipped in v1.7.

    small
  7. 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
  8. 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/
    medium
  9. Click-free voice.stop() (v1.1)

    Tiny gain ramp before source.stop() suppresses the click that fires when buffers are cut mid-waveform.

    small
v1.0.0

First stable release

The headline change was a unit normalization across the public API.

  1. 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
    medium
Shipped

Roadmap tier sweep

A roadmap-tier sweep — every actionable item from Tiers 1–4, end-to-end. Framework adapters remain out of scope.

  1. 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/
    medium
  2. Solo + busGroup

    bus.solo() mutes everyone else; engine.busGroup(name, [...buses]) addresses several buses at once.

    related: /concepts/bus/
    small
  3. engine.masterMeter()

    Live RMS + peak on the master output — same shape as bus.meter() / voice.level().

    small
  4. Spatializer distance config

    refDistance / maxDistance / rolloffFactor / distanceModel per voice, tunable live via the Spatializer set* methods.

    related: /concepts/spatializer/
    medium
  5. Variants helper

    engine.loadVariants(name, urls) + engine.variants(name).play() with random / no-repeat / shuffle-bag strategies.

    small
  6. 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
  7. engine.unloadSound(name, { evictBuffer })

    Drop a sound and evict its decoded buffer from the LRU — for hot-swapping themes.

    small
  8. Branded bus / sound names

    createEngine({ buses }) infers the bus-name union so engine.bus("typo") fails at compile time.

    medium
  9. createEngine({ latencyHint })

    Maps to AudioContext latencyHint — 'interactive' for reactive game audio, 'playback' for music players.

    small
  10. Live spatializer control on Voice

    voice.spatializer.setPan / setPosition during playback.

    related: /concepts/spatializer/
    small
  11. Voice pause / resume

    voice.pause() / resume() with offset retention.

    related: /concepts/voice/
    small
  12. Live voice.playbackRate setter

    voice.setPlaybackRate(rate, { duration, curve }) with optional ramp.

    related: /concepts/voice/
    small
  13. Audio sprites

    engine.loadSprite(name, url, regions) → engine.sprite(name).play(region).

    medium
  14. Stream source

    engine.loadStream(name, url) — HTMLAudioElement + MediaElementAudioSource for long media.

    medium
  15. Loudness normalization on load

    loadSound(..., { normalize: true }) — RMS target with peak ceiling.

    medium
  16. Better error messages

    BusNotFoundError("sxf"; did you mean "sfx").

    related: /concepts/engine/
    small
  17. Realtime stretch via AudioWorklet

    ensureStretchWorklet(ctx) + createStretchWorkletNode(ctx) with live `stretch` AudioParam.

    related: /fx/pitch/
    large
  18. Master limiter

    master.limiter config wires a fast-attack DynamicsCompressor on master out.

    related: /concepts/mixer/
    small
  19. Crossfade helper

    engine.crossfade(from, to, { duration, curve }) — equal-power by default.

    small
  20. Examples directory

    Vanilla deployable apps under /examples/ (slot-machine, match-3, fps-footsteps).

    large
  21. npx zvuk transcode

    ffmpeg ladder (webm/opus + m4a/aac) packaged as a CLI.

    related: /guides/asset-formats/
    small
  22. npx zvuk gen bank.json

    Typed sound-name module emitted from a manifest.

    medium
  23. Bench suite

    vitest bench/ for voice spawn, decode + cache, fade drift.

    medium
  24. Auto-generated /api/ from TypeDoc

    TypeDoc JSON → Astro pages, regenerated each build.

    medium
  25. Pagefind search

    ⌘K modal indexed at build time.

    small
  26. Auto changelog page

    /changelog/ built from .changeset/*.md.

    small
  27. OG images

    Per-page social cards via astro-og-canvas.

    small
Tier 3

For "library people adopt"

Not just "library that works."

  1. Per-voice FX

    FX inserts are bus-level today. No way to put a flanger on one voice without dedicating a bus to it.

    large
Tier 4

Polish

Can wait, but on the list.

  1. engine.recordOutput()

    Capture the master to a Blob via MediaStreamDestination. Casino "show-mode" replays — niche but specific.

    medium
  2. Android focus / interruption tracking

    iOS 'interrupted' state is handled. Android focus loss is similar and we currently lean on visibilitychange only.

    medium
Contribute

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