Tokens
Putting a variable's value or a character's name inside a line of text.
A token is a name in curly braces inside text. At play time it is replaced by the value of a variable, or by the display name of a cast member.
{kai} has {gold} gold.reads as "Kai has 7 gold." while gold holds 7.
The syntax
A token is a {, a name, and a }, with nothing else between the braces. The
name must start with a letter or an underscore and continue with letters,
digits and underscores.
| Written | Result |
|---|---|
{gold} | The value of gold. |
{player_name} | Underscores are fine. |
{ gold } | Not a token. Spaces inside the braces, so it prints as written. |
{1bad} | Not a token. Names cannot start with a digit. |
{my gold} | Not a token, which is why variable names cannot contain spaces. |
That last row is enforced at the other end: a declared name outside identifier
syntax is INVALID_VARIABLE_NAME, with a message telling you to rename it,
precisely because such a name could never be interpolated.
What a name can refer to
Two namespaces are visible to a token:
- Declared variables, of any scope. Project, persistent, chapter and scene variables all interpolate.
- Cast members, by their cast id, which resolve to the member's display name.
Variables win on a collision. If you declare a variable with the same name as a cast id, the variable's value is what prints.
Anything else is UNDECLARED_VARIABLE at compile time, and the editor marks the
chip as you type. Hover it and the tooltip says the token is not a declared
variable or cast member.
Writing one
Type { in a line and a menu opens over the caret, listing declared variables
and cast members. It matches on a substring, so gold finds player_gold.
Enter or Tab inserts a chip: a single object you can
delete with one keypress, rather than five characters you can half-delete.
Typing a complete {token} by hand chips it too, so pasted text and old habits
both work.
Where tokens are resolved
Interpolation happens in the player, on the way to the screen, not at compile time. Two places carry it:
- Line text, including each emphasis span separately.
- Choice option labels, in the list, on a card, and in the spoken announcement of a timed choice's default option.
The token is never rewritten in your script or in the published bundle. The
bundle stores {gold} and the reader's copy of the story resolves it against
their own playthrough.
Because emphasis spans are interpolated one at a time, a token that straddles a
span boundary would never resolve. The compiler catches that as
INVALID_LINE_SPANS. Bold the whole {gold} or none of it.
How values print
| Variable type | Prints as |
|---|---|
| number | The number: 7. |
| text | The text. |
| flag | true or false. |
| list | The entries joined with commas: crowbar,torn note. |
Flags print as the literal words true and false, which is almost never what
you want in prose. Gate the sentence with a condition instead of printing the
flag.
A list token and a HUD text widget bound to the same list print the same thing, on purpose.
When a token cannot resolve
The reader sees the token, braces and all. {ghost} in the script is {ghost}
on screen if nothing called ghost is in scope.
That is a deliberate choice: it fails loudly, in the one place you cannot miss
it, rather than leaving a hole in a sentence. In practice you should never ship
one, because the compiler reports the same token as UNDECLARED_VARIABLE and
publishing is gated on a clean compile.
The case that does reach readers is a variable that is declared but has never been written. That is not an unresolved token; it resolves to whatever the declaration says the value starts as. Give every variable a sensible default and the opening scene reads correctly on a fresh save.
Cast tokens and bindings
A cast token prints the display name. When the member is bound (its face chosen by a variable), the player samples the binding on scene entry and the token reads the resolved name, so the token and the portrait agree. A binding that resolves to nothing falls back to the member's own name. See Cast bindings.