Audio
Play sound effects, music and positional audio through AudioBus, mix categories apart, and check in a playtest which sounds the game played.
On this page
Play a sound
An AudioBus owns a group of sounds and attaches its listener to a camera. Load buffers once
through ctx.assets.audio and reuse them.
import { AudioBus } from "@threenative/core";
const effects = new AudioBus({ camera: ctx.camera, maxVoices: 24 });
const hit = await ctx.assets.audio("audio/hit.ogg");
// On a gameplay event, not every frame:
effects.play(hit, { cue: "player-hit", volume: 0.6 });Browsers block audio until the player interacts with the page. The bus waits for that gesture
and queues sounds until then. Call dispose() when the owning scene or service ends.
Play options
| Option | Effect |
|---|---|
volume |
Linear gain for this sound |
loop |
Repeat until stopped |
fade |
Fade-in time in seconds |
cue |
A label that playtests can count. It does not change the sound. |
refDistance |
Metres from the source where distance falloff begins (playAt only) |
rolloffFactor |
How fast volume drops past refDistance. 0 means no falloff (playAt only). |
detune |
Pitch offset in cents. Web only. |
lowpassHz |
Low-pass filter corner in Hz. Web only. |
cutoffSeconds |
Cut the sound off after this many seconds |
Voices and positional sound
Each sounding clip uses a voice. The bus reuses voices and allows 48 one-shots at once by
default. Set maxVoices to change that. Past the limit, the oldest one-shot stops and the new
sound takes its slot. Looping sounds do not count toward the limit, so stop them yourself.
music(buffer, options) is play with loop: true by default.
play returns the voice. Treat it as valid only while that sound plays, because the bus reuses
it afterwards. Call stopVoice(voice) to stop one sound early.
playAt(buffer, source, options) plays a sound in the world. Pass an Object3D as source and
the sound follows it, or pass a Vector3 for a fixed spot. Three.js defaults refDistance to
1 m, which makes a sound 20 m away nearly silent. Tune both distance options to your world scale.
Mix and pause
effects.pause(); // opening a pause menu
effects.resume(); // back to gameplay
effects.setVolume(0.4, 0.2); // linear gain, fade in secondspause() and resume() keep each sound's position. stop() ends playback. setVolume moves the
whole bus and applies to sounds already playing.
Create one bus each for music, effects and ambience to mix them apart. Buses that share a
listener also share its master volume.
Native formats
The native runtime decodes only RIFF/WAVE and Ogg Vorbis. An MP3 plays nothing on any native target, so the asset build fails on it and names the file to re-encode.
The native host does not implement detune or lowpassHz. It ignores them and lists them in the
bus's unsupported report. Check that your mix still works without them.
You can declare loops and positional clips in threenative.config.ts. The build then cross-fades
loop seams and downmixes positional clips to mono.
assets: {
audio: {
overrides: [
{ glob: "audio/*-bed.ogg", loop: true },
{ glob: "audio/step-*.ogg", positional: true },
],
},
},The asset pipeline README covers normalisation, spectrum checks and the other declarations.
Check audio in a playtest
Give important sounds a cue label. ThreeNative counts every labelled cue and keeps a short
history. A playtest scenario can then assert that a hit sound fired, or that a
narration line played only once. Audio assertions run on web and desktop.
audio: [{ cue: "speech:p01", maxPlays: 1 }]Cue counts show what the game asked for. Listen on your target device too, for speech clarity, distance falloff and the balance between music and effects.