Expressions

An expression is a small piece of code that returns a value: true/false, a number, or a string. Writers use them to decide which choices show up, which scenes the player can reach, when an event fires, and how text reads. This page is the orientation; for every operator and function the runtime supports, see Expression operators and Expression functions.

Where you write them

Anywhere the inspector shows a syntax-highlighted field: node and scene Visibility, event Conditions, scene Resolved when, and a handful of others. The editor validates as you type, autocompletes function and variable names, and underlines unknown identifiers in red.

The simplest expressions

The smallest expression is just a literal value or a variable:

true                      // a literal true
42                        // a number
"hello"                   // a string
var_player_name           // the current value of a variable

Variable names are bare identifiers: no quotes, no $, no dollar-prefix. The editor’s autocomplete suggests them as you type.

Comparing values

To turn a number or string into a yes/no answer, compare it. The result is true or false, which is what visibility and condition fields expect.

var_hp > 0                          // alive?
var_score >= 100                    // hit the threshold?
var_player_name == "Alice"          // string compare (case-insensitive)
var_attempts != 0                   // tried at least once?

All six comparisons (==, !=, <, <=, >, >=) work on numbers, and == / != work on strings.

Combining with &&, ||, !

Most real visibility gates chain a few conditions together:

var_hp > 0 && var_has_key                   // both must hold
var_helmet || var_shield                    // either is enough
!Played(node_warning_intro)                 // logical negation
(var_hp > 0 && var_mp > 5) || var_is_god    // grouped with parens

&& is “and”, || is “or”, ! is “not”. The editor uses these symbols when it generates expressions on your behalf (for example, the gates a Dependency line writes), so they’re the form you’ll see most often in your projects. The keyword spellings and / or / not work too if you prefer reading them aloud. Parentheses group sub-expressions and override the default precedence: comparison binds tighter than &&, which binds tighter than ||.

Referring to entities by id

When you pass a scene, node, tag, skill, or item to a function, you reference it by its id (the short, human-readable label you set in the editor), not by the long internal uuid:

Visits(scene_kitchen)             // correct
Visits("scene_kitchen")           // wrong: ids are bare, not quoted
Visits(d3f9-…-a8c1)               // wrong: uuids are storage details

Each function expects a specific entity kind for each of its arguments, and its reference page calls that out. Renaming an entity’s id afterwards keeps existing expressions working as long as you rename through the editor; it rewrites references everywhere at once.

Calling functions

Most of the expression power comes from functions. The two you’ll reach for most often are play-history checks:

Played(node_meet_alice)           // did this node play?
Visits(scene_kitchen) >= 2        // have they entered this scene twice?

There are around fifty in total, covering math, strings, time, lists, and sequence slots. Skim Expression functions to get a feel for the categories; you don’t need to memorize them.

Scene-scoped play history

This is the rule that catches new writers most often. Played(X), Selected(X), and Seen(X) track state per visit of the scene containing X. Every time a scene reactivates, it starts with an empty visit-state; what happened in the previous visit doesn’t count.

For whole-run queries (“has the player ever encountered this content?”) use the Ever variants:

  • PlayedEver(X) instead of Played(X)
  • SelectedEver(X) instead of Selected(X)
  • SeenEver(X) instead of Seen(X)

Rule of thumb: if you’re asking “did this happen in this conversation with this character?” use the per-visit form. If you’re asking “has the player ever encountered this content at all?” use Ever.

Boolean coercion

When a non-boolean value lands somewhere a boolean is expected (a visibility expression, an If(...) condition, an operand of &&), the runtime coerces it:

  • 0, 0.0, empty string, "false" (case-insensitive) → false
  • Anything else (non-zero numbers, non-empty strings) → true

This means var_hp on its own works as a visibility gate (true when non-zero), the same as var_hp != 0. The Bool(x) function exposes the rule explicitly when you want to be clear about the coercion.

See also

Docs last synced: 2026-07-08
Screenshot viewer