A VS Code extension that analyzes a Ren'Py project's .rpy scripts and shows:
Interactive flow diagram — labels, menus, jumps, and calls as a navigable node graph (double-click a node to jump to that line in the script). Includes a Mermaid export for sharing/docs.
Story stats — word counts, choice counts, branch depth, character appearances, scene/show tag usage, enumerated routes (with estimated reading time), orphan labels, and dead ends.
Diagnostics — duplicate labels and unresolved jump/call targets surface as warnings in the Problems panel.
Install (from source)
npm install
npm run compile
Then in VS Code: F5 (Run Extension) to launch an Extension Development Host with it loaded, or package it:
npx vsce package
This produces a .vsix you can install via Extensions: Install from VSIX....
Usage
Open a folder containing .rpy files, then run from the Command Palette:
Ren'Py Flow: Show Story Flow Diagram — opens the interactive graph.
Ren'Py Flow: Show Story Stats — opens the stats panel.
Ren'Py Flow: Export Diagram as Mermaid — opens Mermaid source in a new editor tab.
Ren'Py Flow: Export Analysis as JSON — full parsed model + stats as JSON.
Ren'Py Flow: Refresh Analysis — re-scans scripts (also runs automatically whenever you save a .rpy file while a panel is open).
Settings
Setting
Default
Description
renpyFlow.scriptsGlob
**/*.rpy
Which files to include
renpyFlow.excludeGlob
**/{tl,common,renpy}/**
Which files/folders to skip (translations, SDK common dir)
renpyFlow.wordsPerMinute
200
Reading speed used for route time estimates
How parsing works
The parser (src/parser.ts) tokenizes each file and tracks an indentation stack to follow Ren'Py's Python-style block nesting. It recognizes:
label name(params): and screen name(params): block headers
jump/call targets, including ones nested inside if/elif/else
menu: blocks and their "choice text" [if condition]: entries, resolving each choice's first inner jump/call as its target
dialogue lines (speaker "text" and bare narrator "text") for word counts and character tracking
The analyzer (src/analyzer.ts) builds an adjacency graph from resolved jumps/choices, finds entry points (the start label plus any label nothing else points to), and enumerates routes via DFS with loop detection (a revisited label ends that branch as "incomplete" rather than recursing forever).
Notes & limitations
Dynamic targets (jump expression some_var) and screen-driven navigation (e.g. button actions calling Jump()) aren't statically resolved — they'll show as diagnostics rather than graph edges.
Comment stripping is line-based and naive; a literal # inside a dialogue string on the same line as real content could be mis-stripped in rare cases.
Route enumeration is capped at 500 paths per project as a safety limit for very dense/looping graphs.
The interactive graph loads vis-network from a CDN inside the webview; if you're fully offline it falls back to a Mermaid-source view automatically.