Understanding branching complexity in visual novels
Every visual novel developer reaches a point where they can no longer hold the full story structure in their head. The script keeps growing, the menu choices multiply, and the question "does this choice actually matter?" stops having an obvious answer.
This isn't a writing problem. It's a structural visibility problem. Here's what's happening mathematically and what you can do about it.
Why simple scripts become hard to reason about
A visual novel script is a directed graph. Labels are nodes, jumps and calls are edges.
When you write menu: with three options, you're creating three outgoing edges
from one node — and those three paths may each branch further downstream.
At small scale this is easy to track mentally. Three labels, two choices, one merge point. You can sketch it on paper.
At medium scale — 50 labels, 20 choice points, 8 possible endings — paper sketches stop working. You're maintaining an implicit mental model of the graph, and that model degrades every time you write new content without looking at the whole structure.
Choice explosion: the numbers
The maximum number of distinct paths through a script grows exponentially with the number of branching choice points. For a simple binary-branching structure (every choice has exactly two options, no merging):
| Choice points | Maximum distinct paths | Testable manually? |
|---|---|---|
| 5 | 32 | Easily |
| 10 | 1,024 | With effort |
| 15 | 32,768 | No |
| 20 | 1,048,576 | No |
Most visual novels merge branches back together frequently — reducing the actual path count well below the theoretical maximum. But "merge at next chapter" is not the same as "all choices are equivalent." The paths between the choice and the merge point may contain different scenes, different assets, different variable states. Those intermediate paths each need to work correctly.
What scripts look like as they grow
Early in a project, the flow is linear with occasional branches:
As the project grows, structure accumulates. New scenes are added between existing ones. Endings multiply. Variables start affecting which branches are reachable:
Now add two more chapters, three more endings, variable-gated paths that only appear if a stat is above a threshold, and a hidden route added halfway through development — and you have a graph that no developer can keep accurate in memory.
Structural problems that only appear at scale
Dead labels
Labels that nothing jumps to. They were written, perhaps fully voiced and illustrated, but removed from the active story flow when the narrative changed. They still exist in the script file. They consume assets. They're invisible in a text editor.
Jump targets that don't exist
A jump ending_secret_route that was added before the label was created —
and then the label creation was forgotten. The error only appears when a player reaches
that exact point in the story.
Orphaned variable state
A variable is set in one branch and read in another, but the path that reads it can also be reached without ever setting it. The variable has its default value — which may produce a grammatically wrong dialogue line, a wrong character expression, or a silent logic error that accumulates through the rest of the game.
Why visual maps change what you can see
Reading a .rpy file is a linear experience. You see labels in the order
they're written, not in the order a player experiences them. A jump
at the bottom of a screen-length label sends execution somewhere that may be hundreds
of lines away, across multiple files.
A visual map renders the same information as a graph — nodes for labels, edges for jumps and calls. On that map you can see, at a glance:
- Which labels have no incoming edges (potential dead labels, or true entry points)
- Which labels have no outgoing edges (endings, or labels that should have a jump but don't)
- Where the story reconverges after branches
- Which nodes have unusually many incoming edges (merge points that many paths pass through)
- Whether the graph has connected components — isolated sub-graphs that can't be reached from the start
None of this is visible from a text editor. All of it is visible in seconds on a graph.
How BranchPy visualises story structure
BranchPy's flow visualiser reads every .rpy file in your project and
generates an interactive node graph. Each label becomes a node. Each jump,
call, and menu-generated branch becomes an edge. The graph is laid out
automatically and is searchable by label name.
This doesn't require any changes to your scripts. You keep writing Ren'Py the way you always have.
Summary
- Branching complexity grows exponentially with the number of choice points.
- Manual testing can cover a small fraction of all possible paths in a mid-size project.
- Structural problems — dead labels, missing jump targets, orphaned paths — are invisible in a text editor at scale.
- A visual map of the story graph makes these problems immediately visible without running the game.
- Understanding structure is a prerequisite for testing it effectively.
See what BranchPy analyses →