Choice
The branching beat: options, inline replies, locks, timers, interrupts, and card layouts.
A choice beat puts options on screen and stops. What each option does, it does through its own route: an edge into another scene, or a small inline body that plays and rejoins this scene. There is no separate "effects" field, because an inline body of set beats is that field.
Every choice needs at least one option. Choices cannot nest inside choices.
Beat fields
| Field | Type | Required | What it does |
|---|---|---|---|
id | string | yes | Stable beat id. |
kind | "choice" | yes | The discriminator. |
options | array, min 1 | yes | See below. |
presentation | "list" | "cards" | "grid" | no | Absent means list. |
columns | integer 1 to 8 | no | Fixed column count for cards and grid. Absent means auto-fit. |
timeout | { ms, optionId } | no | Absent means the choice waits forever. |
interrupt | boolean | no | The story plays on underneath the options. |
presentation and columns are purely how the options are drawn. Routing,
conditions, timers and cast picks are untouched by them.
Option fields
| Field | Type | Required | What it does |
|---|---|---|---|
id | string | yes | Stable option id. Conditions elsewhere can count how often it was taken. |
text | string | yes | The label. Tokens interpolate. |
route | object | yes | { type: "edge", edgeId } or { type: "inline", body }. |
condition | condition | no | Absent means always available. |
whenLocked | "hide" | "disable" | no | Absent means hide. |
castTarget | cast id | no | Clicking that character's avatar picks this option. |
propTarget | prop asset id | no | Clicking that placed prop picks this option. |
imageAsset | asset id | no | Card art, for cards and grid. |
altText | string | no | Description of the card image for assistive tech. |
Routes
Graph edge. The option jumps to the edge's target scene, abandoning
whatever the cursor was doing. Draw the edge in the flow view first, then pick
it in the option's edge dropdown, which lists edges as "From scene → To scene".
An edge id that no longer exists is DANGLING_CHOICE_ROUTE.
Inline body. The option plays a short body of line, stage, set and wait beats, then continues with the beat after the choice. Add rows with the "add line", "add stage", "add set" and "add wait" buttons under the option, and reorder them with the up and down arrows on each row. This is the right shape for a reply, a shrug, an item pickup: anything that does not deserve a scene.
Locking an option
A lock is a condition, not a flag. Write the condition in the option's
condition editor (see Conditions); when it
evaluates false, whenLocked decides what the reader sees:
hide, the default: the option is not rendered at all.disable: the option renders greyed out with a padlock, and is announced as "Locked" to screen readers.
Disable is the honest choice when you want the reader to know something is missable. Hide is right when the option's existence is itself a spoiler.
Timers
Tick timed in the beat header and two more controls appear: the milliseconds and a dropdown of this beat's own options for the default. Both are required, which is why a timeout is one object: a clock with nothing to hand the story to has no meaning.
The reader sees a draining gauge. When it runs out, the default option is taken exactly as if it had been clicked: it records the same "taken" counter, and the story moves past the choice. A save can never rest on a lapse that has not happened yet.
One rule surprises people: if the default option is hidden or disabled when the choice comes up, there is no countdown at all. The reader keeps the choice and picks. Taking a locked option would kill the playthrough, and inventing a different one is a story decision you did not write.
Interrupts
Tick interrupt and the story does not stop. The options sit on screen while the following beats play underneath, and the reader answers or does not. An unanswered interrupt expires when play crosses into another scene, and reaching any other choice replaces it: one choice surface at a time, last one wins.
Interrupt options must route by edge. An inline body has no unambiguous rejoin
point while the cursor is moving underneath it, so the compiler rejects it as
INTERRUPT_INLINE_ROUTE, the timeout default included. A timeout composes
normally: the countdown starts when the interrupt goes live.
Cards and grids
Switch presentation to cards (a wrapping row) or grid (a card grid over
the stage), then give each option a card image. The text label always renders
under the image, so a card is never an unlabeled picture. Set columns to pin
the layout to a fixed width, or leave it empty for auto-fit.
An imageAsset that is in the library but is not an image is
INVALID_CHOICE_IMAGE; one that is not in the library at all is
MISSING_ASSET.
Clickable picks
castTarget names a cast member. While the option is live and takeable,
clicking that character's staged avatar picks it. The text button stays on
screen regardless, as the accessible surface and as the fallback for a
character who is not currently on stage.
propTarget does the same for an object. It names a prop asset that a prop place direction has put on a mark; while the option is live, clicking that
prop picks it. Same rules: the text button always renders, and a prop that is
not placed, was removed, or failed to load simply has nothing to click. See
Props.
A worked example
The walkthrough's beats chapter builds this in three beats: a set beat hands the reader a key they cannot see, then a choice offers an option that only exists because of it.
line The set beat writes a variable. One just ran, and it handed you a key
you cannot see. flag wtKey = true.
set wtKey = on
choice
1. "Open the door this option was locked behind"
when wtKey == true if its condition fails: hide
inline body:
line Without that set beat, this option would have been hidden or
greyed out. Your call, per option, via whenLocked.
2. "Ignore the door"
inline body:
line Fair. But it only appeared because a set beat flipped a flag
two lines ago.Flip the first option's lock setting to disable and replay: the option is now
visible and dead instead of absent. Delete the set beat and replay again to see
what the reader sees when they never found the key.
What the reader gets
Options are numbered on screen, and the number keys 1 to 9 take them. Hidden options are not counted, so the digits always match the buttons the reader can see. Locked options keep their number and ignore the key.
Taking an option records a counter on that option's id, which is what
taken(...) conditions read later. See
Conditions.