Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 28% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 33% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 48% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 38% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 99% | 0% |
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.
(flags, relationship values) that affect later dialogue.
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.
dialogue-heavy or CYOA narrative. Integrate via ink runtime / inkle plugins.
<<commands>>, strong forgame-driven dialogue with lots of engine hooks.
full control or minimal dependencies. Don't build a language; build a graph.
a set of choices, a command/side-effect, or an end/jump. The runner advances through nodes and hands lines/choices to the UI.
strings) the dialogue reads/writes; gate choices with conditions over it.
displayed text comes from a string table keyed by locale.
current node→ emit content → wait for input (continue or choice) → advance.
variable writes, and that every branch reaches an end or a valid jump.
json{ "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.
gdscript# 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
ink// 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).
yarntitle: GuardIntro --- <<declare $gold = 60>> 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}.
rewrite. Author against a string table from day one.
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.
dialogue works in cutscenes, menus, and tests. Persist it via save-systems.
next, choices, or endsilently stalls. Validate that every node terminates or branches.
golddrained twice). Apply set on the transition, or guard with a seen-flag.
* (once-only) and + (sticky) by accident: looped menusneed sticky + choices or the options vanish after one use.
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.
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.Other measured skills in the registry, with their headline benchmark lift.