Sound
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>