ScriptFlow is a browser-based tool that analyzes multiple code scripts and automatically generates interactive relationship diagrams showing how they connect.
- Input scripts — Paste code into named tabs or upload source files.
- Detect relationships — The parser scans all scripts to find cross-file dependencies:
import/export/requirestatements- Cross-script function calls
- Event patterns (
emit,on,addEventListener,dispatchEvent, Roblox:Connect/:Fire*) - Shared variable references
- Render a diagram — An interactive node-graph is generated where each script is a card showing its public API (exports, functions, event handlers), connected by labeled arrows.
| Language | Detection | Key Patterns |
|---|---|---|
| JavaScript / TypeScript | .js, .ts, .jsx, .tsx, .mjs, .cjs |
ES modules, CommonJS, arrow functions, DOM events |
| Python | .py, .pyw + heuristics |
def, class, import/from, __all__, decorators |
| Lua / Luau | .lua, .luau + heuristics |
require(), return Module, Roblox :Connect/:Fire* |
The parser uses a plugin architecture — adding a new language requires implementing a single LanguageParser interface and registering it. See src/lib/parsers/ for details.
- Multi-language analysis — Automatically detects the language of each script and applies the appropriate parser.
- Interactive diagram — Drag, zoom, and pan nodes powered by React Flow.
- Auto-layout — Dagre algorithm positions nodes in Top-Down (TD) or Left-Right (LR) orientation.
- Multi-edge rendering — Each relationship (import, call, event, variable) between two scripts gets its own distinct arrow and label via unique handle allocation.
- Edge hover highlighting — Hovering an edge bolds the line and highlights the specific symbols (functions/variables) in both source and target nodes; non-related elements dim. Dragged node positions are preserved during hover.
- Edge legend — Color-coded arrows distinguish imports (blue), function calls (green), events (amber, dashed), and shared variables (purple).
- Save / Load — Export the entire workspace (scripts + diagram) as a single
.scriptflow.jsonfile and restore it later. - File upload — Browse to upload source files directly (
.js,.ts,.jsx,.tsx,.py,.pyw,.mjs,.cjs,.lua,.luau). - Resizable panels — Adjustable split between the code editor and diagram canvas.
| Layer | Technology |
|---|---|
| Framework | React 18 + TypeScript |
| Build tool | Vite |
| Styling | Tailwind CSS + shadcn/ui components |
| Diagramming | @xyflow/react (React Flow) |
| Auto-layout | dagre graph layout algorithm |
| Parsing | Plugin-based regex static analysis (no backend) |
| State | React hooks (useState, useCallback) |
| Testing | Vitest |
- The user adds scripts via tabbed editors or file upload.
- Clicking Generate Diagram runs the parser pipeline:
- The registry (
src/lib/parsers/registry.ts) detects each script's language and selects the appropriate parser plugin. - Each language parser extracts the script's structure (exports, functions, imports, calls, events, variables).
- The orchestrator (
src/lib/codeParser.ts) cross-references all parsed scripts to build relationship edges.
- The registry (
- The layout engine (
src/lib/layoutGraph.ts) feeds nodes and edges into Dagre to compute positions. - React Flow renders the positioned graph with custom
ScriptNodecomponents and styled edges.
Each language parser implements the LanguageParser interface:
interface LanguageParser {
id: string; // Unique identifier
name: string; // Display name
extensions: string[]; // File extensions handled
detect(name: string, code: string): boolean; // Heuristic detection
parse(script: ScriptData): ParsedScript; // Extract structure
}To add a new language, create a parser file in src/lib/parsers/ and register it in registry.ts.
npm install
npm run devNo backend or API keys required — everything runs client-side in the browser.
npm testTests cover parsing for all supported languages (JS, Python, Lua/Luau).
ScriptFlow projects are saved as .scriptflow.json files containing:
{
"version": 1,
"scripts": [{ "id": "...", "name": "main.js", "code": "..." }],
"parseResult": { "nodes": [...], "edges": [...] },
"direction": "TB"
}