Stage
The beat that changes the 3D stage instead of the text: its thirteen action types and the parallel flag.
A stage beat (a stage direction) carries exactly one action and no text. It moves a character, turns them, plays a clip on them, changes an expression, moves the camera, places a prop, changes the light or the weather, starts or stops audio, fires a screen effect, or puts full-screen media over the stage.
This page is the field list. For what the stage actually is, how a scene is staged, and what each direction looks like, read Stage directions, Props and Staging a scene.
Fields
| Field | Type | Required | What it does |
|---|---|---|---|
id | string | yes | Stable beat id. |
kind | "stageDirection" | yes | The discriminator. |
action | object | yes | One of the thirteen shapes below. |
parallel | boolean | no | Absent or false holds the script. See below. |
The thirteen actions
type | Fields | Notes |
|---|---|---|
move | target (cast id), to (mark or "offstage"), gait, optional face | gait is walk, jog, run or cut. face is applied on arrival and takes the same values as face.toward. |
face | target (cast id), toward (cast id, "camera" or "away") | Turns the character in place. |
animation | target (cast id), clip (name), optional loop | The picker lists clips parsed out of your animation assets, plus assets by id. Free text is allowed for a clip embedded in the character's own model. loop: true makes the clip the resting idle. |
camera | preset, optional target (cast id) | wide, two-shot, close-up, over-shoulder. target frames that member instead of the speaker. |
expression | target (cast id), expression | A select of the target model's own expression names when we have them, with a custom entry for free text; otherwise the six VRM presets: happy, angry, sad, relaxed, surprised, neutral. |
prop | op (place / remove), asset or binding, at (mark or { heldBy }) | The asset must be a prop asset. See Props. |
inspect | asset or binding | Opens the orbit viewer on that prop. A hold the reader releases. |
light | preset | day, dusk, night, candle, neon, storm. |
weather | kind | none, rain, snow, petals, embers, fog. |
music | op (play / stop), asset or binding, gain, fadeMs, loop | Loops by default. |
sfx | same as music | Does not loop by default. |
effect | effect | shake, flash, or letterbox. Letterbox is a toggle: the second one turns it off. |
cutaway | op (show / end), asset or binding | One op for both images and video. The player reads the asset's type. |
gain runs 0 to 1 and the field says so when you type something outside that
range. fadeMs is the fade in on play and the fade out on stop. All three audio
extras are optional; left empty, the director's defaults apply.
One of each new one, as the row reads:
stage move Kai to center walk then face Mira
stage face Mira toward Kai
stage animation Kai Sitting_Idle_Loop loop
stage camera close-up on Mira
stage prop place lantern held by Kai
stage inspect lantern
stage light night
stage weather rainNaming an asset through a variable
The audio, cutaway, prop and inspect actions accept either a literal asset or a binding:
the name of a declared text variable holding an asset id. Pick "asset from" in
the row instead of "asset". A set theme = "m-storm" upstream then chooses the
track, and the same stage beat plays whatever the story picked.
Naming both a literal asset and a binding on one action is
INVALID_ASSET_BINDING: two answers to one question. So is binding to a
variable that is neither asset-typed nor text. If the binding resolves to
nothing usable (unset,
not a string, or an asset id that is not in the library) the action still fires,
just without audio or media. It fails quietly on purpose, the same way a pruned
asset does.
Parallel, and the hold
parallel decides whether the script waits.
parallel: false(the default, checkbox clear) is a hold. The player emits the action and rests on this beat until the action's own chain resolves. A reader tapping the screen does not release a hold.parallel: trueruns the action alongside the beats that follow. Music under dialogue is the standard case.
The hold is why a non-parallel cutaway genuinely gates the next line until the
clip ends, with no duration hard-coded anywhere, and why a non-parallel move
gates it until the character arrives. The old recipe of a parallel cutaway
followed by a wait beat is obsolete. Actions that only set state (face,
prop, light, weather, camera, expression) resolve at once either way.
A held beat cannot be tapped past. If a story appears to freeze on a stage beat during preview, the action it is holding on never resolved: an asset that will not load, or a clip that is not there.
Inside a choice option
Stage beats are legal inside a choice option's inline body, and they edit
exactly as they do at the top level, parallel included. That is how you fire
one sting on one branch without spending a scene on it.
Compile-time errors you may see
| Error | Cause |
|---|---|
UNKNOWN_CAST | A target, a face or toward naming a member, a prop's heldBy, or a camera target names no cast member. |
MISSING_ASSET | asset is not in the project library. |
INVALID_CLIP_REF | clip is a library asset id, but not an animation asset. |
INVALID_PROP_ASSET | A prop or inspect asset that is in the library but is not a prop. |
INVALID_CUTAWAY_REF | A cutaway show pointing at something that is neither an image nor a video, or at nothing at all. |
INVALID_ASSET_BINDING | Both asset and binding on one action, or a binding to a variable that is not asset-typed or text. |
Camera presets, effects, gaits, light presets and weather kinds are
enum-checked by the schema, so a bad one is INVALID_BEAT rather than a rule
of its own.