Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 string
If omitted auto _N from file order
Matches :: park in the script. Required for direction patches.
talking string
If omitted narrator / none
Speaker id, or an array of ids.
talking_anchor string
If omitted first talking id
Which speaker starts focused when several talk.
label string
If omitted character display name
Overrides the plate caption for this moment.
text string
If omitted none / from text_ref
BBCode, {@…} tags, and {flag} inserts.
text_ref string
If omitted use text
Pull body from the strings catalog.
text_from string
If omitted none
Reuse another moment's text by id.
set object
If omitted none
Flag updates when the moment starts. Values may be "= expr".
commands array
If omitted none
Stage directions when the moment starts. Each item is a command object — [Commands](../commands/index.md).
If omitted none
Batches fired by {@cN} markers in text (1-based). Command shapes — [Commands](../commands/index.md).
If omitted none
Run when leaving the moment. Command shapes — [Commands](../commands/index.md).
exit_delay number
If omitted 0
Values seconds
Seconds after exit_commands before the next moment.
next string
If omitted next in file / end
Next moment id, or null / END / NEXT / START.
next_if array
If omitted use next
First truthy { expr, then }; else next.
auto number
If omitted wait for continue
Values seconds
Advance after N seconds ([auto N]).
choices.items[].text string
If omitted use text_key
Choice label.
choices.items[].text_key string
If omitted use text
Catalog key for the caption.
choices.items[].target string
If omitted NEXT
Moment id, or NEXT / END / START.
choices.items[].set object
If omitted none
Flags applied when this option is chosen.
If omitted none
Run on confirm (no jump/input waits). Command shapes — [Commands](../commands/index.md).
choices.items[].id string
If omitted auto
Stable id for this option.
choices.items[].rules object
If omitted always available
show_if / disable_if expressions.
choices.items[].style object
If omitted group / game default
Per-option chrome (icon, colours, sprite).
choices.items[].layout object
If omitted list layout
Position when the menu uses free layout.
choices.items[].source string
If omitted none
Optional per-item pack under themes/.
choices.items[].interaction object
If omitted none
Focus, hotkey, and hooks.
choices.items[].transition object
If omitted none
Show / focus / confirm motion.
choices.items[].shader object
If omitted none
Optional shader on the option.
choices.items[].audio object
If omitted none
Focus / confirm SFX.
choices.items[].state_visual object
If omitted none
Visual tweaks by interaction state.
choices.items[].debug object
If omitted none
Debug-only metadata.
choices.source string
If omitted none
Pack stem under themes/ for the whole menu.
choices.style string
If omitted game / choice_style
Choice button look (themes/<name>.json).
choices.item object
If omitted none
Defaults merged into every item.
choices.shuffle bool
If omitted false
Deterministic shuffle. Forbidden in free layout mode.
choices.show_numbers bool
If omitted true
Prefix captions with N. .
choices.container object
If omitted game layout.choices
Host, anchors, plate style, transitions.
choices.timer object
If omitted none
Countdown while the menu is open.
input.flag string
If omitted required for a working input
Flag that receives the typed value.
input.prompt string
If omitted none
Label above the field.
input.default string
If omitted empty
Ghost text; empty Enter/OK uses this when there is no seed. Supports {flag}.
input.placeholder string
If omitted none
Ghost hint when default is empty; never submitted. Supports {flag}.
input.prefill string
If omitted empty field
Real editable text in the field. Supports {flag}.
input.prefill_from_flag bool
If omitted false
Editable seed from the current flag value when the flag exists (wins over prefill).
input.max_length number
If omitted unlimited
Maximum length.
input.pattern string
If omitted any text
Regex the value must match.
input.style string
If omitted code fallbacks
Pack under themes/ for the field look.
input.source string
If omitted none
Alternate pack resolve key.
input.container object
If omitted defaults
Layout / plate around the field.
input.field object
If omitted defaults
Textures and colours for the input box.
input.confirm object
If omitted defaults
Confirm control chrome.
text_metas object
If omitted none
Map [url=key] markers to a url string or jump/set_flag object.
panel string
If omitted routing chain
Dialogue-box preset from the theme.
panel_id string
If omitted from talking → main
Target panel instance id.
If omitted replace
Values replace · append · plates
Replace the panel body, append as one label, or stack named plates.
append_direction enum
If omitted down
Values down · up
Where new lines or plates attach.
append_gap_lines number
If omitted 0
Blank lines between append chunks (ignored in plates).
append_gap_px number
If omitted 0
Pixel gap between append chunks or plates.
plate string
If 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 bool
If omitted false
Hide the routed panel for this moment.
hide_continue bool
If omitted false
Hide the continue control.
hide_back bool
If omitted false
Hide the back control.
driver_typing bool
If omitted true
Typing driver for speakers. False for silent lines.
driver_typing_targets array
If omitted all talking
Limit typing drive to these speaker ids.
panel_shader object
If omitted clear sticky shader
Per-moment panel shader. Absent clears a sticky one.
panel_presence_mode enum
If omitted routing default
Values talk_only · visible_with_char · always_visible
One-cycle presence override.
panel_non_talking_mode enum
If omitted routing default
Values hide · readonly_last_text
One-cycle non-talking behaviour.
panel_readonly_style_key string
If omitted theme default
Which readonly_styles.<name> to use.
labelplate object
If omitted theme / routing
Same keys as the labelplate command.

Learn more: moment