JSON Export

JSON Export

Export your interactive story as clean, optimized JSON data designed for game engines and custom applications.

What is JSON Export?

JSON export converts your StoryFlow Editor project into a portable, engine-agnostic data format optimized for parsing and integration. Unlike HTML export which packages a complete runtime, JSON export provides pure data that you can load into any game engine or custom application.

Key Features:

  • Text Extraction: All player-visible text moved to string tables for easy localization
  • Clean Structure: Editor metadata stripped, only game-relevant data included
  • Keyed Objects: Nodes and variables indexed by ID for O(1) lookup performance
  • Hash-Based IDs: Collision-free variable identifiers support any character
  • Cross-Platform Paths: Lowercase paths with forward slashes work everywhere
  • Asset Management: Centralized asset registry with automatic file copying

Perfect For

  • Unity, Godot, Unreal Engine integration
  • Custom game engines and frameworks
  • Non-game applications (chatbots, training tools)
  • Multi-language support (localization-ready)
  • Cross-platform deployment (Windows, Mac, Linux, Web, Mobile)
  • Version control friendly (readable JSON with consistent formatting)

Design Philosophy

JSON export prioritizes performance, portability, and parsability. The format is designed to be loaded once at game start, with all lookups happening in O(1) time using dictionaries/maps. Special characters in names are handled via MD5 hashes, ensuring no collisions while preserving original text in localization tables.

How to Export

Export Steps:

  1. Open your project in StoryFlow Editor
  2. Ensure you have set a Startup Script via the menu next to the Play button (required for export)
  3. Click the Export button in the top-right corner (amber download icon)
  4. In the dropdown menu, select JSON as the export format
  5. Click the Export Project button
  6. When complete, click Show in Folder to open the build/ directory

Export dropdown menu showing HTML and JSON format options with Export Project button

Build Folder Behavior

The build/ folder is located inside your project folder and is cleared before each export to ensure a clean state. Both HTML and JSON exports use the same output directory. Any manual edits will be overwritten on re-export.

File Structure

JSON export creates a build/ folder inside your project folder containing project metadata, scripts, variables, and assets.

build/
├── project.json
├── global-variables.json
├── chapter1/
│   ├── intro.json
│   └── dialogue.json
├── shared/
│   └── utilities.json
└── images/
    └── characters/
        ├── hero.png
        └── background.jpg

Path Normalization

All file paths are automatically normalized to lowercase with forward slashes for cross-platform compatibility. Script files (.sfe) are converted to .json extension, and the original folder structure from your content/ directory is preserved. For example, content/Chapter1/Intro.sfe becomes build/chapter1/intro.json. This ensures your exported project works identically on Windows, macOS, and Linux without path separator or case sensitivity issues.

Format Specification

project.json

The root project file containing metadata and the entry point script reference.

JSONCopy

{
  "version": "1.0.0",
  "apiVersion": "1.0",
  "metadata": {
    "title": "My First Project",
    "description": "An interactive adventure game",
    "created": "2025-01-15T10:30:00.000Z",
    "modified": "2025-01-20T14:45:00.000Z"
  },
  "startupScript": "scripts/intro.json"
}
  • version: StoryFlow Editor version (e.g., "1.0.0")
  • apiVersion: JSON API version for compatibility checking (currently "1.0")
  • metadata: Project information (title, description, creation and modification timestamps)
  • startupScript: Path to the initial script file (normalized, lowercase, forward slashes)

Script Files

Each script file represents a single flow graph with nodes, connections, and local data.

JSONCopy

{
  "startNode": "0",
  "nodes": {
    "0": {
      "type": "start",
      "id": "0"
    },
    "8661543518ca4b7284337c6590833b96": {
      "type": "dialogue",
      "id": "8661543518ca4b7284337c6590833b96",
      "title": "dlg_1_title",
      "text": "dlg_2",
      "choices": [
        {
          "id": "668948d5a45a4456abd5f0c4441ff3d5",
          "text": "choice_3"
        }
      ]
    },
    "9090f4ba47b8469dae82ff048322d585": {
      "type": "runScript",
      "id": "9090f4ba47b8469dae82ff048322d585",
      "script": "scripts/next.json"
    }
  },
  "connections": [
    {
      "id": "xy-edge__0source-0--8661...",
      "source": "0",
      "target": "8661543518ca4b7284337c6590833b96",
      "sourceHandle": "source-0-",
      "targetHandle": "target-8661543518ca4b7284337c6590833b96-"
    }
  ],
  "variables": {},
  "strings": {
    "en": {
      "dlg_1_title": "Merchant",
      "dlg_2": "Welcome to my shop!",
      "choice_3": "Show me your wares"
    }
  },
  "assets": {}
}

Key Fields:

  • nodes: Dictionary of nodes keyed by ID for O(1) lookup (see Node Types)
  • connections: Array of edges linking nodes together (see Connection Schema). Editor styling properties (color, animation) are removed.
  • variables: Local variables defined in this script (see Variable Schema)
  • strings: Localization table mapping string keys to display text (see Localization Support). Empty strings result in no property being set on the node, while whitespace-only strings are trimmed and result in empty string keys.
  • assets: Asset references (images) used in this script (see Asset Schema)

Comment Nodes Excluded

Comment nodes are editor-only annotations and are not included in the JSON export. Only functional nodes that affect gameplay or story flow are exported.

Variable Scope in Nodes

Variable get/set nodes (getBool, setBool, getInt, setInt) include an optional isGlobal field. When true, the node references a global variable. When omitted or false, it references a local variable. This allows you to have both global and local variables with the same name without conflicts.

Conditional Node Input Resolution

Multi-input nodes (ANDOREqual (Boolean)PlusMinusGreater ThanGreater Than or EqualLess ThanLess Than or EqualEqual (Integer)) have value1 and value2 fields. These are fallback values used when no connection exists to that input handle. Important: value1 represents the TOP input handle (visually upper), and value2 represents the BOTTOM input handle (visually lower). Always check connections first - if an input handle has an incoming connection, evaluate that connected node instead of using the stored value. Branch nodes have a single value field instead of value1/value2. This design allows nodes to work both with visual connections and standalone checkbox/input values.

Global Variables

The global-variables.json file contains all global variables with hash-based IDs.

JSONCopy

{
  "variables": {
    "var_47c14840": {
      "id": "var_47c14840",
      "name": "var_1_name",
      "type": "boolean",
      "value": false
    },
    "var_cace59e2": {
      "id": "var_cace59e2",
      "name": "var_2_name",
      "type": "integer",
      "value": 0
    }
  },
  "strings": {
    "en": {
      "var_1_name": "QuestCompleted",
      "var_2_name": "PlayerHealth"
    }
  }
}

Hash-Based Variable IDs

Variable IDs are generated using MD5 hashing (first 8 characters) of the original variable name. This allows variables to have any name including spaces and special characters while guaranteeing no ID collisions. Original names are preserved in the strings table for display purposes.

Variable Types:

  • boolean: True/false values for flags and conditions
  • integer: Whole numbers for counters, stats, and quantities (no decimals)

API Reference

Comprehensive reference documentation for all schemas in the JSON export format.

File Schemas

Project File (project.json) Schema

Field Type Required Description
version string Yes StoryFlow Editor version (e.g., "1.0.0")
apiVersion string Yes JSON API version (currently "1.0")
metadata object Yes Project metadata (title, description, created, modified)
startupScript string Yes Path to startup script file (e.g., "scripts/main.json")

Script File Schema

Field Type Required Description
startNode string Yes Node ID to start execution from (always "0")
nodes object Yes Dictionary of nodes keyed by node ID (see Node Types)
connections array Yes Array of connection objects (see Connection Schema)
variables object Yes Dictionary of local variables keyed by ID (see Variable Schema)
strings object Yes Localization table for script text (see Localization Support)
assets object Optional Dictionary of assets keyed by asset ID (see Asset Schema)

global-variables.json Schema

Field Type Required Description
variables object Yes Dictionary of global variables keyed by variable ID (see Variable Schema)
strings object Yes Localization table for variable names (see Localization Support)

Node Types

All nodes share a base structure with type and id fields. Additional fields vary by node type.

Start Node

Start

The entry point node. Every script must have exactly one start node with id "0".

Field Type Required Description
type string Yes Node type ("start")
id string Yes Must be "0" for start node

Dialogue Node

Dialogue

Example Dialogue Node

Example Option

Condition

On Click

Displays text and options (choices) to the player. Supports optional title, image, and multiple options (choices) with conditions.

Field Type Required Description
type string Yes Node type ("dialogue")
id string Yes Unique node identifier
title string No String key for dialogue title (references strings table)
text string No String key for dialogue text (references strings table)
image string No Asset key for dialogue image (references assets table)
choices Choice[] No Array of choice objects (see Choice Schema)

Set Boolean Node

SET

hasKey

Sets a boolean variable to a specific value or accepts input from another node.

Field Type Required Description
type string Yes Node type ("setBool")
id string Yes Unique node identifier
variable string Yes Variable ID to set (e.g., "a1b2c3d4")
value boolean No Hardcoded value. Omit to accept input from connected node
isGlobal boolean No If true, variable is in global scope

Get Boolean Node

hasKey

Retrieves the current value of a boolean variable.

Field Type Required Description
type string Yes Node type ("getBool")
id string Yes Unique node identifier
variable string Yes Variable ID to retrieve (e.g., "a1b2c3d4")
isGlobal boolean No If true, variable is in global scope

NOT Boolean Node

NOT

Inverts a boolean value. Outputs the logical NOT of the input.

Field Type Required Description
type string Yes Node type ("notBool")
id string Yes Unique node identifier

AND Boolean Node

AND

Performs logical AND operation on two boolean inputs. Returns true only if both inputs are true.

Field Type Required Description
type string Yes Node type ("andBool")
id string Yes Unique node identifier
value1 boolean No Value used when this input handle has no incoming connection
value2 boolean No Value used when this input handle has no incoming connection

OR Boolean Node

OR

Performs logical OR operation on two boolean inputs. Returns true if at least one input is true.

Field Type Required Description
type string Yes Node type ("orBool")
id string Yes Unique node identifier
value1 boolean No Value used when this input handle has no incoming connection
value2 boolean No Value used when this input handle has no incoming connection

Equal Boolean Node

==

Compares two boolean values for equality. Returns true if both inputs are the same.

Field Type Required Description
type string Yes Node type ("equalBool")
id string Yes Unique node identifier
value1 boolean No Value used when this input handle has no incoming connection
value2 boolean No Value used when this input handle has no incoming connection

Branch Node

Branch

True

Condition

False

Conditional branching based on a boolean input. Routes execution to different paths.

Field Type Required Description
type string Yes Node type ("branch")
id string Yes Unique node identifier
value boolean No Value used when condition handle has no incoming connection

Run Script Node

Run Script

Select Script

Executes another script file, allowing for modular story organization and reusable subscripts.

Field Type Required Description
type string Yes Node type ("runScript")
id string Yes Unique node identifier
script string Yes Path to script file (e.g., "content/chapter2.sfe")

End Node

End

Marks the end of script execution. When reached, the story concludes or returns to caller.

Field Type Required Description
type string Yes Node type ("end")
id string Yes Unique node identifier

Set Integer Node

SET

playerGold

Sets an integer variable to a specific value or accepts input from another node.

Field Type Required Description
type string Yes Node type ("setInt")
id string Yes Unique node identifier
variable string Yes Variable ID to set (e.g., "a1b2c3d4")
value number No Hardcoded value. Omit to accept input from connected node
isGlobal boolean No If true, variable is in global scope

Get Integer Node

playerGold

Retrieves the current value of an integer variable.

Field Type Required Description
type string Yes Node type ("getInt")
id string Yes Unique node identifier
variable string Yes Variable ID to retrieve (e.g., "a1b2c3d4")
isGlobal boolean No If true, variable is in global scope

Plus Node

Adds two integer values together. Outputs the sum of the inputs.

Field Type Required Description
type string Yes Node type ("plus")
id string Yes Unique node identifier
value1 number No Value used when this input handle has no incoming connection
value2 number No Value used when this input handle has no incoming connection

Minus Node

Subtracts the second input from the first. Outputs the difference.

Field Type Required Description
type string Yes Node type ("minus")
id string Yes Unique node identifier
value1 number No Value used when this input handle has no incoming connection
value2 number No Value used when this input handle has no incoming connection

Greater Than Node

Compares two integer values. Returns true if the first input is greater than the second.

Field Type Required Description
type string Yes Node type ("greaterThan")
id string Yes Unique node identifier
value1 number No Value used when this input handle has no incoming connection
value2 number No Value used when this input handle has no incoming connection

Greater Than or Equal Node

=

Compares two integer values. Returns true if the first input is greater than or equal to the second.

Field Type Required Description
type string Yes Node type ("greaterThanOrEqual")
id string Yes Unique node identifier
value1 number No Value used when this input handle has no incoming connection
value2 number No Value used when this input handle has no incoming connection

Less Than Node

<

Compares two integer values. Returns true if the first input is less than the second.

Field Type Required Description
type string Yes Node type ("lessThan")
id string Yes Unique node identifier
value1 number No Value used when this input handle has no incoming connection
value2 number No Value used when this input handle has no incoming connection

Less Than or Equal Node

<=

Compares two integer values. Returns true if the first input is less than or equal to the second.

Field Type Required Description
type string Yes Node type ("lessThanOrEqual")
id string Yes Unique node identifier
value1 number No Value used when this input handle has no incoming connection
value2 number No Value used when this input handle has no incoming connection

Equal Integer Node

==

Compares two integer values for equality. Returns true if both inputs are the same.

Field Type Required Description
type string Yes Node type ("equalInt")
id string Yes Unique node identifier
value1 number No Value used when this input handle has no incoming connection
value2 number No Value used when this input handle has no incoming connection

Connection Schema

Connections define the flow between nodes in the script graph.

Field Type Required Description
id string Yes Unique connection identifier
source string Yes Source node ID
target string Yes Target node ID
sourceHandle string No Source handle ID for nodes with multiple outputs (e.g., branch, dialogue options)
targetHandle string No Target handle ID for nodes with multiple inputs (e.g., boolean operators)

Variable Schema

Variables store persistent state across script execution. Variable IDs are MD5 hash-based identifiers (first 8 characters of the hash of the variable name).

Field Type Required Description
id string Yes Variable ID (e.g., "a1b2c3d4" - first 8 chars of MD5 hash)
name string Yes String key for variable display name (references strings table)
type string Yes Variable type: "boolean" or "integer"
value any Yes Default value (type matches variable type)

Asset Schema

Assets define references to external image files used in the story.

Field Type Required Description
id string Yes Unique asset identifier (e.g., "asset_elder_portrait")
type string Yes Asset type: "image"
path string Yes Relative path to asset file from build directory

Choice Schema

Choices are options presented to the player in dialogue nodes. Each choice can have a condition and triggers an action when selected.

Field Type Required Description
id string Yes Unique choice identifier
text string Yes String key for choice text (references strings table)

Parsing and Loading

This section explains how to integrate StoryFlow Editor's JSON export into external systems and game engines. The examples below demonstrate the recommended patterns for loading project data, building connection maps, and resolving variables at runtime.

Initial Load

Load the exported data in your game engine at startup. The recommended loading sequence is:

  1. Parse [project.json](https://storyflow-editor.com/docs/json-export/#project-json) to get metadata and startup script path
  2. Load [global-variables.json](https://storyflow-editor.com/docs/json-export/#global-variables) into a runtime variable store
  3. Load the startup script file referenced in [project.json](https://storyflow-editor.com/docs/json-export/#project-json)
  4. Pre-load additional scripts as needed for your use case

Loading Strategy

For small projects, load all scripts at startup. For large projects with hundreds of scripts, implement lazy loading where scripts are loaded on-demand when referenced by runScript nodes. Cache loaded scripts to avoid re-parsing.

Building Connection Maps

Build adjacency maps when loading each script to enable fast graph traversal. This converts the connections array into a dictionary structure for O(1) lookups.

JavaScriptCopy

// Example: Building an adjacency map
function buildConnectionMap(script) {
  const map = new Map();

  for (const connection of script.connections) {
    if (!map.has(connection.source)) {
      map.set(connection.source, []);
    }
    map.get(connection.source).push({
      target: connection.target,
      sourceHandle: connection.sourceHandle,
      targetHandle: connection.targetHandle
    });
  }

  return map;
}

// Usage: Get all outgoing connections from a node
const outgoing = connectionMap.get(currentNodeId) || [];

This pattern allows you to instantly find all nodes connected to the current node without iterating through the entire connections array.

Variable Resolution

Variables are referenced by their hash-based IDs in node data. Maintain separate stores for global and local variables, using the isGlobal flag in get/set nodes to determine which store to access.

JavaScriptCopy

// Example: Variable resolution with separate global/local stores
class VariableStore {
  constructor(globalVariables) {
    this.globalVars = new Map();
    this.localVars = new Map();

    // Load global variables
    for (const [id, variable] of Object.entries(globalVariables.variables)) {
      this.globalVars.set(id, variable.value);
    }
  }

  loadScriptVariables(scriptVariables) {
    // Clear local variables when loading a new script
    this.localVars.clear();

    // Load script-local variables
    for (const [id, variable] of Object.entries(scriptVariables)) {
      this.localVars.set(id, variable.value);
    }
  }

  get(variableId, isGlobal = false) {
    if (isGlobal) {
      return this.globalVars.get(variableId);
    }
    return this.localVars.get(variableId);
  }

  set(variableId, value, isGlobal = false) {
    if (isGlobal) {
      this.globalVars.set(variableId, value);
    } else {
      this.localVars.set(variableId, value);
    }
  }
}

// Usage in a getBool node
const node = script.nodes['863fc74e828046daa020f6696fe60f2e'];
const value = variableStore.get(node.variable, node.isGlobal || false);

Variable Scope Resolution

Get/set nodes include an optional isGlobal field to indicate scope. When true, the variable should be looked up in global storage. When false or omitted, the variable is local to the current script. Your runtime implementation should maintain separate global and local variable stores, with the isGlobal flag determining which store to use. This allows both global and local variables to have identical hash-based IDs without conflicts.

Performance Optimization

The JSON export format is designed for maximum runtime performance. Follow these best practices:

  • Dictionary Lookups: Nodes and variables are keyed objects, not arrays. Use direct lookups instead of iteration.
  • Connection Caching: Build adjacency maps once at load time, reuse throughout execution.
  • String Table Lookups: Cache localized strings at startup to avoid repeated lookups during gameplay.
  • Lazy Script Loading: For large projects, load scripts on-demand when first referenced by runScript nodes.
  • Asset Preloading: Parse asset references from scripts and preload required assets before execution.

Performance Profile

With proper implementation, node execution should run in O(1) time for lookups and O(E) time for traversal where E is the number of edges from the current node. Even projects with thousands of nodes execute efficiently.

Localization Support

StoryFlow Editor does not currently have built-in localization functionality, but the JSON export format was designed from the ground up to support multi-language projects. All player-facing text is extracted to string tables, making localization straightforward when you're ready to add it. Each file has a strings object with language codes as keys.

JSONCopy

"strings": {
  "en": {
    "dlg_1_title": "Merchant",
    "dlg_2": "Welcome to my shop!",
    "choice_3": "Show me your wares"
  },
  "es": {
    "dlg_1_title": "Comerciante",
    "dlg_2": "¡Bienvenido a mi tienda!",
    "choice_3": "Muéstrame tus productos"
  },
  "ja": {
    "dlg_1_title": "商人",
    "dlg_2": "私の店へようこそ!",
    "choice_3": "商品を見せてください"
  }
}

Localization Workflow:

  1. Export your project to JSON (includes default language strings)
  2. Extract all string keys from strings objects across all files
  3. Send keys to translators or use translation tools
  4. Add translated strings to the strings objects with appropriate language codes
  5. Set the current language in your game settings
  6. Look up strings using the current language code at runtime

Language Fallback

Implement fallback logic where if a string key is missing in the selected language, fall back to the defaultLanguage specified in each file. This prevents missing text if translations are incomplete.

→ HTML Export→ Game Engine Integration→ Node Types→ Variables

← Previous: HTML Export

Next: Game Engine Integration →