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