AudioManager
The AudioManager system owns the audio mixer for your game: a bus tree with parent / child relationships, default fader levels in dB, ducking rules between buses, and a voice pool that caps simultaneous playback.
Open it from Inspector → Systems → AudioManager → Open. The editor renders the mixer visually so you can see and tune everything at once.
Bus tree
Section titled “Bus tree”A bus is a named audio channel with an optional parent and a default fader level (dB, from -60 to +6).
Common shapes:
Master├── Music├── SFX│ ├── SFXOneshot│ └── SFXLoop├── Dialog└── UIThe Master bus is the root; everything else hangs off it. A child bus’s gain is multiplied by its parent’s, so muting Master mutes everything.
To add a bus, click + Add bus in the editor. Each bus gets:
- A name (required, unique).
- A parent (optional; defaults to “no parent” which makes it a root).
- A default dB (-60 to +6).
Names go into your code (audio.playSfx('/audio/coin.wav', { bus: 'SFXOneshot' })), so pick them carefully. Renaming a bus is a hand-edit-everywhere operation.
Ducking rules
Section titled “Ducking rules”Ducking lowers the volume on one or more buses whenever a different bus emits sound. The canonical example: when Dialog plays, Music ducks by 8 dB and SFXLoop ducks by 6 dB so the player can hear the line.
Each rule has:
- A trigger bus (
whenBus): the source that causes the duck. - A list of targets: each with the bus name, the amount in dB to duck, an attack time in ms, and a release time in ms.
The defaults in the bundled bundles are tuned for typical game audio:
| Pattern | Attack | Release | Why |
|---|---|---|---|
| Music ducking under Dialog | 80 ms | 250 ms | Fast enough to clear the first word, soft enough not to pop |
| SFXLoop ducking under Dialog | 80 ms | 250 ms | Same shape; loops are usually ambient |
| SFXLoop ducking under SFXOneshot | 40 ms | 150 ms | Quick punch for hit / pickup feedback |
The editor surfaces the rules as a visual matrix so you can see at a glance which bus ducks which.
Voice pool
Section titled “Voice pool”The voicePoolSize field caps how many concurrent audio sources can play at once. The Web Audio API has practical limits on simultaneous sources; 16 is a sensible default for most games. Bump it for sound-dense games (twin-stick shooters, bullet hells), lower it for narrative games where you want to guarantee dialogue never gets crowded out.
When the pool is full, the AudioManager’s behavior depends on the source’s priority: low-priority oneshots are dropped, high-priority lines wait.
Common patterns
Section titled “Common patterns”Music crossfade on level transition: call audio.crossfade('Music', '/audio/music/forest.ogg', 800). The current music fades out over 800ms while the new track fades in.
Dialogue voice-over: route to the Dialog bus. The ducking rule fires automatically; you don’t need to manually lower Music every time.
One-shot SFX (jump, coin, hit): route to SFXOneshot. Pool eviction picks the oldest oneshot when the pool fills.
Looping ambience (wind, water, machinery): route to SFXLoop. Don’t put it on SFXOneshot; the eviction strategy will kill your ambience the moment any other oneshot fires.
Editing the config by hand
Section titled “Editing the config by hand”The AudioManager’s config in .forge/gamemanager.toml looks like:
[systems.AudioManager.config]voicePoolSize = 16buses = [ { name = "Master", defaultDb = 0 }, { name = "Music", parent = "Master", defaultDb = -6 }, { name = "SFX", parent = "Master", defaultDb = -3 }, { name = "Dialog", parent = "Master", defaultDb = 0 },]duckingRules = [ { whenBus = "Dialog", duck = [ { bus = "Music", amountDb = -8, attackMs = 80, releaseMs = 250 }, { bus = "SFX", amountDb = -6, attackMs = 80, releaseMs = 250 }, ] }]Hand-edit it and the editor will pick up your changes on next load. Validation: bus names must be unique, every parent must reference an existing bus, dB values are clamped to the -60 to +6 range.