Concept

Snapshot

Capture a mix state. Apply it later with a smooth crossfade. Your menu/gameplay/boss switcher in one call.

TL;DR

A Snapshot is an immutable record of bus levels, mutes, and parameter values. Capture once when the mix is right, then re-apply later with fade (in seconds) to crossfade the whole mix in one call. No more orchestrating ten fadeTo calls by hand.

Mental model

SNAPSHOT menu music sfx ui SNAPSHOT gameplay music sfx ui SNAPSHOT boss music sfx ui .apply({ fade: 0.25 }) crossfades the entire mix
Three named snapshots. apply() ramps every bus level (and parameter) in lockstep.

API surface

Snapshot ts
engine.captureSnapshot(name): Snapshot
engine.snapshot(name, state): Snapshot
engine.blendSnapshots(a, b, t): void   // snap mix to lerp(a, b, t)

class Snapshot {
  readonly name: string;
  readonly state: SnapshotState;
  apply(options?: { fade?: number }): Promise<void>;
  blendWith(other: Snapshot, t: number): void;
}

Live demo

Three presets, 800 ms crossfade between mixes.

Recipes

Capture from the live engine

ts ts
// Set the mix to a known-good "menu" state, then capture it.
engine.bus('music').level = 0.8;
engine.bus('sfx').level   = 0.3;
const menu = engine.captureSnapshot('menu');

Build from explicit state

ts ts
// Build a snapshot from explicit state — no need to mutate the live engine.
const boss = engine.snapshot('boss', {
  buses: {
    music: { level: 1.0, muted: false },
    sfx:   { level: 0.8, muted: false },
  },
  parameters: { intensity: 1.0 },
});

Switch with crossfade

ts ts
await menu.apply({ fade: 0.25 });        // crossfade everything in 250ms
await boss.apply({ fade: 0.8 });

Blend continuously between two snapshots

apply is a one-shot crossfade. For an interpolated mix that follows a knob — game tension, distance to a boss room, time of day — capture two snapshots and let a Parameter drive blendSnapshots.

ts ts
const calm   = engine.captureSnapshot('calm');
// ...switch the mix to its combat shape, then re-capture.
const combat = engine.captureSnapshot('combat');

// Snap the mix to lerp(calm, combat, t). Drive a Parameter to animate.
engine.blendSnapshots(calm, combat, 0.4);   // 40% of the way to combat

const tension = engine.parameter('tension', 0);
tension.subscribe((t) => engine.blendSnapshots(calm, combat, t));
tension.set(0.75);                          // per-frame friendly

Each call snaps the mix instantly (every bus level setter still rides a 10 ms anti-click ramp internally), so calling it on every frame is cheap. Buses or parameters that aren't present in both snapshots are skipped. Mute flips at t = 0.5 rather than interpolating. The snapshot-blend example wires a slider through a Parameter end-to-end.

Pitfalls

Snapshots don't include voices.
They restore the mix, not what's playing on it. If you need a "boss music starts" effect, trigger the boss music yourself then apply the snapshot.
Capturing twice does not snapshot motion.
A snapshot is a single moment. To animate a fade-in over time, drive a Parameter instead.

Related

  • Parameter — for continuous values.
  • Mixer — the bus state being captured.