NarraLeaf

Control

Control is a class that has some utility methods for flow control.

Control.do([
    character1.say("hello"),

    // play sound and shake image at the same time
    Control.allAsync([
        sound.play(),
        shake(image1),
    ]),
]);

Static Method

do

Execute actions in order, waiting for each action to complete

  • actions: ActionStatements - ActionStatements
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

doAsync

Execute actions in order, do not wait for this action to complete

  • actions: ActionStatements - ActionStatements
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

any

Execute all actions at the same time, waiting for any one action to complete

  • actions: ActionStatements - ActionStatements
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

all

Execute all actions at the same time, waiting for all actions to complete

  • actions: ActionStatements - ActionStatements
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

allAsync

Execute all actions at the same time, do not wait for all actions to complete

  • actions: ActionStatements - ActionStatements
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

repeat

Execute actions multiple times

  • times: number - times
  • actions: ActionStatements - ActionStatements
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

whileLoop

Execute actions while condition is true

const loopState = new Persistent("loop-state", {
    tries: 0,
});

story.registerPersistent(loopState);

scene.action([
    loopState.set("tries", 0),

    Control.whileLoop(loopState.evaluate("tries", (tries) => tries < 3), [
        character.say`Attempt ${loopState.get("tries")}`,
        loopState.set("tries", (tries) => tries + 1),
    ]),
]);
  • condition: Lambda<boolean> | LambdaHandler<boolean> - condition to check
  • actions: ActionStatements - ActionStatements
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

breakLoop

Break the current loop (repeat/while) Can only be used inside a loop body

scene.action([
    Control.whileLoop(loopState.evaluate("tries", (tries) => tries < 10), [
        Condition.If(loopState.equals("tries", 3), [
            character.say("Stop here."),
            Control.breakLoop(),
        ]),
        loopState.set("tries", (tries) => tries + 1),
    ]),
]);
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

sleep

Sleep for a duration

  • duration: number | Awaitable<any> | Promise<any> - sleep duration
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

waitForClick

Pause execution until the user clicks anywhere on the stage (excluding GUI elements such as dialog, buttons, menus). Similar to inserting a pause with no duration in a Sentence.

Useful for creating "click to continue" moments in ADV mode, or for pausing within NVL blocks until the player is ready to proceed.

scene.action([
    character.say("Read this carefully..."),
    Control.waitForClick(),
    character.say("Now we continue."),
]);
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

label

Mark a named point inside the current scene that jump can jump to. A label is invisible at runtime — it simply passes through to the next action.

Label names are scoped to the scene they are declared in, so the same name may be reused across different scenes. Declaring the same name twice in one scene fails the build.

scene.action([
    Control.label("intro"),
    character.say("Let's begin."),
]);
  • name: string - the label name, unique within its scene
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

jump

Jump to a label elsewhere in the same scene and resume playing from there.

Unlike Scene.jumpTo, this stays inside the current scene — no scene is unloaded or re-initialized, only the play head moves. The target must be a label declared in the same scene, otherwise the story fails to build.

Control.jump redirects the main story flow, so place it as the last action of a branch (such as a menu choice). To loop a scene, drive the loop through a menu or condition rather than jumping out of a repeat / while body.

scene.action([
    Control.label("start"),
    Menu.prompt("Again?")
        .choose("Yes", [Control.jump("start")])
        .choose("No", []),
]);
  • name: string - the name of the target label, declared in the same scene
  • Returns Proxied<Control, Chained<LogicAction.Actions>> - Chained Control instance

On this page