FlowForge
git clone https://github.com/wentong2022-arch/flowforge-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/wentong2022-arch/flowforge-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/FlowForge" ~/.claude/skills/wentong2022-arch-flowforge-skill-flowforge && rm -rf "$T"
skills/FlowForge/SKILL.mdFlowForge — Draw.io Diagram Skill
Generate professional diagrams as draw.io XML files. Supports flowcharts, architecture diagrams, comparisons, mind maps, timelines, and more.
Usage
/FlowForge "OAuth 2.0 authorization code flow" /FlowForge path/to/design-doc.md /FlowForge "CI/CD pipeline" --type loop /FlowForge "Monolith vs Microservices" --type compare --theme morandi /FlowForge "System Architecture" --lang en
Workflow
Step 1: Understand Requirements
If given a document:
- Read the full document
- Identify 1–3 places that benefit from a diagram
- For each, list:
- Insert position (after which section)
- Diagram topic (one sentence)
- Recommended diagram type (see Diagram Type Reference below)
- Wait for user confirmation
If given a concept directly:
- Confirm the core message to convey
- Choose diagram type
- Proceed to Step 2
Step 2: Confirm Theme
If the user hasn't specified
--theme, state:
Default theme: tech-blue (科技蓝灰). Other options: morandi, mint, terracotta, indigo. Want a different one?
Proceed after user confirms. For full theme definitions, see themes.md.
Step 3: Design Sketch (ASCII)
Produce an ASCII sketch showing:
- All nodes with labels
- Arrow directions and labels
- Grouping/regions
- Color role assignments (e.g.,
,[primary]
,[accent]
)[neutral] - Approximate dimensions and layout direction
Example sketch:
Direction: left-to-right | Nodes: 4 | Type: flow [primary] Code Commit → [process] Build → [process] Test → [accent] Deploy ↓ (fail) [error] Alert
STOP — Wait for user confirmation or revision before proceeding to XML generation.
Step 4: Generate draw.io XML
- Select layout algorithm for the chosen type (see Layout System below)
- Compute all coordinates using the formulas and constants
- Apply theme colors from themes.md
- Use element templates from xml-reference.md
- Reference complete examples in examples.md for pattern matching
- Fix any issues found
Step 5: Save & Deliver
Save the
.drawio file. Default path:
./diagrams/{diagram-name}.drawio
Or user-specified path. After saving, report:
- File path
- How to open: draw.io desktop app or https://app.diagrams.net
Iteration
If the user wants changes after viewing:
- Read the current
file.drawio - Modify the XML per feedback
- Save as
(preserve previous version){name}_v2.drawio
Layout System
Global Constants
CANVAS_PAD = 40 # padding from content to canvas edge NODE_W = 160 # default node width NODE_H = 50 # single-label node height NODE_H_RICH = 90 # node with title + bullet list TITLE_H = 28 # diagram title height GAP_H = 60 # horizontal gap between nodes GAP_V = 50 # vertical gap between nodes DIAMOND_W = 120 # decision diamond width DIAMOND_H = 80 # decision diamond height GROUP_PAD = 20 # padding inside dashed group boxes FONT_TITLE = 18 # diagram title font size FONT_NODE = 13 # node title font size FONT_BODY = 10 # node body/list font size FONT_ARROW = 9 # arrow label font size STROKE_NODE = 1.2 # node border stroke width STROKE_ARROW = 0.8 # arrow stroke width ARC_SIZE = 10 # rounded rect arc size ARROW_SIZE = 5 # arrowhead size
Adjust constants when needed:
- If nodes > 6 in a flow, reduce
to 140 orNODE_W
to 40GAP_H - If labels are long, increase
up to 200NODE_W - Rich nodes (title + list): use
instead ofNODE_H_RICHNODE_H
Layout Algorithms by Type
flow
— Linear Flow (left-to-right)
flowx[i] = CANVAS_PAD + i × (NODE_W + GAP_H) y = CANVAS_PAD + TITLE_H + GAP_V Canvas width = CANVAS_PAD × 2 + n × NODE_W + (n-1) × GAP_H Canvas height = CANVAS_PAD × 2 + TITLE_H + GAP_V + NODE_H
If n > 5, use snake layout — wrap to next row flowing right-to-left:
Row 0 (L→R): nodes 0..4 Row 1 (R→L): nodes 5..9 Row 2 (L→R): nodes 10..14 y[row] = CANVAS_PAD + TITLE_H + GAP_V + row × (NODE_H + GAP_V) x[i] in even row = CANVAS_PAD + col × (NODE_W + GAP_H) x[i] in odd row = CANVAS_PAD + (4-col) × (NODE_W + GAP_H)
flow-vertical
— Linear Flow (top-to-bottom)
flow-verticalx = CANVAS_PAD + (Canvas width / 2) - NODE_W / 2 y[i] = CANVAS_PAD + TITLE_H + GAP_V + i × (NODE_H + GAP_V)
compare
— Left-Right Comparison
compareVS_W = 50 # width of "VS" badge Left column x = CANVAS_PAD Right column x = CANVAS_PAD + NODE_W + GAP_H + VS_W + GAP_H VS badge x = CANVAS_PAD + NODE_W + GAP_H Header y = CANVAS_PAD + TITLE_H + GAP_V Row y[j] = Header y + NODE_H + GAP_V/2 + j × (NODE_H + GAP_V/2)
Each side has a header node (title) and content rows below.
layers
— Layer Stack
layersLAYER_W = 400 x = CANVAS_PAD + (canvas center offset) y[i] = CANVAS_PAD + TITLE_H + GAP_V + i × (NODE_H_RICH + GAP_V/3) Canvas width = CANVAS_PAD × 2 + LAYER_W Canvas height = CANVAS_PAD × 2 + TITLE_H + GAP_V + n × NODE_H_RICH + (n-1) × GAP_V/3
Layers span full width. Top layer = highest abstraction.
loop
— Cycle / Feedback Loop
loopArrange N nodes in a rectangular path (clockwise):
For 4 nodes (most common):
Positions: [0] top-left: (CANVAS_PAD, CANVAS_PAD + TITLE_H + GAP_V) [1] top-right: (CANVAS_PAD + NODE_W + GAP_H × 2, same y) [2] bottom-right: (same x as [1], y + NODE_H + GAP_V) [3] bottom-left: (same x as [0], same y as [2]) Arrows: 0→1 (top), 1→2 (right), 2→3 (bottom, R→L), 3→0 (left, bottom→top)
For N nodes: distribute evenly across 4 sides of a rectangle.
tree
— Tree / Hierarchy
treeLevel spacing = GAP_V × 1.5 Sibling spacing = NODE_W + GAP_H / 2 Root: centered at top Children: evenly distributed below parent, centered under parent Subtree width = max(sum of children subtree widths, NODE_W) Parent x = leftmost child x + (rightmost child x + NODE_W - leftmost child x) / 2 - NODE_W / 2
hub
— Hub and Spoke (Center Radiate)
hubCenter node at canvas center. Spokes at equal angles.
Lookup table (use these positions instead of computing cosines):
| N spokes | Positions relative to center (dx, dy) |
|---|---|
| 3 | (0, -R), (R×0.87, R×0.5), (-R×0.87, R×0.5) |
| 4 | (0, -R), (R, 0), (0, R), (-R, 0) |
| 5 | (0, -R), (R×0.95, -R×0.31), (R×0.59, R×0.81), (-R×0.59, R×0.81), (-R×0.95, -R×0.31) |
| 6 | (0, -R), (R×0.87, -R×0.5), (R×0.87, R×0.5), (0, R), (-R×0.87, R×0.5), (-R×0.87, -R×0.5) |
Where
R = 180 (radius). Spoke node position:
x[i] = cx + dx[i] - NODE_W / 2 y[i] = cy + dy[i] - NODE_H / 2
columns
— Parallel Columns
columnsColumn x[i] = CANVAS_PAD + i × (NODE_W + GAP_H) Header y = CANVAS_PAD + TITLE_H + GAP_V Item y[j] = Header y + NODE_H + GAP_V/2 + j × (NODE_H + GAP_V/3)
Each column has a header node (colored) and vertically stacked item nodes below.
matrix
— Comparison Matrix
matrixCELL_W = 140 CELL_H = 45 HEADER_H = 40 Col header x[c] = CANVAS_PAD + HEADER_W + GAP_H/3 + c × (CELL_W + GAP_H/3) Row header y[r] = CANVAS_PAD + TITLE_H + HEADER_H + GAP_V/3 + r × (CELL_H + GAP_V/3) Cell (r,c): x = Col header x[c], y = Row header y[r]
funnel
— Funnel
funnelMAX_W = 360 MIN_W = 120 w[i] = MAX_W - i × ((MAX_W - MIN_W) / (n - 1)) x[i] = CANVAS_PAD + (MAX_W - w[i]) / 2 y[i] = CANVAS_PAD + TITLE_H + GAP_V + i × (NODE_H + GAP_V / 3)
Centered, decreasing-width bands stacked vertically.
timeline
— Timeline
timelineLINE_Y = canvas vertical center Node spacing = NODE_W + GAP_H Event nodes alternate above and below the timeline: Above: y = LINE_Y - NODE_H - GAP_V/2 Below: y = LINE_Y + GAP_V/2 x[i] = CANVAS_PAD + i × (NODE_W + GAP_H) Draw a horizontal line at LINE_Y spanning full width. Draw vertical ticks from line to each node.
sequence
— Sequence Diagram
sequenceLIFELINE_GAP = 180 MESSAGE_GAP = 50 PARTICIPANT_Y = CANVAS_PAD + TITLE_H + GAP_V PARTICIPANT_W = 140 PARTICIPANT_H = 40 Participant x[i] = CANVAS_PAD + i × LIFELINE_GAP Lifeline: vertical dashed line from bottom of participant box downward Message y[j] = PARTICIPANT_Y + PARTICIPANT_H + GAP_V + j × MESSAGE_GAP Messages: horizontal arrows between lifelines
Diagram Type Reference
Core Types
| Type | Code | Best For | Example |
|---|---|---|---|
| Linear Flow | | Sequential steps A→B→C | API call flow, data pipeline |
| Vertical Flow | | Top-down processes | Decision process, approval chain |
| Comparison | | A vs B side by side | Traditional vs AI approach |
| Layer Stack | | Tech stack, tiers | System architecture layers |
| Cycle | | Iterative processes | ML training loop, CI/CD |
| Tree | | Hierarchies, taxonomies | Org chart, decision tree |
| Hub & Spoke | | Core concept + branches | Product feature map |
Extended Types
| Type | Code | Best For |
|---|---|---|
| Parallel Columns | | 3+ parallel concepts |
| Matrix | | Multi-dimension comparison |
| Funnel | | Filtering, conversion |
| Timeline | | Version evolution, history |
| Sequence | | Component interactions |
Selection Guide
| Content Pattern | Recommended Type |
|---|---|
| Sequential steps | or |
| Two things compared | |
| 3+ parallel concepts | or |
| Layered system | |
| Iterative/cyclical process | |
| One core, many branches | or |
| Components communicating | |
| Change over time | |
| Multi-criteria evaluation | |
| Progressive filtering | |
Quality Checks
Before delivering the
file, verify ALL of the following. Fix any failures before saving..drawio
Layout Checks
- No overlapping nodes — For every pair of nodes, their bounding boxes must not intersect. Verify:
OR|x1 - x2| >= width
.|y1 - y2| >= height - Canvas large enough — No node extends beyond:
andmax(x + w) + CANVAS_PAD <= CANVAS_W
.max(y + h) + CANVAS_PAD <= CANVAS_H - Consistent spacing — Gaps between adjacent nodes should match
/GAP_H
(±10px tolerance).GAP_V - Alignment — Nodes in the same row share the same
. Nodes in the same column share the samey
.x
Text Checks
- Text fits in node — Estimate: Chinese characters ≈ 14px each at font 13; English characters ≈ 8px each. If text width > node width - 20px padding, either widen the node, reduce font, or add
line breaks.<br> - Minimum readability — No font size below 9px. No node smaller than 80×30.
XML Checks
- All arrow targets exist — Every
andsource="X"
must match antarget="Y"
/id="X"
defined as a vertex.id="Y" - Unique IDs — Every
attribute is unique across the entire XML.id - Correct parent — All content elements have
unless intentionally grouped.parent="1" - Valid XML — Well-formed, all attributes quoted, HTML entities escaped (
<>&
)."
Style Checks
- Theme consistency — All fill/stroke/font colors come from the selected theme. No ad-hoc hex values.
- Arrow routing — Arrows use orthogonal routing only (horizontal + vertical). No diagonal arrows. Return arrows route around the outside, never crossing through unrelated nodes.
Color Usage Principles
This is the most important section for visual quality.
The 4+6 Rule
Each theme has 4 base colors and 6 extended colors:
- Base 4:
,primary
,process
,accentneutral - Extended 6:
,success
,warning
,error
,secondary
,storagegroup
Blue (primary + process) should always be the dominant color family, but the amount of non-blue accents should scale with diagram size.
Color Budget by Diagram Size
| Node Count | Target Colors | Guideline |
|---|---|---|
| 3-5 nodes | 2-3 colors | Blue dominates. At most 1 accent node. |
| 6-8 nodes | 3-4 colors | Blue ~60%. Add 1-2 non-blue at semantic turning points. |
| 9+ nodes | 4-5 colors | Blue ~50%. Distribute 2-3 non-blue for visual rhythm. |
6+ colors almost always looks bad regardless of diagram size.
Color Assignment Strategy
-
Blue dominates —
andprimary
should cover the largest visual area and the biggest nodes.process -
Accent is a scalpel, not a paintbrush — Use
for at most 1-2 key highlights. Never on the largest node.accent -
Scale with length — A 4-node flow with 2 colors looks clean. A 9-node flow with only 2 colors is a monotonous wall. Add non-blue colors at natural semantic boundaries to create rhythm.
-
3-consecutive guideline — Avoid more than 3 adjacent nodes in the same color. If you spot 4+ consecutive blue nodes, promote the most semantically distinctive one to a non-blue color.
-
Distribute spatially — Non-blue nodes should be spread across the diagram (top/middle/bottom), not clustered in one region.
Semantic Color Heuristics
When deciding which nodes get non-blue colors, use this table:
| Node Type | Recommended Color |
|---|---|
| User input / starting point | |
| Standard processing step | |
| Decision / branching point | or |
| Domain-specific / translation step | |
| Key transformation / highlight | |
| Data source / external system | |
| Error path / fallback | or |
| Successful output / endpoint | or |
| Database / storage | |
Examples
Bad (rainbow — every node a different color):
[neutral] 数据源 → [process] 采集 → [warning] 检查 → [success] 清洗 → [error] 告警 → [storage] 入库
Bad (wall of blue — 9 nodes all the same):
[primary] 提问 → [process] 校验 → [process] 评估 → [process] 翻译 → [process] 执行 → [process] 解读 → [process] 可视化 → [process] 标注 → [primary] 返回
Good (short flow, 2-3 colors):
[neutral] 数据源 → [process] 采集 → [process] 检查 → [process] 清洗 → [primary] 入库 ↓ (异常) [accent] 告警处理
Good (long flow, 4-5 colors with rhythm):
[primary] 提问 → [process] 校验 → [warning] 评估 → [secondary] 翻译 → [process] 执行 → [process] 解读 → [accent] 可视化 → [process] 标注 → [success] 返回
Design Principles
- Narrative titles — Use "How OAuth 2.0 Authorizes a User" not "OAuth 2.0 Diagram".
- Bilingual labels — Use the user's language. Technical abbreviations (API, LLM, CI/CD) stay in English regardless.
- Orthogonal arrows only — All arrows run horizontally or vertically, no diagonals. Always include
in every arrow's style attribute.edgeStyle=orthogonalEdgeStyle;
Gotchas — Common Failure Points
These are the most common mistakes when generating draw.io XML. Check for these first when debugging.
-
Rich node text overflow — The
inside a rich node uses a separate text cell. If you put the title in the<b>Title</b>
attribute of the background rect AND in a text cell, the title renders twice. Usevalue
on the background rect.value="" -
Arrow ignores exit/entry points — If you omit
from the arrow style, draw.io auto-routes, which often looks wrong. Always specify explicit exit/entry points.exitX/exitY/entryX/entryY -
HTML entities in value attributes —
attributes use HTML, sovalue
must be<
,<
must be>
,>
must be&
. Missing escapes break the entire XML. The most common miss:&
in bulleted lists — use•
when inside an attribute.&bull; -
Dashed group box covers its children — If a dashed group box is defined AFTER its child nodes in the XML, it renders on top and hides them. Always define group boxes BEFORE their child elements.
-
Canvas too small —
/pageWidth
that are too small cause nodes to be cut off in the exported image. Always compute from layout formulas:pageHeight
.max(x + w) + CANVAS_PAD -
Forgetting
— Every content element must haveparent="1"
. Missing this silently breaks the node.parent="1" -
Diamond text overflow — Diamond/rhombus shapes have less usable area than rectangles. Keep labels to 2-3 short words. Use font size 11 instead of 13.
-
Snake layout wrong arrow direction — In snake layouts (flow with >5 nodes), the wrap-around arrow must exit from the bottom of the last node in row N and enter the top of the first node in row N+1, not go sideways.
-
Cycle arrow goes through center — In
diagrams, the return arrow (last→first) must route along the outside of the rectangle, not diagonally through the center.loop -
Coordinate calculation off-by-one — When computing
items: there aren
nodes butn
gaps. Canvas width =n-1
, notPAD×2 + n×NODE_W + (n-1)×GAP_H
.n×GAP_H -
Diagonal arrows on branching/merging — When a centered node branches to two side-by-side targets, exit/entry points are not aligned vertically. Without
in the style, draw.io renders these as diagonal lines. Always include it in every arrow.edgeStyle=orthogonalEdgeStyle;
Initial Setup
On first invocation, check if
config.json exists in the skill directory. If not, ask the user:
- Default theme — Which color theme to use by default? (tech-blue / morandi / mint / terracotta / indigo)
- Output directory — Where to save
files? (default:.drawio
)./diagrams/ - Language — Primary language for labels? (zh / en / auto-detect)
Save responses to
config.json:
{ "defaultTheme": "tech-blue", "outputDir": "./diagrams", "language": "auto" }
On subsequent invocations, read
config.json and apply defaults. User can override per-invocation with --theme, --lang flags.
Supporting Files
The skill directory contains these files. Read them when needed — don't load everything upfront.
| File | When to read |
|---|---|
| themes.md | When applying colors — has all 5 themes with 10 semantic colors + 7 text colors each |
| xml-reference.md | When writing XML — canvas boilerplate, 8 element templates, arrow direction table |
| examples.md | When generating a diagram — 3 complete XML examples with coordinate calculations |
|
config.json | On every invocation — user preferences (created on first run, see Initial Setup) |
Example .drawio
files (in examples/
)
.drawioexamples/These are real, working
.drawio files you can read as reference when generating similar diagram types:
— Linear flow, 4 nodes, tech-blue themeexamples/flow-cicd.drawio
— Comparison, 2 columns × 3 rows, morandi themeexamples/compare-monolith-vs-micro.drawio
— Cycle, 4 nodes clockwise, mint themeexamples/loop-ml-training.drawio