NarraLeaf

Moving from Ren'Py

NarraLeaf uses TypeScript objects instead of a separate script language. The closest concepts are:

Ren'PyNarraLeaf React
labelScene
jumpscene.jumpTo(otherScene)
scene bg roomScene background or scene.setBackground()
show eileen happyimage.show() then image.char(["happy"])
hide eileenimage.hide()
e "Hello"character.say("Hello")
menuMenu.prompt().choose()
default / persistent variablePersistent
screen languageReact components inside Player
with dissolvenew Dissolve({ duration })

The names are similar, but the boundaries differ. A NarraLeaf Character only owns dialog identity and avatar rules. A stage Image owns the sprite. A Scene is closer to a Ren'Py label than to Ren'Py's scene statement.

A small translation

Ren'Py:

define a = Character("Alice")

label start:
    scene bg room
    show alice happy at center
    with dissolve
    a "Good morning."

    menu:
        "Open the window":
            $ opened_window = True
            jump window
        "Stay in bed":
            jump sleep

NarraLeaf React:

import {
    Character,
    Dissolve,
    Image,
    Menu,
    Scene,
    Story,
} from "narraleaf-react";

const story = new Story("morning");
const state = story.createPersistent("state", { openedWindow: false });
const alice = new Character("Alice");
const aliceSprite = new Image({
    src: {
        groups: [["happy", "sleepy"]],
        defaults: ["happy"],
        resolve: (expression) => `/characters/alice-${expression}.webp`,
    } as const,
});

const windowScene = new Scene("window");
const sleepScene = new Scene("sleep");
const start = new Scene("start", {
    background: "/backgrounds/room.webp",
}).action((scene) => [
    aliceSprite.show(),
    aliceSprite.char(["happy"], new Dissolve({ duration: 400 })),
    alice.say("Good morning."),
    Menu.prompt("What should I do?")
        .choose("Open the window", [
            state.set("openedWindow", true),
            scene.jumpTo(windowScene),
        ])
        .choose("Stay in bed", [
            scene.jumpTo(sleepScene),
        ]),
]);

story.entry(start);

UI and screens

NarraLeaf does not ship a screen language. Settings, save slots, history, galleries, and menus are React components. Put routed pages inside Player, and replace the dialog, menu, NVL, or notification slots through Game configuration.

Start with Basic, then use Page Overlay, Custom Dialog, and Save System for common engine UI.

Differences to plan for

  • There is no rollback UI by default, though liveGame.undo() provides the underlying action.
  • Save data is serializable, but you build the storage and slot UI.
  • Assets are URLs or bundler imports. Web preload and browser audio rules apply.
  • Transforms and transitions are TypeScript objects, not ATL blocks.
  • React owns interface layout and accessibility.

On this page