Visual Novel
A playbook for visual novels — the branching script, the presentation (text box, characters,
backgrounds), choices, and the quality-of-life systems players expect (save anywhere, backlog,
skip, auto). This is a compositional skill: it drives a dialogue engine and a UI layer. It
does not re-teach the dialogue engine or UI nodes; it defines the script model and the player
conveniences that make a VN pleasant to read.
When to use
- Use when the game is mostly reading branching text with character art and backgrounds:
visual novel, dating sim, branching interactive fiction, story-choice game.
- Use when designing a choice/route structure, story flags, or VN conveniences (backlog,
skip, auto-advance, save-anywhere).
When not to use: dialogue as one feature inside a larger game → rpg consuming
dialogue-systems. Card/board play → other genres. For the branching-script engine itself,
use dialogue-systems (Ink / Yarn Spinner).
Core loop
Read a line → advance → (at a branch) make a choice → the story branches on flags/choices →
read on → reach an ending. The "game" is the shape of the branching and whether choices
feel consequential; everything else is presentation and convenience.
Must-have systems
- Branching script — ordered lines + choices + jumps, with conditions and variables (Ink/Yarn).
- Text box — speaker name, body text, typewriter reveal, advance on click/key.
- Characters — sprites with expressions/poses, positions, show/hide transitions.
- Backgrounds + transitions — scene images, fades/dissolves.
- Choices — present options, gate some on flags, record the pick.
- Story state — flags/variables that branch the script and unlock content.
- Save/load (save-anywhere) — full script position + state; multiple slots; quick save.
- VN conveniences — backlog/history, skip (read text), auto-advance, text-speed setting.
- Audio — music per scene, SFX, optional voice clips.
Design knobs
| Knob |
Effect |
Notes |
| Text speed / instant |
reading comfort |
Always allow instant + a skip. |
| Auto-advance delay |
hands-free reading |
Tunable; pause on choices. |
| Skip scope |
re-reading |
Skip read text only by default. |
| Branch breadth/depth |
replay value vs. cost |
Branches multiply writing/art work. |
| Flag-gated content |
reactivity |
Lines/choices that check past decisions. |
| Route structure |
story shape |
Branch-and-merge vs. distinct routes (refs). |
| Choice visibility |
fairness |
Show locked choices vs. hide them. |
| Backlog length |
convenience |
Keep enough to re-read recent context. |
Patterns
1. Script as data the engine walks
# Pseudocode. Lines, choices, and jumps as data — usually authored in Ink/Yarn and stepped
# through by that runtime. The engine asks the script for "the next thing to show".
node = script.current()
if node.kind == "line":
show_text(node.speaker, node.text) # wait for advance input
elif node.kind == "choice":
options = [o for o in node.options if condition_met(o.condition, flags)] # gate by flags
show_choices(options) # wait for selection
elif node.kind == "set":
flags[node.var] = eval_expr(node.expr, flags)
script.advance(selected_option_or_none)
2. Typewriter reveal + advance (skippable)
# Pseudocode. Reveal characters over time; a click first completes the line, then advances.
def show_text(speaker, text):
name_label.text = speaker
revealed = 0
while revealed < len(text):
if advance_pressed(): # first press: reveal the whole line instantly
revealed = len(text); break
revealed += chars_per_second * dt
body_label.text = text[:int(revealed)]
push_to_backlog_when_complete(speaker, text)
wait_for_advance() # second press: go to the next line
3. Choice sets a flag that branches later content
# Pseudocode. Choices write flags; later conditions read them — that is "reactivity".
def on_choice(option):
if option.set: flags[option.set] = True # e.g. flags["helped_npc"] = True
script.jump(option.target) # follow the branch
# Elsewhere, a line/choice/ending checks the flag:
if flags.get("helped_npc"): play_route("good_ending") else: play_route("neutral_ending")
Pitfalls / failure modes
- Save that only stores a checkpoint → VNs need save-anywhere. Persist the exact script
position and all flags/variables (and seen-text data) so a load resumes the same line.
- Presentation logic baked into the script → unmaintainable. Keep content (text, choices)
in the script and how it looks (sprites, transitions) in the engine layer.
- No skip/auto/backlog → readers feel trapped, especially on replays. These are expected
baseline features, not extras.
- Skipping unread text → players miss content. Skip should fast-forward read text only.
- Choices with no consequence → branches that reconverge instantly feel fake. Set flags that
visibly change later lines, choices, or endings.
- Combinatorial branch explosion → unshippable. Prefer branch-and-merge with a few flagged
variations over fully distinct trees (refs).
- Lost reading context → no backlog to re-read the last lines. Keep a history buffer.
- Hardcoded language → no localization path. Keep text in data keyed for translation.
Composition (build it from these skills)
- Script engine:
dialogue-systems (Ink / Yarn Spinner) — branching, conditions, variables, localization hooks.
- Presentation:
game-ui-ux for text-box/choice-menu layout, scaling, and safe areas; godot-ui-control for the concrete text box, choice menu, name plate, and backlog UI.
- Persistence:
save-systems for save-anywhere slots, seen-text/skip data, and settings.
- Audio:
audio-design for per-scene music, SFX, and voice playback.
- Visuals: the engine animation/
Tween skill for sprite/background transitions; shader-programming for dissolves.
- Process:
prototype-fast to test the branch structure in plain text before adding art.
References
- For the branching data model, route structures (branch-and-merge vs. routes), flags/variables,
save-anywhere + backlog/skip data, and the content/presentation split, read
references/script-and-flow.md.
1---
2name: visual-novel
3description: >
4 Build a visual novel: a branching script, character and background display, a text box with choices,
5 save/load, backlog, and skip/auto. Use for a VN, dating sim, or branching story game.
6---
7
8# Visual Novel
9
10A playbook for visual novels — the branching script, the presentation (text box, characters,
11backgrounds), choices, and the quality-of-life systems players expect (save anywhere, backlog,
12skip, auto). This is a **compositional** skill: it drives a dialogue engine and a UI layer. It
13does not re-teach the dialogue engine or UI nodes; it defines the script model and the player
14conveniences that make a VN pleasant to read.
15
16## When to use
17
18- Use when the game is **mostly reading branching text** with character art and backgrounds:
19 visual novel, dating sim, branching interactive fiction, story-choice game.
20- Use when designing a choice/route structure, story flags, or VN conveniences (backlog,
21 skip, auto-advance, save-anywhere).
22
23**When *not* to use:** dialogue as one feature inside a larger game → `rpg` consuming
24`dialogue-systems`. Card/board play → other genres. For the branching-script engine itself,
25use `dialogue-systems` (Ink / Yarn Spinner).
26
27## Core loop
28
29**Read a line → advance → (at a branch) make a choice → the story branches on flags/choices →
30read on → reach an ending.** The "game" is the *shape of the branching* and whether choices
31feel consequential; everything else is presentation and convenience.
32
33## Must-have systems
34
351. **Branching script** — ordered lines + choices + jumps, with conditions and variables (Ink/Yarn).
362. **Text box** — speaker name, body text, typewriter reveal, advance on click/key.
373. **Characters** — sprites with expressions/poses, positions, show/hide transitions.
384. **Backgrounds + transitions** — scene images, fades/dissolves.
395. **Choices** — present options, gate some on flags, record the pick.
406. **Story state** — flags/variables that branch the script and unlock content.
417. **Save/load (save-anywhere)** — full script position + state; multiple slots; quick save.
428. **VN conveniences** — backlog/history, skip (read text), auto-advance, text-speed setting.
439. **Audio** — music per scene, SFX, optional voice clips.
44
45## Design knobs
46
47| Knob | Effect | Notes |
48|------|--------|-------|
49| Text speed / instant | reading comfort | Always allow instant + a skip. |
50| Auto-advance delay | hands-free reading | Tunable; pause on choices. |
51| Skip scope | re-reading | Skip *read* text only by default. |
52| Branch breadth/depth | replay value vs. cost | Branches multiply writing/art work. |
53| Flag-gated content | reactivity | Lines/choices that check past decisions. |
54| Route structure | story shape | Branch-and-merge vs. distinct routes (refs). |
55| Choice visibility | fairness | Show locked choices vs. hide them. |
56| Backlog length | convenience | Keep enough to re-read recent context. |
57
58## Patterns
59
60### 1. Script as data the engine walks
61
62```python
63# Pseudocode. Lines, choices, and jumps as data — usually authored in Ink/Yarn and stepped
64# through by that runtime. The engine asks the script for "the next thing to show".
65node = script.current()
66if node.kind == "line":
67 show_text(node.speaker, node.text) # wait for advance input
68elif node.kind == "choice":
69 options = [o for o in node.options if condition_met(o.condition, flags)] # gate by flags
70 show_choices(options) # wait for selection
71elif node.kind == "set":
72 flags[node.var] = eval_expr(node.expr, flags)
73script.advance(selected_option_or_none)
74```
75
76### 2. Typewriter reveal + advance (skippable)
77
78```python
79# Pseudocode. Reveal characters over time; a click first completes the line, then advances.
80def show_text(speaker, text):
81 name_label.text = speaker
82 revealed = 0
83 while revealed < len(text):
84 if advance_pressed(): # first press: reveal the whole line instantly
85 revealed = len(text); break
86 revealed += chars_per_second * dt
87 body_label.text = text[:int(revealed)]
88 push_to_backlog_when_complete(speaker, text)
89 wait_for_advance() # second press: go to the next line
90```
91
92### 3. Choice sets a flag that branches later content
93
94```python
95# Pseudocode. Choices write flags; later conditions read them — that is "reactivity".
96def on_choice(option):
97 if option.set: flags[option.set] = True # e.g. flags["helped_npc"] = True
98 script.jump(option.target) # follow the branch
99
100# Elsewhere, a line/choice/ending checks the flag:
101if flags.get("helped_npc"): play_route("good_ending") else: play_route("neutral_ending")
102```
103
104## Pitfalls / failure modes
105
106- **Save that only stores a checkpoint** → VNs need **save-anywhere**. Persist the exact script
107 position *and* all flags/variables (and seen-text data) so a load resumes the same line.
108- **Presentation logic baked into the script** → unmaintainable. Keep *content* (text, choices)
109 in the script and *how it looks* (sprites, transitions) in the engine layer.
110- **No skip/auto/backlog** → readers feel trapped, especially on replays. These are expected
111 baseline features, not extras.
112- **Skipping unread text** → players miss content. Skip should fast-forward **read** text only.
113- **Choices with no consequence** → branches that reconverge instantly feel fake. Set flags that
114 visibly change later lines, choices, or endings.
115- **Combinatorial branch explosion** → unshippable. Prefer branch-and-merge with a few flagged
116 variations over fully distinct trees (refs).
117- **Lost reading context** → no backlog to re-read the last lines. Keep a history buffer.
118- **Hardcoded language** → no localization path. Keep text in data keyed for translation.
119
120## Composition (build it from these skills)
121
122- **Script engine:** `dialogue-systems` (Ink / Yarn Spinner) — branching, conditions, variables, localization hooks.
123- **Presentation:** `game-ui-ux` for text-box/choice-menu layout, scaling, and safe areas; `godot-ui-control` for the concrete text box, choice menu, name plate, and backlog UI.
124- **Persistence:** `save-systems` for save-anywhere slots, seen-text/skip data, and settings.
125- **Audio:** `audio-design` for per-scene music, SFX, and voice playback.
126- **Visuals:** the engine animation/`Tween` skill for sprite/background transitions; `shader-programming` for dissolves.
127- **Process:** `prototype-fast` to test the branch structure in plain text before adding art.
128
129## References
130
131- For the branching data model, route structures (branch-and-merge vs. routes), flags/variables,
132 save-anywhere + backlog/skip data, and the content/presentation split, read
133 `references/script-and-flow.md`.