Git-native narrative design
for story-driven games

Schema-first. Engine-agnostic. Your story is plain JSON in your repo — no database, no export step, no proprietary format between your writers and your game.

Download Parlance Play the demo Read the docs macOS · Windows · Linux — free, including for commercial games · the format spec is MIT

Your story is files

Every character, dialogue, and quest is a human-readable JSON file the visual editor reads and writes directly. Git is the single source of truth — which means narrative gets branches, diffs, reviews, and CI, just like code.

{
  "id": "dlg_wren_cornered",
  "title": "Wren — The Yard",
  "speakerId": "npc_wren",
  "offer": {
    "when": { "type": "flag", "flag": "knows_wren_dismissed", "value": true }
  },
  "entry": "node_corner",
  "nodes": [ … ]
}
$ git diff data/dialogues/dlg_wren_first.json

  "text":
-  "I sell tinctures. Nothing stronger."
+  "I sell tinctures, magistrate. Nothing stronger —
+   nothing that would do *that* to a man."

One line of dialogue changed. One line in the diff.
Review it in a pull request like everything else.

Built around the way stories actually branch

A visual editor for the whole narrative layer — not just dialogue trees. This is it, editing the demo mystery:

The Parlance editor: a dialogue node graph with skill-check badges, START and END markers, and a pacing panel showing words, nodes, choices, and dead ends

The dialogue canvas — a suspect's confrontation scene, with skill-check routes (green success / red failure) and live pacing analysis.

Dialogue offers and conditional narration

Each dialogue declares an offer — when it should play, and at what priority. Talk to a suspect before you find the evidence and you get one scene; talk to them after, and a more specific offer wins — no ordering to maintain, no scripting.

Within a scene, conditional narration lets you gate individual lines on state. A narration line whose condition fails is skipped; on a node with choices, only the line is hidden and the choices stay. A beat belongs only to a player who earned it, without fabricating fake choices. Choices can be gated too: shown greyed out with a reason when locked, or held back as a fallback for when nothing else is available.

How dialogue offers work →

A dialogue inspector in Parlance showing the Offer fields and a live resolution preview highlighting which of a character's dialogues wins in the current state

Wren's offers: the confrontation gated on evidence, the first meeting as the fallback — the inspector shows which one wins right now.

Playtest mode in Parlance: the active node glows on the canvas while the play panel shows a passed Observation check, applied effects, a discovery pool, and a live state table

A live session: the d20 roll, the effects it fired, where the story can go next, and every flag it touched.

Playtest in place — then hand anyone a playable file

Walk any scene with a live simulated game state: seeded, deterministic dice, a rewindable transcript, forced check outcomes, and edit-while-playing. When a scene is ready for feedback, export a share build — one self-contained HTML file that plays in any browser, no install.

Playtesting & determinism →

Validation everywhere — on save, in CI, in your pipeline

Thirty families of checks run on every save and stream to every open editor window. The validator catches classic structural bugs like dangling references, unreachable nodes, quests that can't complete, and dialogue-offer mistakes. It also includes a prose check that learns your project's proper nouns to act as a narrative-aware spellchecker inline as you type.

The same validator runs headless as parlance ci-check, so a broken story fails the build before it ships. And Explore plays the story for you — every choice, both outcomes of every check — to find the nodes no playthrough reaches and the states where a player gets stuck.

The validation model →

$ parlance ci-check . --strict

✗ [REF]    dlg_accuse: choice targets missing
           node "node_confession"
⚠ [OFFER]  dlg_bragg_first: priority 1 but no 'when' —
           it out-ranks every other offer forever
⚠ [FLAG]   flag "heard_bell" is set but never read

exit 1  — the build fails, the story stays whole

A contract, not an exporter

Your engine reads the exact files the editor writes. The runtime semantics are a published contract with conformance vectors — ports prove themselves against the vectors, not against vibes.

The Godot runtime executes Parlance JSON natively in GDScript and is verified against the published conformance suite. The same vectors are how any engine — Unity, custom, whatever — gets a provably-correct port.

The contract, schemas, and vectors are published as parlance-spec under MIT — your data's meaning never depends on our goodwill.

There's also an MCP server, so LLM agents can read and write project data through the same validated path the editor uses.

The engine contract →

  PASS  mulberry32                  6 vectors
  PASS  evaluate                   53 vectors
  PASS  applyEffect                29 vectors
  PASS  resolveCheck               24 vectors
  PASS  stepDialogue               24 vectors
  PASS  chooseChoice               17 vectors
  PASS  advanceNode                14 vectors
  PASS  resolveCharacterDialogue   16 vectors
  PASS  nextContinuations           4 vectors
  PASS  resolveQuests               7 vectors
  PASS  progression                13 vectors

  207 passed, 0 failed, 0 skipped

Try it on a real mystery

The demo project is a complete, tiny whodunit: one night, one body, three suspects, three endings. Skill checks with real failure branches, evidence-gated dialogue offers, counters, quests — every feature demonstrated in a story you can actually play. Released CC0.

First dialogue in ten minutes