dialogue-systems
gamedev-skills/awesome-gamedev-agent-skills
Build branching dialogue trees with Ink, Yarn Spinner, or a custom JSON runner.
What is dialogue-systems?
Design conversations as node/choice graphs with conditions, variables, and localization. Choose between proven authoring tools (Ink or Yarn Spinner) or write a minimal data-driven runner. Use when designing branching dialogue, choice menus, or narrative state that affects later dialogue.
- Model conversations as a graph with nodes, choices, conditions, and variables
- Choose between Ink (prose-first), Yarn Spinner (node-based), or custom JSON/resource runners
- Separate dialogue logic from UI—wire scripts into your game loop to advance lines and present choices
- Gate dialogue options with conditions and mutate narrative state via variable writes
- Localize dialogue by keying lines to string-table IDs instead of hardcoded text
- Validate dialogue branches to ensure every node terminates, branches, or jumps correctly
How to install dialogue-systems
npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill dialogue-systemsHow to use dialogue-systems
- 1.Choose your authoring approach: Ink (prose-first, writer-friendly), Yarn Spinner (node-based, explicit commands), or a custom JSON graph runner
- 2.Define your node contract—each node yields a line, choices, a command, or an end/jump
- 3.Separate variables from flow: maintain a variable store (booleans, numbers, strings) that dialogue reads and writes
- 4.Author with line IDs, not raw strings, so displayed text comes from a localization string table
- 5.Implement a runner as a state machine: current node → emit content → wait for input → advance
- 6.Walk each dialogue branch to verify conditions, variable writes, and that every path reaches an end or valid jump
Use cases
- Design a branching NPC conversation where player choices affect available options and narrative flags
- Build a choice-driven narrative game or visual novel with persistent state across scenes
- Create a dialogue system that works engine-neutrally across Godot, Unity, or custom engines
- Implement a bribery or persuasion mechanic where dialogue choices depend on player resources or prior decisions
- Author dialogue-heavy CYOA (Choose Your Own Adventure) content with a writer-friendly tool like Ink
- Game designers building narrative-driven or dialogue-heavy games
- Writers authoring branching dialogue and interactive fiction
- Developers integrating dialogue systems into Godot, Unity, or custom engines
- Teams needing engine-neutral dialogue that persists state across sessions
dialogue-systems FAQ
Use Ink for prose-first, writer-friendly dialogue with complex flow control; Yarn Spinner for node-based dialogue with explicit engine hooks; custom JSON runner for minimal dependencies and full control over a simple branching tree. Don't build a language—build a graph.
Author against line IDs (e.g., 'DLG_GUARD_001') from the start, then populate a string table keyed by locale and line ID. The runner looks up the ID at display time, making localization a data change, not a rewrite.
Apply variable mutations (`set`) on the transition (choice or next), not on the line node itself. Alternatively, guard mutations with a seen-flag so they only fire once.
'*' is once-only: the choice disappears after selection. '+' is sticky: the choice remains available on revisits. Use '+' for looped menus; use '*' for one-time branching.
Store narrative variables and seen-flags separately from the dialogue runner, then use the `save-systems` skill to persist them to disk. Load the state when the game starts.
Full instructions (SKILL.md)
Source of truth, from gamedev-skills/awesome-gamedev-agent-skills.
name: dialogue-systems description: > Build branching dialogue and narrative — a node/choice graph with conditions, variables, and localization hooks — and choose between authoring tools Ink and Yarn Spinner or a custom data-driven runner. Engine-neutral. Use when the user mentions dialogue system, branching dialogue, conversation tree, choices, Ink (.ink), Yarn Spinner (.yarn), or NPC dialogue.
Dialogue systems
Model conversations as a graph: nodes hold lines, choices branch the flow,
conditions gate options, and variables remember what the player did. The first
real decision is build vs. buy — adopt a proven authoring tool (Ink or
Yarn Spinner) or write a small data-driven runner. This skill owns both Ink
and Yarn; the visual-novel and rpg genres consume it.
When to use
- Use to design branching conversations, choice menus, or narrative state (flags, relationship values) that affect later dialogue.
- Use to decide between Ink, Yarn Spinner, and a custom JSON/resource format.
- Use to wire a dialogue script into your game loop (advance line, present choices, run commands, resolve variables).
When not to use: for engine UI (text boxes, portraits, choice buttons), use
godot-ui-control or the engine's UI skill. For persisting narrative variables
across sessions, use save-systems. For data-as-resources in Godot/Unity, see
godot-resources / unity-scriptableobjects.
Core workflow
- Choose the authoring approach.
- Ink — prose-first, writer-friendly, weave/gather flow; great for dialogue-heavy or CYOA narrative. Integrate via ink runtime / inkle plugins.
- Yarn Spinner — node-based, explicit
<<commands>>, strong for game-driven dialogue with lots of engine hooks. - Custom runner — a JSON/resource graph + a small interpreter when you need full control or minimal dependencies. Don't build a language; build a graph.
- Define the node contract. A node yields one of: a line (speaker + text), a set of choices, a command/side-effect, or an end/jump. The runner advances through nodes and hands lines/choices to the UI.
- Separate variables from flow. Keep a variable store (booleans, numbers, strings) the dialogue reads/writes; gate choices with conditions over it.
- Localize from the start. Author with line IDs, not raw strings, so the displayed text comes from a string table keyed by locale.
- Drive it from the game loop. The runner is a state machine:
currentnode → emit content → wait for input (continue or choice) → advance. - Verify by walking branches. Exercise each choice path; confirm conditions, variable writes, and that every branch reaches an end or a valid jump.
Patterns
1. Engine-neutral dialogue graph (data, not code)
{
"start": "guard_intro",
"nodes": {
"guard_intro": {
"speaker": "Guard", "line": "DLG_GUARD_001",
"choices": [
{ "text": "DLG_OPT_BRIBE", "to": "bribe", "if": "gold >= 50" },
{ "text": "DLG_OPT_LEAVE", "to": "end" }
]
},
"bribe": {
"speaker": "Guard", "line": "DLG_GUARD_BRIBED",
"set": { "gate_open": true, "gold": "gold - 50" },
"next": "end"
},
"end": { "end": true }
}
}
line/text are string-table IDs (localization), not literal text. if
gates a choice; set mutates the variable store. The full interpreter that walks
this graph is in references/runner.md.
2. Runner step (a state machine over the graph)
# The runner holds the current node and a variable store; the UI calls advance().
func present(node):
if node.has("line"):
ui.show_line(node.speaker, localize(node.line))
if node.has("choices"):
var shown = node.choices.filter(func(c): return eval_cond(c.get("if", "")))
ui.show_choices(shown) # only choices whose condition passes
func choose(choice): # called when the player clicks a choice
apply_set(choice.get("set", {})) # write variables
goto(choice.to)
func goto(id):
current = graph.nodes[id]
apply_set(current.get("set", {}))
if current.get("end", false): ui.close(); return
present(current)
if current.has("next") and not current.has("choices"):
goto(current.next) # auto-advance linear nodes
3. Ink — branching with knots, choices, and variables (inkle)
// Ink: '*' = once-only choice, '+' = sticky. [bracketed] text shows only in the
// choice, not the printed result. '->' diverts; '-> END' stops the flow.
VAR gold = 60
=== guard_intro ===
The guard blocks the gate.
* {gold >= 50} [Offer 50 gold] "Here, take it."
~ gold = gold - 50
The guard pockets it and steps aside. -> END
* [Leave] You turn back. -> END
Ink tracks how often each knot was seen, so {visited_knot} is a built-in
condition. Variables are global (VAR) or temporary (~ temp).
4. Yarn Spinner — nodes, options, and commands (Yarn Spinner 3.x)
title: GuardIntro
---
<<declare $gold = 60>>
<<declare $gate_open = false>>
Guard: You can't pass.
-> Offer 50 gold <<if $gold >= 50>>
<<set $gold = $gold - 50>>
Guard: ...fine. Go on through.
<<set $gate_open to true>>
-> Leave
Guard: Good choice.
===
Yarn lines may start with Speaker:; options use ->; <<set>>/<<declare>>
manage $variables; <<if>> gates an option; <<jump NodeName>> moves between
nodes. Interpolate values in text with {$gold}. Declare every variable before first
use: an undeclared one still compiles (Yarn infers its type and a zero/false/empty
start value), but that hides typos. These constructs are unchanged from Yarn Spinner 2.x.
Pitfalls
- Hardcoding display strings instead of line IDs makes localization a rewrite. Author against a string table from day one.
- Inventing a scripting language for a simple branching tree. If you only need lines + choices + flags, a JSON/resource graph plus a 50-line runner beats a parser you must maintain. Use Ink/Yarn when writers need real flow control.
- Variables coupled to the UI: store narrative state separately so the same
dialogue works in cutscenes, menus, and tests. Persist it via
save-systems. - Unreachable or dead-end nodes: a node with no
next, choices, or end silently stalls. Validate that every node terminates or branches. - Mutating state in a line node the player can revisit double-applies (
golddrained twice). Applyseton the transition, or guard with a seen-flag. - Mixing Ink's
*(once-only) and+(sticky) by accident: looped menus need sticky+choices or the options vanish after one use.
References
references/ink-and-yarn.md— side-by-side syntax cheat sheet (choices, diverts/jumps, variables, conditions, includes) and integration notes.references/runner.md— a complete custom dialogue runner: graph schema, condition/expression evaluation, variable store, and localization lookup.
Related skills
save-systems— persist narrative variables and seen-flags.godot-resources,unity-scriptableobjects— store dialogue as engine data.godot-ui-control— render text boxes, portraits, and choice buttons.visual-novel,rpg— genres that compose this skill.
Related skills
More from gamedev-skills/awesome-gamedev-agent-skills and the wider catalog.

fps-shooter
Build first-person shooter mechanics: controller, hitscan/projectile combat, weapons, health, and enemy AI.

game-ai
Design NPC and enemy decision-making with FSMs, behavior trees, steering, and A* pathfinding.

game-feel
Add punchy, satisfying feedback—screen shake, hit-stop, easing, squash & stretch—to make game actions feel responsive.

game-jam
Plan and ship a game under a jam deadline: lock scope, schedule hours, cut features, submit on time.

game-ui-ux
Design responsive game UIs that work on any screen, input device, and aspect ratio.

godot-2d-movement
Build responsive 2D character controllers in Godot 4.x with CharacterBody2D and move_and_slide().