| name | interactive-diagram |
| description | Generate interactive, draggable diagrams with REAL-TIME incremental rendering via SSE.
Supports flowcharts, architecture diagrams, mind maps, and sequence diagrams.
Nodes appear one by one as the agent generates them — zero wait time.
Use this skill whenever the user asks to draw, visualize, or create any kind of diagram.
Trigger keywords: 画图, 流程图, 架构图, 思维导图, 时序图, diagram, flowchart, architecture,
mind map, sequence diagram, 画一个, 可视化, visualize, 拓扑图, 关系图, draw, 图解, 示意图.
Also trigger when users describe processes, architectures, or relationships that would benefit
from visual representation, even if they don't explicitly say "draw".
|
Interactive Diagram — Real-Time Incremental Rendering
This skill generates interactive diagrams using a lightweight SSE server and a pre-built HTML renderer.
Instead of generating entire HTML files, the agent sends tiny JSON commands via curl.
Each node and edge appears in the browser in real-time as the agent generates it.
Architecture
Agent sends curl commands (~30-50 tokens each)
→ Python SSE Server (scripts/server.py)
→ Server stores state + broadcasts via SSE
→ template.html renders with AntV X6 + Dagre auto-layout
→ GET /state returns full history (supports page refresh recovery)
Key Features
- Real-time incremental rendering: Nodes/edges appear one by one as agent generates them
- Page refresh recovery: Server stores all commands; refreshing the page replays full state
- Persistent browser edits: Manual edits in the browser are saved as a full graph snapshot
- Dagre auto-layout: Uses the real dagre.js library (CDN) for proper hierarchical layout
- AntV X6 rendering engine: Professional diagram editor powered by X6 v2
- Interactive editing: Users can edit diagrams directly in the browser after generation:
- Drag nodes to reposition
- Double-click to edit node/edge labels
- Right-click context menu (edit, duplicate, delete)
- Drag from ports to create new connections
- Shift+drag for rubber-band multi-select
- Delete/Backspace to remove selected elements
- Ctrl/Cmd+Z undo, Ctrl/Cmd+Shift+Z redo
- Snapline alignment guides
- Left panel to add new nodes by clicking
- Export: PNG, SVG, JSON, Draw.io XML (download or copy to clipboard)
- Smooth zoom: Mouse wheel / trackpad zoom centered on cursor
Quick Start Workflow
⚠️ CRITICAL ORDERING: Start server → Open browser → WAIT for page to load → THEN send commands.
The user MUST see the browser page BEFORE any node/edge commands are sent, otherwise the real-time incremental effect is lost.
Step 1: Start the server AND open browser FIRST
This step MUST be a SEPARATE Bash call that completes BEFORE any diagram commands.
IMPORTANT: ALWAYS use a unique session ID for each diagram. Generate a short, descriptive session name based on the diagram topic (e.g., login-flow, arch-overview, deploy-pipeline). NEVER use the default session (no ?s= param) — it gets overwritten by the next diagram.
curl -s http://127.0.0.1:6100/status 2>/dev/null || python3 ~/.claude/skills/interactive-diagram/scripts/server.py &
sleep 1 && curl -s http://127.0.0.1:6100/status && open 'http://127.0.0.1:6100/?s=my-diagram'
IMPORTANT: Wait for Step 1 to complete (browser opened) before proceeding to Step 2.
Do NOT combine server start + browser open + diagram commands in a single Bash call.
Step 2: Initialize the diagram (SEPARATE Bash call)
Use a shell variable S to avoid repeating the session ID in every curl:
S=my-diagram
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"init","title":"图表标题","direction":"TB"}'
Direction options: TB (top-bottom), LR (left-right), BT (bottom-top), RL (right-left)
Step 3: Add nodes one by one
Send each node as an individual curl command. The user will see nodes appear in real-time:
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"n1","label":"开始","type":"terminal"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"n2","label":"处理数据","type":"process"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"n3","label":"是否成功?","type":"decision"}'
Step 4: Add edges one by one
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"n1","to":"n2"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"n2","to":"n3","label":"验证"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"n3","to":"n4","label":"是","color":"green"}'
Step 5 (optional): Trigger manual layout
Nodes auto-layout as they're added, but you can force a re-layout:
curl -s '127.0.0.1:6100/cmd?s=my-diagram' -d '{"cmd":"layout"}'
Node Types
| type | Appearance | Usage |
|---|
terminal | Green ellipse | Start node |
terminal-end | Red ellipse | End node |
process | Blue-bordered rounded rect | Processing step |
decision | Yellow-bordered diamond | Branch/condition |
service | Purple-bordered rounded rect | Microservice/API |
database | Cyan-bordered rect with thick top bar | Database/storage |
success | Green-bordered rect | Success state |
error | Red-bordered rect | Error/failure state |
container | Dashed background frame with header | Group related nodes |
Nodes support an icon field: {"cmd":"node","id":"s1","label":"API Gateway","type":"service","icon":"🔀"}
Node Options
| Field | Required | Description |
|---|
id | Yes | Node ID |
label | No | Node text |
type | No | One of the node types above; default process |
icon | No | Prefix icon shown before the label, useful for architecture diagrams |
color | No | Primary accent color: border for outlined nodes, fill for filled nodes |
fill | No | Body fill color |
stroke | No | Border color; overrides color for outlined nodes |
textColor / labelColor | No | Label color |
strokeWidth | No | Border width |
dashed / strokeDasharray | No | Dashed border |
width / height | No | Manual node size |
Named colors: blue, green, red, purple, cyan, orange, yellow, black, white, gray/grey; hex and rgb(...) values are also supported.
Containers
Use containers to visually group related nodes. Send the child nodes first, then the container command with a children array so it can auto-size around them:
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"container","id":"frontend","label":"前端","children":["login","dashboard"],"color":"blue"}'
Container fields:
| Field | Required | Description |
|---|
id | Yes | Container ID |
label | No | Header label |
children | No | Node IDs to wrap; container auto-sizes around them |
padding | No | Extra space around children; default 34 |
color | No | Border color: named color or hex |
fill | No | Body fill color; hex/rgb supported |
width / height | No | Manual size when children is omitted |
You can also create a container with {"cmd":"node","type":"container",...} for compatibility with node-based command generation.
Edge Options
| Field | Required | Description |
|---|
from | Yes | Source node ID |
to | Yes | Target node ID |
label | No | Text label on the edge |
color | No | Named, hex, or rgb(...) color |
strokeWidth / width | No | Edge width |
vertices | No | Manual bend points: [{"x":100,"y":120}] |
sourcePort / targetPort | No | Explicit port IDs (pt, pb, pl, pr) |
All Commands
| Command | Description | Example |
|---|
init | Clear and initialize | {"cmd":"init","title":"My Diagram","direction":"TB"} |
node | Add/update a node | {"cmd":"node","id":"n1","label":"Step 1","type":"process"} |
edge | Add an edge | {"cmd":"edge","from":"n1","to":"n2","label":"next"} |
layout | Force re-layout | {"cmd":"layout"} |
clear | Clear all nodes/edges | {"cmd":"clear"} |
title | Change title | {"cmd":"title","text":"New Title"} |
remove | Remove a node | {"cmd":"remove","id":"n1"} |
batch | Add multiple at once | {"cmd":"batch","nodes":[...],"edges":[...]} |
container | Add/update a container frame | {"cmd":"container","id":"g1","label":"Group","children":["n1","n2"]} |
graph | Restore a full saved X6 graph snapshot | Internal persistence command |
export | Trigger browser download | {"cmd":"export","format":"png"} (png/svg/json/drawio) |
Server-Side Export (Save to Disk)
Use the /export endpoint to export diagrams directly to a file on disk via curl. The server coordinates with the browser to generate the file and save it.
curl -s 127.0.0.1:6100/export -d '{"format":"png","path":"/tmp/diagram.png"}'
curl -s 127.0.0.1:6100/export -d '{"format":"png","path":"/tmp/diagram@2x.png","ratio":2}'
curl -s 127.0.0.1:6100/export -d '{"format":"svg","path":"/tmp/diagram.svg"}'
curl -s 127.0.0.1:6100/export -d '{"format":"drawio","path":"/tmp/diagram.drawio"}'
curl -s 127.0.0.1:6100/export -d '{"format":"json","path":"/tmp/diagram.json"}'
curl -s 127.0.0.1:6100/export -d '{"format":"png"}'
curl -s '127.0.0.1:6100/export?s=arch' -d '{"format":"drawio","path":"~/arch.drawio"}'
Supported formats: png, svg, json, drawio
PNG export defaults to a high-DPI ratio so output is sharper on Retina/high-density displays. You can override it with ratio, and also pass padding / backgroundColor for PNG exports.
Note: The browser tab must be open for export to work — the browser generates the image/data and sends it back to the server for saving. The command blocks until the file is saved (timeout: 15s).
CRITICAL RULES for the Agent
- ALWAYS use a unique session ID (
?s=xxx) for every diagram. Generate a short, descriptive name based on the diagram topic (e.g., login-flow, arch-overview). NEVER use the default session (omitting ?s=). All curl commands and browser URLs must include ?s=SESSION_ID. This prevents diagrams from overwriting each other and ensures each diagram survives server restarts.
- BROWSER MUST BE OPEN BEFORE SENDING COMMANDS TO A NEW SESSION. For the first diagram or a new session (
?s=xxx), Step 1 (start server + open browser) MUST be a separate Bash call that completes before Step 2. NEVER combine server start/browser open and diagram commands in a single Bash call. However, if replacing a diagram in an EXISTING session (browser tab already open), just send init directly — no need to re-open the browser.
- Send nodes and edges INDIVIDUALLY — one curl per node, one curl per edge. This creates the real-time incremental effect.
- Keep commands minimal — only include required fields. Don't add unnecessary whitespace in JSON. Use
S=session-name shell variable to avoid repeating session ID in every curl.
- Use descriptive IDs — like
start, login, validate instead of n1, n2, n3.
- Auto-layout handles positioning — do NOT specify
x or y coordinates. Dagre calculates optimal positions.
- Send init first — always start with an
init command to clear previous state and set the title.
- Add all nodes before edges — this produces better layout results. Send all node commands first, then container commands, then all edge commands, then optionally a
layout command.
- Execution order for NEW sessions: Bash 1: start server + open browser → Bash 2: init + nodes + edges. Two separate tool calls, NOT one. For EXISTING sessions (browser already open): just send init + nodes + edges directly in one Bash call.
Token Efficiency
Each curl command costs ~30-50 tokens. A 10-node flowchart uses ~500 tokens total.
This is 90% less than generating a full HTML file (~4000+ tokens).
Server Lifecycle
Starting the server
- Check if already running:
curl -s http://127.0.0.1:6100/status 2>/dev/null
- If not running, start in background:
python3 ~/.claude/skills/interactive-diagram/scripts/server.py &
- The server is very lightweight (~5MB memory), keep it running throughout the session
- Do NOT stop the server between diagrams
Multiple diagrams in one session
Opening the browser
- Always include session ID:
open 'http://127.0.0.1:6100/?s=session_name'
- Only open browser when starting a NEW session, not when adding to an existing one
Server Endpoints
All endpoints support ?s=SESSION_ID query parameter (default: default).
| Endpoint | Method | Description |
|---|
/ | GET | Serve the HTML template |
/?s=NAME | GET | Serve template for a specific session |
/events | GET | SSE event stream |
/state | GET | Return full command history (JSON array) |
/status | GET | Health check with session/client counts |
/sessions | GET | List all sessions with command counts |
/cmd | POST | Send a diagram command |
/export | POST | Export diagram to file (server-side save) |
/save-graph | POST | Persist full browser-edited graph snapshot |
/clear | POST | Clear session state |
Fallback
If the server cannot start (e.g., port blocked, Python unavailable), fall back to generating
a standalone HTML file directly. Use the batch command format as a reference for the data structure,
and generate a complete HTML file with inline Dagre layout, CSS, and JS.
Example: Complete Login Flow
curl -s http://127.0.0.1:6100/status 2>/dev/null || python3 ~/.claude/skills/interactive-diagram/scripts/server.py &
sleep 1 && open 'http://127.0.0.1:6100/?s=login-flow'
S=login-flow
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"init","title":"用户登录流程","direction":"TB"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"start","label":"开始","type":"terminal"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"input","label":"输入用户名密码","type":"process"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"validate","label":"验证信息","type":"process"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"check","label":"是否正确?","type":"decision"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"ok","label":"登录成功","type":"success"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"fail","label":"显示错误","type":"error"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"retry","label":"重试次数超限?","type":"decision"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"lock","label":"账户锁定","type":"error"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"node","id":"end","label":"结束","type":"terminal-end"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"start","to":"input"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"input","to":"validate"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"validate","to":"check"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"check","to":"ok","label":"是","color":"green"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"check","to":"fail","label":"否","color":"red"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"fail","to":"retry"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"retry","to":"input","label":"否"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"retry","to":"lock","label":"是","color":"red"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"ok","to":"end"}'
curl -s "127.0.0.1:6100/cmd?s=$S" -d '{"cmd":"edge","from":"lock","to":"end"}'