NarraLeaf

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>

On this page