State & Simulation Lifecycle
Drafft separates authored data from simulated state.
This distinction is essential to understanding how scripts behave, how the Dialogue Simulator works, and how to debug narrative flow without coupling logic to export or runtime.
This page describes how state exists, changes, and resets during authoring.
Core Concepts
Defaults (Authored State)
Defaults are the values you author in Drafft documents:
- Variables
- Quest properties
- Actor properties
- Items, flags, and other design data
Defaults represent authorial intent.
They are:
- Stable
- Version-controlled
- Exported as part of the project
- Never mutated by scripts
Live Scenario (Simulated State)
The Live Scenario represents the current simulated world state while authoring.
It is derived from defaults and then modified by script execution or manual data entry.
Think of the Live Scenario as: “What is true right now, based on what I’ve simulated so far?”
State Lifecycle
1. Initialization
When a project or editor session starts:
Live Scenario = Defaults
At this point, no simulation has occurred.
2. Script Execution
When a script is simulated:
@set variables.aries.mood = "angry"
- The script runs against the Live Scenario
- Mutations apply immediately
- Subsequent scripts see the updated state
Example:
::Narrator:: Aries looks ${variables.aries.mood}.
After simulation, this resolves to:
Aries looks angry.
3. Continuity Across Scripts
The Live Scenario persists across scripts.
If Script A sets:
@set variables.aries.mood = "angry"
Then Script B, authored later, will observe:
${variables.aries.mood} → "angry"
This matches natural author expectations during narrative development.
4. Resetting State
At any point, the Live Scenario can be reset . This clears all simulated mutations and restores the authored baseline.
Write to Live Scenario Toggle
By default, simulation writes to the Live Scenario.
However, Drafft provides a toggle:
Write to Live Scenario
Enabled (default)
- Script mutations persist
- State carries across simulations
- Ideal for narrative authoring and iteration
Disabled (ephemeral simulation)
- Scripts run against a temporary copy of state
- All changes are discarded after execution
- Live Scenario remains unchanged
This mode is useful for:
- Testing edge cases
- Previewing alternative branches
- Verifying conditional logic without affecting ongoing work
Divergence Detection
The Live Scenario compares itself against the currently loaded scenario to detect divergence. This comparison is snapshot-based.
When Does Divergence Occur?
Divergence is only detected when:
- A scenario is loaded into the Live Scenario
- You modify values (manually via the Variables Inspector or via script execution)
- The modified values differ from the loaded scenario's snapshot
Divergence only exists when a scenario is loaded. If no scenario is active, there is no divergence to track.
Visual Indicator
When divergence is detected:
- A divergence indicator (an asterisk) appears in the UI
- The "Update Source Scenario" button becomes enabled
- The "Discard Changes" button becomes enabled
Divergence vs Changes
- Divergence: Live state differs from a loaded scenario's snapshot
- No divergence + scenario loaded: Live matches the loaded scenario exactly (clean state)
- Changes with no scenario loaded: Not tracked as divergence; considered a new scenario if saved
Scenarios as Diffs
While the Live Scenario is ephemeral during authoring, you can save and restore snapshots of it using scenarios.
Scenarios are diffs, not complete snapshots.
A scenario stores only the values that differ from defaults, not the entire state. This is similar to a patch file.
Why Diffs?
- Smaller files: Only overridden values are stored
- Clearer intent: You see exactly which defaults were modified
- Better version control: Diffs are easier to review and merge
Example
If your defaults contain:
{
"player": {
"level": 1,
"hp": 100,
"status": "healthy"
}
}
And during authoring you change only status to "sad", the saved scenario will contain:
{
"player": {
"status": "sad"
}
}
When you load this scenario, it overwrites only the status field while preserving level: 1 and hp: 100 from defaults.
Current Scope
Scenarios currently save Variable state only. Support for additional collections (Actors, Quests, Items, etc.) is planned for future releases.
Use Cases
- "Chapter 2 – After Library"
- "Boss Fight Setup"
- Bug reproduction states
- QA handoff
- Testing alternative narrative branches
Scenarios:
- Do not affect defaults
- Can be loaded and restored into the Live Scenario
- Are optional, not required for normal authoring
Live Scenario Buttons
The Live Scenario page provides several buttons for managing scenarios. Here's what each does:
Save as New Scenario
Button: 💾 Save as New Scenario
Serializes the current Live Scenario state and creates a new scenario document.
What it saves:
- Compares live state against defaults
- Stores only the values that differ
- Creates a new scenario document with a user-provided name
When to use:
- After reaching a meaningful narrative checkpoint
- Before testing alternative branches
- To create reproducible QA states
You can also open the Live Scenario page by right clicking on the current scenario in the status bar.
Update Source Scenario
Button: 🔄 Update Source Scenario (enabled only when divergence is detected)
Serializes current live divergence and updates the source scenario document in the editor.
What it does:
- Compares current live state against the loaded scenario's snapshot
- Serializes only the differences (the new diff)
- Opens the scenario document in the editor tab (or focuses existing tab)
- Updates the editor buffer with the new content
- Waits for you to explicitly save (preserves review/approval workflow)
Multi-user safety:
- Checks if scenario is locked by another user
- Prevents automatic overwrites
- User remains in editor before committing changes
When to use:
- You've made changes during scripting that should become the new baseline
- You want to refine an existing scenario incrementally
Discard Changes
Button: 🔄 Discard Changes (enabled only when divergence is detected)
Reloads the original loaded scenario back into the Live Scenario, discarding all modifications.
What it does:
- Clears all live state
- Reapplies the loaded scenario's snapshot
- Removes the divergence indicator
When to use:
- You made experimental changes and want to return to the scenario baseline
- You want to reset to a known state without reloading from disk
Reset to Defaults
Button: 🔄 Reset to Defaults
Clears all live state and unloads any active scenario, returning to the pure authored defaults.
What it does:
- Clears all live variable values
- Clears the loaded scenario snapshot
- Unsets the active scenario
- Removes all divergence tracking
Differs from "Discard Changes" because:
- It removes the scenario context entirely
- You start fresh from authored defaults, not a scenario snapshot
- Useful for starting a new simulation from baseline
When to use:
- Starting a new test or simulation
- Clearing all runtime state after a session
- Testing default-only behavior without scenario modifications
State Resolution in Scripts
All state access follows the same resolution rule:
<collection>.<_sid>.<property>
Examples:
variables.player.courage
variables.player.inventory[0].name
// other collections will be implemented in future updates, but the same resolution applies:
actors.Aries.mood
quest.forestTrial.completed
Resolution Order (Three-Tier Fallback)
When you access a value, Drafft resolves it in this order:
- Live Scenario ← Used first if available
- Defaults ← Used if no live value exists
- Undefined ← If neither exists
// If live has modified this value:
${variables.player.mood} → resolves to live value
// If live doesn't have this, falls back to defaults:
${variables.player.level} → resolves to default value
// If neither exists:
${variables.nonexistent} → undefined
Accessing Defaults Explicitly
To access authored values and bypass any live modifications, use the defaults root:
${defaults.variables.player.courage} → always uses authored default
This is useful for:
- Debugging state divergence
- Checking what the original value was
- Exporting context-free content
Context-Aware Resolution
Dependending on context, resolution behavior changes:
| Context | Resolution | Use Case |
|---|---|---|
| Authoring | Live → Defaults | Script simulation, testing |
| Export | Defaults only | Pure narrative content |
| Runtime | Engine-defined (script-bound) | Your target platform |
This separation ensures your exports remain pure and unaffected by simulation state.
What Scripts Can and Cannot Do
Scripts Can
- Read Live Scenario state
- Mutate Live Scenario via
@set - Drive conditional structure during simulation
- Be replayed deterministically
Scripts Cannot
- Mutate defaults
- Persist changes automatically
- Execute engine logic
- Implicitly affect export output
Relationship to Export and Runtime
| Context | Behavior |
|---|---|
| Export | State is not evaluated or mutated |
| Simulation | Uses Live Scenario |
| Runtime | Engine defines state behavior |
The Dialogue Simulator (aka Script Player) uses the same rules described on this page.
Why This Model Exists
This design ensures:
- Predictable authoring
- Clear separation of intent vs outcome
- Debuggable narrative flow
- Engine-agnostic exports
- No hidden side effects
Summary
- Defaults define what should exist
- Live Scenario defines what currently exists
- Scripts mutate Live Scenario
- Live Scenario can be reset or saved
- Export remains pure and context-free