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
{
"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
| Operation | Types | Syntax | Behavior |
|---|---|---|---|
set | all | [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 |
toggle | boolean | [id: toggle] | Flip true/false |
append | string | [id: append " text"] | Concatenate |
merge | json (object) | [id: merge {"key": "val"}] | Shallow merge |
push | json (array) | [id: push "item"] or [id: push {...}] | Append to array |
delete | json | [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:
categoryis 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.
| Category | Typical Use |
|---|---|
stat | Health, mana, stamina, level |
inventory | Items, equipment, resources |
resource | Gold, energy, food, materials |
flag | Quest completion, met NPCs, discovered locations |
relationship | NPC affinity, faction standing, trust |
custom | Anything 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-healthis accessible as{{player-health}}in entries - Avoid reserved words:
audio,user,char,time,date
