Architecture
Responsibilities
The package is four focused layers with no application singleton:
init.tsowns the gesture-gated start transaction. Tone unlock and caller bootstrap either both complete or the next gesture may retry.buses.tsowns continuous Tone signal flow. The first caller-provided bus is the master and routes through a -1 dBFS limiter to the destination.sprite-resolver.tsowns Howler sample sheets. It validates and flattens the map, creates oneHowlper file, and tracks active sound IDs by target bus.preferences-bridge.tstranslates persisted percentages and mute policy into the two runtime engines without owning persistence.
The Node-only build-tools export is a separate entry point so filesystem and
process modules cannot enter a browser bundle.
Invariants
- Audio initialization is never started during module evaluation.
startedmeans both Web Audio unlock and caller bootstrap succeeded.- A bus topology cannot change silently; dispose before rebuilding it.
- Configured gain, duck attenuation, and mute reasons are independent state.
- Manual, focus-loss, and global-preference mutes cannot undo one another.
- Resolver initialization is idempotent for identical options and rejects different options until disposal.
- Preference read/update transactions are serialized per store so concurrent sliders cannot overwrite a newer runtime or persisted value with stale state.
- Every active Howler sound retains its target bus so live volume and mute changes affect loops and long samples, not only future playback.
- Public runtime imports do not evaluate Node-only build tooling.
Lifecycle and cleanup
registerAudioGestureTrigger returns a listener cleanup. disposeBuses clears
duck timers and Tone nodes. disposeSpriteResolver unloads Howls, clears active
sound bookkeeping, and allows initialization with new options. _resetAudioEngine
is retained for existing test/hot-reload integrations; application shutdown
normally needs the returned listener cleanup plus the two disposal functions.
Error policy
Programmer errors such as invalid topology, non-finite gain, path traversal, or malformed verifier configuration throw immediately. Runtime sprite acquisition degrades to an empty resolver by default because audio may be optional; strict mode turns the same failure into a rejected bootstrap transaction. Persistence errors are rethrown after restoring the prior runtime mix.
