Skip to content

Variables & Directives

Variables are the world's game state. The AI reads current values each turn and writes bracket directives in its response to update them.

Variable Schema

json
{
  "id": "health",
  "name": "Health",
  "type": "number",
  "defaultValue": 100,
  "min": 0,
  "max": 100,
  "description": "Player's physical health",
  "category": "stat",
  "behaviorRules": "0 = death. 1-20 = critical. 20-50 = wounded. 50-80 = bruised. 80-100 = healthy. Decrease on physical damage: punch -5 to -10, slash -15 to -25, fall -20 to -40. Rest +5, healing +10 to +30. Max change per turn: 30."
}

Variable Types

number

Numeric values with optional min/max bounds.

Directive syntax:

[health: set 50]       → set to 50
[health: +10]          → add 10 (alias: add)
[health: -15]          → subtract 15 (alias: subtract)
[health: *2]           → multiply by 2 (alias: multiply)
[gold: 100]            → implicit set (no operator)

string

Text values.

Directive syntax:

[location: set "dark forest"]
[mood: set "suspicious"]
[notes: append " Found a clue."]

boolean

True/false flags.

Directive syntax:

[has-key: toggle]        → flip true ↔ false
[met-elder: set true]
[quest-active: set false]

json

Complex structures — objects and arrays. Supports nested dot-path updates.

Directive syntax:

[inventory: push {"name": "Iron Sword", "damage": 10}]
[inventory: delete 0]
[inventory: set [{"name": "Potion", "qty": 3}]]

[npcs.aria.affinity: +5]
[npcs.aria.mood: set "happy"]
[npcs: merge {"aria": {"trust": 80}}]
[quest-log: push {"id": "q1", "status": "active"}]
[config: delete "deprecated-key"]

Dot-path operations:

  • [root.nested.field: op value] — updates a nested field within a JSON variable
  • Auto-creates intermediate objects if they don't exist
  • Array index access: [inventory.0.durability: -1]

All Operations

OperationTypesSyntaxBehavior
setall[id: set value] or [id: value]Replace value
add / +number[id: +10] or [id: add 10]Increment
subtract / -number[id: -5] or [id: subtract 5]Decrement
multiply / *number[id: *2] or [id: multiply 2]Scale
toggleboolean[id: toggle]Flip true/false
appendstring[id: append " text"]Concatenate
mergejson (object)[id: merge {"key": "val"}]Shallow merge
pushjson (array)[id: push "item"] or [id: push {...}]Append to array
deletejson[id: delete "key"] or [id: delete 0]Remove key/index

Audio Directives

Audio is triggered through a separate directive format:

[audio: track-id play]
[audio: track-id stop]
[audio: track-id crossfade 2.5]
[audio: track-id volume 0.5]
[audio: track-id play chain:next-track]

Behavior Rules

The behaviorRules field is plain English that gets injected into the AI's system prompt as a <behavior-rules> block. It teaches the AI when and how to update the variable.

Effective behavior rules include:

  • What each value range means narratively
  • What triggers changes (and in which direction)
  • Magnitude guidelines (how much to change)
  • Limits (max change per turn, absolute bounds)
  • Relationships with other variables

Example — Complex JSON variable:

"behaviorRules": "Array of party members. Push new object when recruiting: {\"name\": \"...\", \"class\": \"...\", \"trust\": 50}. Update trust via dot-path: [allies.0.trust: +5]. Remove via index: [allies: delete 0]. Trust < 20 = may betray."

Variable Categories

Note: category is accepted by Studio AI tools for organizational purposes but is NOT part of the world schema and will be stripped during validation. It does not appear in the Zod schema.

CategoryTypical Use
statHealth, mana, stamina, level
inventoryItems, equipment, resources
resourceGold, energy, food, materials
flagQuest completion, met NPCs, discovered locations
relationshipNPC affinity, faction standing, trust
customAnything else

ID Conventions

  • Use kebab-case: player-health, day-count, npc-trust
  • IDs must be unique within the world
  • IDs become macro names: variable player-health is accessible as {{player-health}} in entries
  • Avoid reserved words: audio, user, char, time, date