Sound
Sound effects, background music, and voice clips with Sound, and running playback alongside the story with Control.doAsync.
Use Sound for sound effects, background music, and voice clips. The static constructors mark each sound with the correct type.
import { Sound } from "narraleaf-react";
const door = Sound.sound({
src: "/audio/door.ogg",
volume: 0.8,
});
const theme = Sound.bgm({
src: "/audio/theme.ogg",
volume: 0.5,
loop: true,
});Sound effects
play() is an action. By default, the story waits for the clip to finish.
scene.action([
door.play(),
alice.say("Someone is here."),
]);To let the story continue while a sound plays, run it on an asynchronous control stack.
import { Control } from "narraleaf-react";
scene.action([
Control.doAsync([door.play()]),
alice.say("The door closes behind you."),
]);The old sync option no longer exists. Use Control.doAsync() or Control.allAsync() for non-blocking audio.
Background music
Set BGM on the scene config, or change it during the scene. The fade value is in milliseconds.
const room = new Scene("room", {
backgroundMusic: theme,
backgroundMusicFade: 800,
});
room.action([
room.setBackgroundMusic(Sound.bgm("/audio/night.ogg"), 800),
]);Pass null to stop the current BGM.
room.setBackgroundMusic(null, 500);Intros and loop regions
seek is a clip's in point and endTime is its out point. With loop, the pair becomes a loop
region, and loopStart says where each repeat returns to — which is how background music with an
intro plays the opening once and then repeats only its body.
const theme = Sound.bgm({
src: "/audio/theme.ogg",
loop: true,
seek: 0, // the first pass starts at the top
loopStart: 12, // every repeat returns here, after the intro
endTime: 90,
});The repeat is sample-accurate — no gap at the seam, no drift over a long session. See ISoundUserConfig.
To move the play head of a clip that is already playing, use seek() as an action:
room.action([
theme.seek(12), // skip the intro
]);Volume and buses
Every clip plays on an audio bus, chosen by its type. A game gets bgm, sound and voice
without asking, and can declare more — a bus per character, say — to give the player controls the
three fixed ones cannot express. See Audio Buses.
Playback controls
Sound actions can change playback state and values.
scene.action([
door.setVolume(0.3, 300),
door.setRate(1.2),
door.pause(200),
door.resume(200),
door.mute(),
door.unmute(),
door.stop(300),
]);Inside React UI, use liveGame.playSound() for immediate playback instead of adding a story action.
const liveGame = useLiveGame();
<button onClick={() => liveGame.playSound("/audio/click.ogg")}>Play</button>