story/story.json — file map
A JSON array of moments. With script.txt, each entry patches the matching script scene by id (direction only — dialogue usually stays in the script). Without a script, the array is the whole story. You rarely type every field by hand; start from The same beat as data.
The whole file
The file is a JSON array. Each { … } is one moment. Linked entries jump to that section. Under each section, Keys lists type, If omitted, allowed values, and a short note.
[
{ … }, // one moment — any id; with a script, match :: id
{ … } // more moments — same shape
]
moment
One moment — any id; with a script, match :: id.
{
"id": "park", // moment id
"talking": "hana", // who speaks
"talking_anchor": "hana", // initial focus
"label": "Hana", // name-plate text
"text": "Watch the meter.", // dialogue body
"text_ref": "line.park.1", // strings catalog key
"text_from": "earlier_node", // copy text from node
"set": {"met_hana": true}, // flags on enter
"commands": [{"type": "bg", "value": "street"}], // enter commands
"flow_commands": [[{"type": "sfx", "value": "click"}]], // mid-line batches
"exit_commands": [{"type": "char", "name": "hana", "show": false}], // leave commands
"exit_delay": 0.3, // pause after exit
"next": "after", // linear target
"next_if": [{"expr": "score > 5", "then": "good"}], // conditional next
"auto": 2.0, // auto-advance
"choices": { // choice menu — full tables in Story detail
"items": [ { // the options (required)
"text": "Stay", // caption
"text_key": "choice.stay", // translated caption
"target": "stay", // where it goes
"set": {"chose_stay": true}, // flags on pick
"commands": [{"type": "sfx", "value": "click"}], // commands on pick
"id": "stay", // option id
"rules": {"show_if": "has_key"}, // show / disable
"style": {}, // this option's look
"layout": {"x": 100, "y": 80}, // free placement
"source": "choice_plain", // pack stem
"interaction": {}, // hotkey / hooks
"transition": {}, // option motion
"shader": {}, // option shader
"audio": {}, // option sounds
"state_visual": {}, // state look
"debug": {} // author debug
} ],
"source": "choice_yes_no", // menu pack
"style": "choice_button", // button pack
"item": {}, // shared item defaults
"shuffle": false, // reshuffle options
"show_numbers": true, // number prefix
"container": {}, // menu plate / layout
"timer": {"seconds": 30, "on_end": "explode"} // choice deadline
},
"input": { // text field wait
"flag": "player_name", // where to store
"prompt": "Your name?", // prompt copy
"default": "", // ghost + empty confirm
"placeholder": "Type a name…", // hint only
"prefill": "Hero", // editable starter
"prefill_from_flag": true, // seed from flag
"max_length": 24, // character cap
"pattern": "^[A-Za-z ]+$", // validation
"style": "name_entry", // chrome pack
"source": "name_entry", // pack stem
"container": {}, // field host
"field": {}, // field chrome
"confirm": {} // confirm button
},
"text_metas": {"help": "url:https://example.com"}, // body link actions
"panel": "default", // panel preset
"panel_id": "main", // which panel
"text_mode": "replace", // body write mode
"append_direction": "down", // append / plates direction
"append_gap_lines": 0, // append line gap
"append_gap_px": 0, // append pixel gap
"plate": "them", // plate name this moment
"hide_panel": false, // hide dialogue box
"hide_continue": false, // hide continue
"hide_back": false, // hide back
"driver_typing": true, // mouth / beep drive
"driver_typing_targets": ["hana"], // who gets drive
"panel_shader": {}, // panel shader
"panel_presence_mode": "talk_only", // when panel shows
"panel_non_talking_mode": "hide", // when not talking
"panel_readonly_style_key": "default", // readonly look
"labelplate": {"visible": true} // name plate override
}
Keys
id stringIf omitted auto
_N from file orderMatches
:: park in the script. Required for direction patches.talking stringIf omitted narrator / none
Speaker id, or an array of ids.
talking_anchor stringIf omitted first talking id
Which speaker starts focused when several talk.
label stringIf omitted character display name
Overrides the plate caption for this moment.
text stringIf omitted none / from text_ref
BBCode,
{@…} tags, and {flag} inserts.text_ref stringIf omitted use
textPull body from the strings catalog.
text_from stringIf omitted none
Reuse another moment's text by id.
set objectIf omitted none
Flag updates when the moment starts. Values may be
"= expr".commands arrayIf omitted none
Stage directions when the moment starts. Each item is a command object — [Commands](../commands/index.md).
flow_commands arrayIf omitted none
Batches fired by
{@cN} markers in text (1-based). Command shapes — [Commands](../commands/index.md).exit_commands arrayIf omitted none
Run when leaving the moment. Command shapes — [Commands](../commands/index.md).
exit_delay numberIf omitted
0Values seconds
Seconds after
exit_commands before the next moment.next stringIf omitted next in file / end
Next moment id, or
null / END / NEXT / START.next_if arrayIf omitted use
nextFirst truthy
{ expr, then }; else next.auto numberIf omitted wait for continue
Values seconds
Advance after N seconds (
[auto N]).choices.items[].text stringIf omitted use text_key
Choice label.
choices.items[].text_key stringIf omitted use text
Catalog key for the caption.
choices.items[].target stringIf omitted NEXT
Moment id, or
NEXT / END / START.choices.items[].set objectIf omitted none
Flags applied when this option is chosen.
choices.items[].commands arrayIf omitted none
Run on confirm (no jump/input waits). Command shapes — [Commands](../commands/index.md).
choices.items[].id stringIf omitted auto
Stable id for this option.
choices.items[].rules objectIf omitted always available
show_if / disable_if expressions.choices.items[].style objectIf omitted group / game default
Per-option chrome (icon, colours, sprite).
choices.items[].layout objectIf omitted list layout
Position when the menu uses free layout.
choices.items[].source stringIf omitted none
Optional per-item pack under
themes/.choices.items[].interaction objectIf omitted none
Focus, hotkey, and hooks.
choices.items[].transition objectIf omitted none
Show / focus / confirm motion.
choices.items[].shader objectIf omitted none
Optional shader on the option.
choices.items[].audio objectIf omitted none
Focus / confirm SFX.
choices.items[].state_visual objectIf omitted none
Visual tweaks by interaction state.
choices.items[].debug objectIf omitted none
Debug-only metadata.
choices.source stringIf omitted none
Pack stem under
themes/ for the whole menu.choices.style stringIf omitted game / choice_style
Choice button look (
themes/<name>.json).choices.item objectIf omitted none
Defaults merged into every item.
choices.shuffle boolIf omitted
falseDeterministic shuffle. Forbidden in free layout mode.
choices.show_numbers boolIf omitted
truePrefix captions with
N. .choices.container objectIf omitted game layout.choices
Host, anchors, plate style, transitions.
choices.timer objectIf omitted none
Countdown while the menu is open.
input.flag stringIf omitted required for a working input
Flag that receives the typed value.
input.prompt stringIf omitted none
Label above the field.
input.default stringIf omitted empty
Ghost text; empty Enter/OK uses this when there is no seed. Supports {flag}.
input.placeholder stringIf omitted none
Ghost hint when default is empty; never submitted. Supports {flag}.
input.prefill stringIf omitted empty field
Real editable text in the field. Supports {flag}.
input.prefill_from_flag boolIf omitted
falseEditable seed from the current flag value when the flag exists (wins over prefill).
input.max_length numberIf omitted unlimited
Maximum length.
input.pattern stringIf omitted any text
Regex the value must match.
input.style stringIf omitted code fallbacks
Pack under
themes/ for the field look.input.source stringIf omitted none
Alternate pack resolve key.
input.container objectIf omitted defaults
Layout / plate around the field.
input.field objectIf omitted defaults
Textures and colours for the input box.
input.confirm objectIf omitted defaults
Confirm control chrome.
text_metas objectIf omitted none
Map
[url=key] markers to a url string or jump/set_flag object.panel stringIf omitted routing chain
Dialogue-box preset from the theme.
panel_id stringIf omitted from talking → main
Target panel instance id.
text_mode enumIf omitted
replaceValues
replace · append · platesReplace the panel body, append as one label, or stack named plates.
append_direction enumIf omitted
downValues
down · upWhere new lines or plates attach.
append_gap_lines numberIf omitted
0Blank lines between append chunks (ignored in
plates).append_gap_px numberIf omitted
0Pixel gap between append chunks or plates.
plate stringIf omitted sticky / character / preset default
Which
plates.<name> to use for this moment when text_mode is plates. Prefer character ui.default_plate for chat sides.hide_panel boolIf omitted
falseHide the routed panel for this moment.
hide_continue boolIf omitted
falseHide the continue control.
hide_back boolIf omitted
falseHide the back control.
driver_typing boolIf omitted
trueTyping driver for speakers. False for silent lines.
driver_typing_targets arrayIf omitted all talking
Limit typing drive to these speaker ids.
panel_shader objectIf omitted clear sticky shader
Per-moment panel shader. Absent clears a sticky one.
panel_presence_mode enumIf omitted routing default
Values
talk_only · visible_with_char · always_visibleOne-cycle presence override.
panel_non_talking_mode enumIf omitted routing default
Values
hide · readonly_last_textOne-cycle non-talking behaviour.
panel_readonly_style_key stringIf omitted theme default
Which
readonly_styles.<name> to use.labelplate objectIf omitted theme / routing
Same keys as the
labelplate command.Learn more: moment