Blueprints & Scenes
Blueprint Structure
A BlueprintExport is the JSON file exported from the LSDE editor. It contains all the data the engine needs.
interface BlueprintExport {
format: "lsde-blueprints"; // anything else is refused outright
version: 1; // the FORMAT version, not the editor's
generator: Generator; // which software wrote the file
exportedAt: string; // ISO 8601
project: string;
locales: string[];
referenceLocale: string; // the locale written first
dictionaries: DictionaryDefinition[];
functions: FunctionDefinition[];
cards: Card[]; // what a block's `actors` and `emotion` cite
scenes: BlueprintScene[];
}public class BlueprintExport {
public string Format { get; set; } // "lsde-blueprints"
public int Version { get; set; } // 1
public Generator? Generator { get; set; }
public string ExportedAt { get; set; }
public string Project { get; set; }
public List<string> Locales { get; set; }
public string ReferenceLocale { get; set; }
public List<DictionaryDefinition> Dictionaries { get; set; }
public List<FunctionDefinition> Functions { get; set; }
public List<Card> Cards { get; set; }
public List<BlueprintScene> Scenes { get; set; }
}struct BlueprintExport {
std::string format; // "lsde-blueprints"
int version = 0; // 1
Generator generator;
std::string exportedAt;
std::string project;
std::vector<std::string> locales;
std::string referenceLocale;
std::vector<DictionaryDefinition> dictionaries;
std::vector<FunctionDefinition> functions;
std::vector<Card> cards;
std::vector<BlueprintScene> scenes;
};# Dictionary with keys:
# "format": String — always "lsde-blueprints"
# "version": int — the FORMAT version, 1
# "generator": Dictionary
# "exportedAt": String — ISO 8601
# "project": String
# "locales": Array[String]
# "referenceLocale": String
# "dictionaries": Array[Dictionary]
# "functions": Array[Dictionary]
# "cards": Array[Dictionary]
# "scenes": Array[Dictionary]Scenes
A scene is a self-contained dialogue sequence — a conversation, a cutscene, a tutorial prompt, a shop interaction. In a game, scenes are typically triggered by script events: the player talks to an NPC, enters a zone, or picks up an item.
Each scene has its own entry block, its own flow, and its own state. Multiple scenes can run in parallel (e.g. a main dialogue and a tutorial overlay). Scenes are defined by the BlueprintScene interface:
interface Scene {
scene: string; // the path — reactor_breach. Builds the i18n keys; changes on a rename.
id: string; // the stable id — sc_u0vqg2g8. Store THIS outside the payload.
label?: string;
start?: string; // the id of the entry block. The scene names it; blocks carry no flag.
blocks: Block[]; // wires live on each block, in block.next. There is no connection table.
}public class BlueprintScene {
public string Scene { get; set; } // the path — reactor_breach
public string Id { get; set; } // the stable id — sc_u0vqg2g8
public string? Label { get; set; }
public string? Start { get; set; } // the id of the entry block
public List<BlueprintBlock> Blocks { get; set; }
}struct BlueprintScene {
std::string scene; // the path — reactor_breach
std::string id; // the stable id — sc_u0vqg2g8
std::optional<std::string> label;
std::optional<std::string> start; // the id of the entry block
std::vector<BlueprintBlock> blocks;
};# Dictionary with keys:
# "scene": String — the path, reactor_breach
# "id": String — the stable id, sc_u0vqg2g8
# "label": String (optional)
# "start": String (optional) — the id of the entry block
# "blocks": Array[Dictionary] — wires live on each block, in block["next"]Connections
Connections are the wires between blocks — they define which block leads to which. There is no connection table in the export: every block carries its own outgoing wires in block.next, and a wire only says which port it leaves by and where it goes.
A wire has never crossed a scene, in any version of the format: to always names a block of the same scene.
BlueprintConnection is the flattened view of those wires, the one engine.getSceneConnections(sceneRef) returns — a wire with the block it leaves put back on it:
// A Link, plus the block it leaves. `Link` is what the payload carries, on block.next.
type BlueprintConnection = Link & { from: string };
interface Link {
port: string; // the exit port NAME: out, then, catch, default, C1, K1, or a card id
to: string; // the id of the target block, IN THE SAME SCENE
toPort: string; // always "in"
}public class BlueprintConnection {
public string From { get; set; } // the id of the block this wire leaves
public string Port { get; set; } // the exit port NAME
public string To { get; set; } // the id of the target block, in the same scene
public string ToPort { get; set; } // always "in"
}struct BlueprintConnection {
std::string from; // the id of the block this wire leaves
std::string port; // the exit port NAME
std::string to; // the id of the target block, in the same scene
std::string toPort = "in";
};# Dictionary with keys:
# "from": String — the id of the block this wire leaves
# "port": String — the exit port NAME: out, then, catch, default, C1, K1, or a card id
# "to": String — the id of the target block, in the same scene
# "toPort": String — always "in"You won't typically need to inspect them — the engine handles routing internally. engine.getSceneConnections(sceneRef) exposes them for graph inspection: a debug view that shows the wiring without playing the scene.
Dictionaries
Dictionaries describe the registers of your game — switches, variables, inventory. The developer declares them in the LSDE editor to expose available game variables to the narrative designer. At runtime, the developer maps each dictionary to the corresponding system in their game. Conditions and onResolveCondition use these keys to evaluate game state. Defined by the DictionaryDefinition interface:
interface DictionaryDefinition {
id: string; // what a ConditionTest.dict cites
valueType: 'boolean' | 'number' | 'string'; // what its entries hold
entries: string[]; // the entry names, flat
}public class DictionaryDefinition {
public string Id { get; set; }
public string ValueType { get; set; } // "boolean" | "number" | "string"
public List<string> Entries { get; set; }
}struct DictionaryDefinition {
std::string id;
std::string valueType; // "boolean" | "number" | "string"
std::vector<std::string> entries;
};# Dictionary with keys:
# "id": String
# "valueType": "boolean" | "number" | "string"
# "entries": Array[String]Functions
Functions describe what your game knows how to do — set_flag, play_sound, give_item. The developer declares them in the LSDE editor so that narrative designers can compose sequences with typed parameters. At runtime, the function id is what the developer maps to their own systems: an ACTION block cites it in call.fn, and its arguments arrive by name in call.args. Defined by the FunctionDefinition interface:
interface FunctionDefinition {
id: string; // what an ActionCall.fn names
params: FunctionParameter[];
}
interface FunctionParameter {
name: string; // ActionCall.args is keyed BY NAME, never by position
type: ValueType; // 'boolean' | 'number' | 'string' | 'dictionaryKey'
dictionary?: string; // for type 'dictionaryKey': the DictionaryDefinition.id it draws from
}public class FunctionDefinition {
public string Id { get; set; }
public List<FunctionParameter> Params { get; set; }
}
public class FunctionParameter {
public string Name { get; set; }
public string Type { get; set; }
public string? Dictionary { get; set; }
}struct FunctionDefinition {
std::string id;
std::vector<FunctionParameter> params;
};
struct FunctionParameter {
std::string name;
std::string type;
std::optional<std::string> dictionary;
};# FunctionDefinition Dictionary:
# "id": String
# "params": Array[FunctionParameter]
#
# FunctionParameter Dictionary:
# "name": String — args are keyed BY NAME, never by position
# "type": "boolean" | "number" | "string" | "dictionaryKey"
# "dictionary": String (optional) — for type "dictionaryKey", the DictionaryDefinition id