Skip to content
Development
Skill

/dialogue-systems

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

From plugin
awesome-gamedev-agent-skills
6.3k77 skills

Claude Code

$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill dialogue-systems --agent claude-code

SKILL.md

dialogue-systems.SKILL.md
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

1. **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. 2. **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. 3. **Separate variables from flow.** Keep a variable store (booleans, numbers, strings) the dialogue reads/writes; gate choices with conditions over it. 4. **Localize from the start.** Author with **line IDs**, not raw strings, so the displayed text comes from a string table keyed by locale. 5. **Drive it from the game loop.** The runner is a state machine: `current` node → emit content → wait for input (continue or choice) → advance. 6. **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",
  "vars": { "gold": 0, "gate_open": false },
  "nodes": {
    "guard_intro": {
      "speaker": "Guard", "line": "DLG_GUARD_001",
      "choices": [
        { "text": "DLG_OPT_BRIBE", "to": "bribe", "if": "gold >= 50",
          "set": { "gold": "gold - 50" } },
        { "text": "DLG_OPT_LEAVE", "to": "end" }
      ]
    },
    "bribe": {
      "speaker": "Guard", "line": "DLG_GUARD_BRIBED",
      "set": { "gate_open": true },
      "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 gold cost sits on the *choice*, so it is paid once per pick even if the `bribe` node is revisited; the idempotent `gate_open` write can live on the node. A string `set` value is an expression, so a literal string needs inner quotes: `"mood": "'angry'"`. The full interpreter that walks this graph is in `references/runner.md`. Its variable store starts from `vars`; replace those defaults with the player's saved narrative state when starting a real conversation. Declare every referenced variable so unknown names still expose authoring mistakes.

2. Runner step (a state machine over the graph)

# Godot 4.7. The runner holds the current node and a variable store. Every line
# waits for the player: the UI calls choose() or the continue callback.
func goto(id: String) -> void:
    current = graph.nodes[id]
    apply_set(current.get("set", {}))
    if current.get("end", false):
        ui.close()
        return
    if current.has("line"):
        ui.show_line(current.get("speaker", ""), localize(current.line))
    if current.has("choices"):
        var shown = current.choices.filter(func(c): return eval_cond(c.get("if", "")))
        ui.show_choices(shown)            # only choices whose condition passes
    elif current.has("next"):
        var next_id: String = current.next
        ui.show_continue(func(): goto(next_id))   # advance when the player continues

func choose(choice: Dictionary) -> void:   # called when the player picks a choice
    apply_set(choice.get("set", {}))       # write on the transition (revisit-safe)
    goto(choice.to)

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 story starts at the top: divert into a knot

=== 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 = $go
Read more
@gamedev-skills
Ships withawesome-gamedev-agent-skills

<img src="docs/assets/awesome-gamedev-agent-skills-banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.

Stars on GitHub

Momentum

stars in total
6.3k
Star history of gamedev-skills/awesome-gamedev-agent-skills on GitHub, a chart by star-history.com

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc11d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about dialogue-systems.

Which coding agents can use dialogue-systems?
dialogue-systems installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.