| name | godot-genre-visual-novel |
| description | Expert blueprint for visual novels (Doki Doki Literature Club, Phoenix Wright, Steins;Gate) focusing on branching narratives, dialogue systems, choice consequences, rollback mechanics, and persistent flags. Use when building story-driven, choice-based, or dating sim games. Keywords visual novel, dialogue system, branching narrative, typewriter effect, rollback, bbcode, RichTextLabel. |
Genre: Visual Novel
Branching narratives, meaningful choices, and quality-of-life features define visual novels.
Core Loop
- Read → dialogue / narration
- Decide → choice moment
- Branch → flag or path change
- Consequence → immediate line variation and/or lasting flag
- Conclude → one of multiple endings
NEVER Do (Expert Anti-Patterns)
Narrative & Flow
- NEVER create the "Illusion of Choice" exclusively; strictly provide Immediate Dialogue Variations or Flag Changes even if the plot converges later.
- NEVER skip mandatory QoL features; strictly implement Auto-Play, Fast-Forward, and Backlog/History for replayability.
- NEVER display "Walls of Text"; strictly limit dialogue boxes to 3-4 Lines max to avoid intimidating the reader.
- NEVER hardcode dialogue text inside GDScripts; strictly store narrative scripts in External Files (JSON, CSV, or custom Resources) for iteration.
- NEVER ignore the Rollback mechanic; strictly maintain a history stack so players can undo miss-clicks or reread missed lines.
Technical & UI
- NEVER use plain text for emotional beats; strictly use RichTextLabel BBCode (e.g.,
[shake], [wave]) to add visual weight.
- NEVER parse massive narrative files on the main thread; strictly use
ResourceLoader.load_threaded_request() to prevent transition stutters.
- NEVER use standard Strings for frequently accessed game flags; strictly use
StringName (&"met_alice") for faster dictionary lookups.
- NEVER use
_process for letter-by-letter animation; strictly use a Tween on visible_ratio for smooth, frame-independent reveals.
- NEVER neglect character Z-ordering; strictly ensure the active speaker is brought to the front for visual clarity.
- NEVER use
z_index for Control node priority if input handling is required; strictly use move_to_front() to ensure draw order and input propagation match.
- NEVER use absolute pixel positioning for character sprites; strictly rely on Anchors & Percent-based Offsets for responsive scaling.
- NEVER allow text animations to continue when the player skips; strictly set
visible_ratio to 1.0 instantly on input.
- NEVER leave orphaned character sprites; strictly use
queue_free() when actors exit the stage to prevent memory leaks.
- NEVER mutate flags before snapshotting rollback state — always push history, then apply the choice.
🛠 Expert Components (scripts/)
MANDATORY before implementing undo / branching / presentation:
- vn_rollback_manager.gd — history stack (flags/backgrounds/index)
- story_manager.gd — flag-aware dialog orchestration
- dialogue_ui.gd — typewriter + choice UI
- visual_novel_patterns.gd — BBCode, choice filtering, sprite layering
Catalog (deduped)
- story_manager.gd - Flag-aware dialog orchestrator with branching logic and character state persistence.
- dialogue_ui.gd - Presentation layer: typewriter tweens (
visible_ratio) and choice-window generation.
- vn_rollback_manager.gd - History stack for state rollback (flags/backgrounds/index).
- visual_novel_patterns.gd - Reusable BBCode effects, choice filtering by flags, sprite layering.
Decision Tree: Script Storage vs Plugin
| Approach | When to choose | Notes |
|---|
| JSON / CSV scripts | Writers edit outside Godot; rapid iteration | Load via FileAccess or threaded ResourceLoader; validate schema in StoryManager |
Custom Resource dialogue trees | Designer Inspector editing, typed fields | Peer godot-resource-data-patterns; MANDATORY story_manager.gd |
| Dialogic (plugin) | Full VN suite (timelines, characters, themes) with editor tooling | Prefer when shipping a large route graph fast; still keep rollback + flag discipline. Skip building a second StoryManager if Dialogic already owns timelines |
| Build lightweight custom | Tiny kinetic novel / learning project | Use scripts in this skill; do not re-stub StoryManager inline |
Do not paste incomplete JSON StoryManager demos — implement from MANDATORY story_manager.gd.
Golden Path (order matters)
- Snapshot before mutate — On every advance/choice, MANDATORY vn_rollback_manager.gd pushes
{line_index, flags, background, music} before flag writes.
- Typewriter + skip — dialogue_ui.gd: Tween
visible_ratio 0→1; on skip/advance input set visible_ratio = 1.0 and kill the tween.
- Choice filter by flags — Present only options whose
requires StringName flags pass; apply choice → mutate flags → jump label (visual_novel_patterns.gd + story_manager.gd).
- Speaker focus —
move_to_front() on Control actors (not z_index alone) + dim inactive.
- Heavy CG/BG —
ResourceLoader.load_threaded_request for backgrounds; never sync-parse huge scripts on the main thread.
# Choice handler shape (flags after snapshot)
func make_choice(choice_id: StringName) -> void:
rollback_manager.push_snapshot() # BEFORE mutate
match choice_id:
&"be_nice":
flags[&"relationship_alice"] = int(flags.get(&"relationship_alice", 0)) + 1
story_manager.jump_to_label(&"alice_happy")
&"be_mean":
flags[&"relationship_alice"] = int(flags.get(&"relationship_alice", 0)) - 1
story_manager.jump_to_label(&"alice_sad")
Common Pitfalls
- Walls of text — Cap dialogue to 3–4 lines.
- Illusion of choice — Always vary lines or flags even on converging plots.
- Missing QoL — Auto / Skip / Backlog / Save are mandatory genre features.
- Broken rollback — Mutating flags before snapshot makes undo lie.
Deep recipes (on demand)
Reference
Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain — do not preload the whole lattice.
Official Documentation
- BBCode in RichTextLabel — shake/wave BBCode and append_text for emotional dialogue without plain Label walls.
- Size and anchors — percent offsets and anchors so character sprites and dialogue boxes scale across resolutions.
- GUI containers — VBox/HBox choice rows and dialogue chrome instead of absolute pixel layouts.
- Background loading — ResourceLoader.load_threaded_request so heavy CG/background swaps never hitch the typewriter.
- Saving games — FileAccess patterns for flags, history stacks, and multi-slot VN saves.
- Resources — typed dialogue/choice Resources as an alternative to brittle hardcoded JSON strings.
- Internationalizing games — tr() / CSV keys so script lines stay localization-ready.
- Audio streams — BGM crossfades and optional voice lines tied to line advances.
- Using InputEvent — skip/advance/ui_accept handling that finishes visible_ratio instantly.
- Singletons (Autoload) — persistent flag/history owners across chapter scene changes.
- Signals — line_advanced / options_presented wiring between StoryManager and DialogueUI.
- Tween — tween_property on RichTextLabel.visible_ratio for frame-independent typewriter reveals.
Related Skills
Prerequisites
Complements
Downstream / consumers
Master
- godot-master — library router and mirrored module entry for cross-skill discovery.