diagram-image (based on Fireworks Tech Graph)
Generate production-quality SVG technical diagrams exported as PNG via cairosvg (recommended), rsvg-convert, or puppeteer.
Helper Scripts (Recommended)
Four helper scripts in scripts/ directory provide stable SVG generation and validation:
1. generate-diagram.sh - Validate SVG + export PNG
./scripts/generate-diagram.sh -t architecture -s 1 -o ./output/arch.svg
- Validates an existing SVG file
- Exports PNG after validation
- Example:
./scripts/generate-diagram.sh -t architecture -s 1 -o ./output/arch.svg
2. generate-from-template.py - Create starter SVG from template
python3 ./scripts/generate-from-template.py architecture ./output/arch.svg '{"title":"My Diagram","nodes":[],"arrows":[]}'
- Loads a built-in SVG template
- Renders nodes, arrows, and legend entries from JSON input
- Escapes text content to keep output XML-valid
3. validate-svg.sh - Validate SVG syntax
./scripts/validate-svg.sh <svg-file>
- Checks XML syntax
- Verifies tag balance
- Validates marker references
- Checks attribute completeness
- Validates path data
4. test-all-styles.sh - Batch test all styles
./scripts/test-all-styles.sh
- Tests multiple diagram sizes
- Validates all generated SVGs
- Generates test report
When to use scripts:
- Use scripts when generating complex SVGs to avoid syntax errors
- Scripts provide automatic validation and error reporting
- Recommended for production diagrams
When to generate SVG directly:
- Simple diagrams with few elements
- Quick prototypes
- When you need full control over SVG structure
Workflow (Always Follow This Order)
- Classify the diagram type (see Diagram Types below)
- Extract structure — identify layers, nodes, edges, flows, and semantic groups from user description
- Plan layout — apply the layout rules for the diagram type
- Load style reference — always load
references/style-1-flat-icon.md unless user specifies another; load the matching references/style-N.md for exact color tokens and SVG patterns
- Map nodes to shapes — use Shape Vocabulary below
- Check icon needs — load
references/icons.md for known products
- Write SVG with adaptive strategy (see SVG Generation Strategy below)
- Validate: Run
python3 -c "import xml.etree.ElementTree as ET; ET.parse('file.svg')" to check XML syntax
- Export PNG: Use
cairosvg (recommended). See SVG → PNG Conversion section below for full method comparison
- Report the generated file paths
- (Optional) Visual self-review — if your runtime can read images, load the exported PNG back and inspect it. Syntactic validity does not guarantee visual correctness: arrows may cross through component interiors, labels may collide with lifelines or other labels, boxes may overlap, alt-frame text may sit on top of a message, or a legend may cover content. If you see any of these, revise the SVG and re-export; repeat until the rendered image is clean. Common fixes:
- Route arrows through gaps between boxes, not through box interiors
- Move arrow labels 6-8px away from the arrow line (offset-first); add background rects only when offset is insufficient
- Widen inter-row/inter-column gutters so same-layer arrows have clear corridors
- Collapse repeated cross-layer arrows into a single "delegates down" rail outside the content area
- Move legend/notes out of any region where arrows or labels land
- Increase viewBox height/width rather than packing elements tighter
- If a filtered element (drop-shadow, blur) is missing one side of its border, move it ≥30px away from that viewBox edge, or remove the filter and rely on color/contrast for visual separation
Skip this step silently if image reading is unavailable — do not guess.
Diagram Types & Layout Rules
Architecture Diagram
Nodes = services/components. Group into horizontal layers (top→bottom or left→right).
- Typical layers: Client → Gateway/LB → Services → Data/Storage
- Use
<rect> dashed containers to group related services in the same layer
- Arrow direction follows data/request flow
- ViewBox:
0 0 960 600 standard, 0 0 960 800 for tall stacks
Data Flow Diagram
Emphasizes what data moves where. Focus on data transformation.
- Label every arrow with the data type (e.g., "embeddings", "query", "context")
- Use wider arrows (
stroke-width: 2.5) for primary data paths
- Dashed arrows for control/trigger flows
- Color arrows by data category (not just Agent/RAG — use semantics)
Flowchart / Process Flow
Sequential decision/process steps.
- Top-to-bottom preferred; left-to-right for wide flows
- Diamond shapes for decisions, rounded rects for processes, parallelograms for I/O
- Keep node labels short (≤3 words); put detail in sub-labels
- Align nodes on a grid: x positions snap to 120px intervals, y to 80px
Agent Architecture Diagram
Shows how an AI agent reasons, uses tools, and manages memory.
Key conceptual layers to always consider:
- Input layer: User, query, trigger
- Agent core: LLM, reasoning loop, planner
- Memory layer: Short-term (context window), Long-term (vector/graph DB), Episodic
- Tool layer: Tool calls, APIs, search, code execution
- Output layer: Response, action, side-effects
Use cyclic arrows (loop arcs) to show iterative reasoning. Separate memory types visually.
Memory Architecture Diagram (Mem0, MemGPT-style)
Specialized agent diagram focused on memory operations.
- Show memory write path and read path separately (different arrow colors)
- Memory tiers: Working Memory → Short-term → Long-term → External Store
- Label memory operations:
store(), retrieve(), forget(), consolidate()
- Use stacked rects or layered cylinders for storage tiers
Sequence Diagram
Time-ordered message exchanges between participants.
- Participants as vertical lifelines (top labels + vertical dashed lines)
- Messages as horizontal arrows between lifelines, top-to-bottom time order
- Activation boxes (thin filled rects on lifeline) show active processing
- Group with
<rect> loop/alt frames with label in top-left corner
- ViewBox height = 80 + (num_messages × 50)
Comparison / Feature Matrix
Side-by-side comparison of approaches, systems, or components.
- Column headers = systems, row headers = attributes
- Row height: 40px; column width: min 120px; header row height: 50px
- Checked cell: tinted background (e.g.
#dcfce7) + ✓ checkmark; unsupported: #f9fafb fill
- Alternating row fills (
#f9fafb / #ffffff) for readability
- Max readable columns: 5; beyond that, split into two diagrams
Timeline / Gantt
Horizontal time axis showing durations, phases, and milestones.
- X-axis = time (weeks/months/quarters); Y-axis = items/tasks/phases
- Bars: rounded rects, colored by category, labeled inside or beside
- Milestone markers: diamond or filled circle at specific x position with label above
- ViewBox:
0 0 960 400 typical; wider for many time periods: 0 0 1200 400
Mind Map / Concept Map
Radial layout from central concept.
- Central node at
cx=480, cy=280
- First-level branches: evenly distributed around center (360/N degrees)
- Second-level branches: branch off first-level at 30-45° offset
- Use curved
<path> with cubic bezier for branches, not straight lines
Class Diagram (UML)
Static structure showing classes, attributes, methods, and relationships.
- Class box: 3-compartment rect (name / attributes / methods), min width 160px
- Top compartment: class name, bold, centered (abstract = italic)
- Middle: attributes with visibility (
+ public, - private, # protected)
- Bottom: method signatures, same visibility notation
- Relationships:
- Inheritance (extends): solid line + hollow triangle arrowhead, child → parent
- Implementation (interface): dashed line + hollow triangle, class → interface
- Association: solid line + open arrowhead, label with multiplicity (1, 0.., 1..)
- Aggregation: solid line + hollow diamond on container side
- Composition: solid line + filled diamond on container side
- Dependency: dashed line + open arrowhead
- Interface:
<<interface>> stereotype above name, or circle/lollipop notation
- Enum: compartment rect with
<<enumeration>> stereotype, values in bottom
- Layout: parent classes top, children below; interfaces to the left/right of implementors
- ViewBox:
0 0 960 600 standard; 0 0 960 800 for deep hierarchies
Use Case Diagram (UML)
System functionality from user perspective.
- Actor: stick figure (circle head + body line) placed outside system boundary
- Label below figure, 13-14px
- Primary actors on left, secondary/supporting on right
- Use case: ellipse with label centered inside, min 140×60px
- Keep names verb phrases: "Create Order", "Process Payment"
- System boundary: large rect with dashed border + system name in top-left
- Relationships:
- Include: dashed arrow
<<include>> from base to included use case
- Extend: dashed arrow
<<extend>> from extension to base use case
- Generalization: solid line + hollow triangle (specialized → general)
- Layout: system boundary centered, actors outside, use cases inside
- ViewBox:
0 0 960 600 standard
State Machine Diagram (UML)
Lifecycle states and transitions of an entity.
- State: rounded rect with state name, min 120×50px
- Internal activities: small text
entry/ action, exit/ action, do/ activity
- Initial state: filled black circle (r=8), one outgoing arrow
- Final state: filled circle (r=8) inside hollow circle (r=12)
- Choice: small hollow diamond, guard labels on outgoing arrows
[condition]
- Transition: arrow with optional label
event [guard] / action
- Guard conditions in square brackets
- Actions after
/
- Composite/nested state: larger rect containing sub-states, with name tab
- Fork/join: thick horizontal or vertical black bar (synchronization)
- Layout: initial state top-left, final state bottom-right, flow top-to-bottom
- ViewBox:
0 0 960 600 standard
ER Diagram (Entity-Relationship)
Database schema and data relationships.
- Entity: rect with entity name in header (bold), attributes below
- Primary key attribute: underlined
- Foreign key: italic or marked with (FK)
- Min width: 160px; attribute font-size: 12px
- Relationship: diamond shape on connecting line
- Label inside diamond: "has", "belongs to", "enrolls in"
- Cardinality labels near entity:
1, N, 0..1, 0..*, 1..*
- Weak entity: double-bordered rect with double diamond relationship
- Associative entity: diamond + rect hybrid (rect with diamond inside)
- Line style: solid for identifying relationships, dashed for non-identifying
- Layout: entities in 2-3 rows, relationships between related entities
- ViewBox:
0 0 960 600 standard; wider 0 0 1200 600 for many entities
Network Topology
Physical or logical network infrastructure.
- Devices: icon-like rects or rounded rects
- Router: circle with cross arrows
- Switch: rect with arrow grid
- Server: stacked rect (rack icon)
- Firewall: brick-pattern rect or shield shape
- Load Balancer: horizontal split rect with arrows
- Cloud: cloud path (overlapping arcs)
- Connections: lines between device centers
- Ethernet/wired: solid line, label bandwidth
- Wireless: dashed line with WiFi symbol
- VPN: dashed line with lock icon
- Subnets/Zones: dashed rect containers with zone label (DMZ, Internal, External)
- Labels: device hostname + IP below, 12-13px
- Layout: tiered top-to-bottom (Internet → Edge → Core → Access → Endpoints)
- ViewBox:
0 0 960 600 standard
UML Coverage Map
Full mapping of UML 14 diagram types to supported diagram types:
| UML Diagram |
Supported As |
Notes |
| Class |
Class Diagram |
Full UML notation |
| Component |
Architecture Diagram |
Use colored fills per component type |
| Deployment |
Architecture Diagram |
Add node/instance labels |
| Package |
Architecture Diagram |
Use dashed grouping containers |
| Composite Structure |
Architecture Diagram |
Nested rects within components |
| Object |
Class Diagram |
Instance boxes with underlined name |
| Use Case |
Use Case Diagram |
Full actor/ellipse/relationship |
| Activity |
Flowchart / Process Flow |
Add fork/join bars |
| State Machine |
State Machine Diagram |
Full UML notation |
| Sequence |
Sequence Diagram |
Add alt/opt/loop frames |
| Communication |
— |
Approximate with Sequence (swap axes) |
| Timing |
Timeline |
Adapt time axis |
| Interaction Overview |
Flowchart |
Combine activity + sequence fragments |
| ER Diagram |
ER Diagram |
Chen/Crow's foot notation |
Shape Vocabulary
Map semantic concepts to consistent shapes across all diagram types:
| Concept |
Shape |
Notes |
| User / Human |
Circle + body path |
Stick figure or avatar |
| LLM / Model |
Rounded rect with brain/spark icon or gradient fill |
Use accent color |
| Agent / Orchestrator |
Hexagon or rounded rect with double border |
Signals "active controller" |
| Memory (short-term) |
Rounded rect, dashed border |
Ephemeral = dashed |
| Memory (long-term) |
Cylinder (database shape) |
Persistent = solid cylinder |
| Vector Store |
Cylinder with grid lines inside |
Add 3 horizontal lines |
| Graph DB |
Circle cluster (3 overlapping circles) |
|
| Tool / Function |
Gear-like rect or rect with wrench icon |
|
| API / Gateway |
Hexagon (single border) |
|
| Queue / Stream |
Horizontal tube (pipe shape) |
|
| File / Document |
Folded-corner rect |
|
| Browser / UI |
Rect with 3-dot titlebar |
|
| Decision |
Diamond |
Flowcharts only |
| Process / Step |
Rounded rect |
Standard box |
| External Service |
Rect with cloud icon or dashed border |
|
| Data / Artifact |
Parallelogram |
I/O in flowcharts |
Arrow Semantics
Always assign arrow meaning, not just color:
| Flow Type |
Color |
Stroke |
Dash |
Meaning |
| Primary data flow |
blue #2563eb |
2px solid |
none |
Main request/response path |
| Control / trigger |
orange #ea580c |
1.5px solid |
none |
One system triggering another |
| Memory read |
green #059669 |
1.5px solid |
none |
Retrieval from store |
| Memory write |
green #059669 |
1.5px |
5,3 |
Write/store operation |
| Async / event |
gray #6b7280 |
1.5px |
4,2 |
Non-blocking, event-driven |
| Embedding / transform |
purple #7c3aed |
1px solid |
none |
Data transformation |
| Feedback / loop |
purple #7c3aed |
1.5px curved |
none |
Iterative reasoning loop |
Always include a legend when 2+ arrow types are used.
Layout Rules & Validation
Spacing:
- Same-layer nodes: 80px horizontal, 120px vertical between layers
- Canvas margins: 40px minimum, 60px between node edges
- Snap to 8px grid: horizontal 120px intervals, vertical 120px intervals
Arrow Labels (CRITICAL):
- Offset-first (default): place label 6-8px above horizontal arrows, or 8px left/right of vertical arrows — do not overlap the arrow line
- Background fallback: add
<rect fill="canvas_bg" opacity="0.95"/> only when the offset label still crosses another visual element (another arrow, a node edge, etc.)
- Place mid-arrow, ≤3 words, stagger by 15-20px when multiple arrows converge
- Maintain 10px safety distance from nodes
Arrow Routing:
- Prefer orthogonal (L-shaped) paths to minimize crossings
- Anchor arrows on component edges, not geometric centers
- Route around dense node clusters, use different y-offsets for parallel arrows
- Jump-over arcs (5px radius) for unavoidable crossings
Post-Generation Arrow Optimization:
When a user asks to "优化箭头" / "fix arrow routing" / "optimize the diagram" on an already-generated diagram, preserve all nodes, containers, styles, and layout — only modify the arrows entries in the JSON data, then re-render with generate-from-template.py.
Available arrow override fields (in recommended order of use):
| Field |
Type |
When to Use |
source_port / target_port |
"left" / "right" / "top" / "bottom" |
Arrow exits/enters from the wrong edge |
corridor_x |
[x, ...] |
Hint vertical segments toward this x lane (soft preference) |
corridor_y |
[y, ...] |
Hint horizontal segments toward this y lane (soft preference) |
route_points |
[[x1,y1], [x2,y2], ...] |
Force exact waypoints (bypasses auto-routing); keep segments orthogonal |
routing_padding |
number (default: 24) |
(Advanced) Adjust obstacle clearance for this arrow |
port_clearance |
number |
(Advanced) Adjust first-segment offset from node edge |
label_style |
"badge" / "offset" |
Choose "offset" when badge backgrounds create visual clutter; keep "badge" (default) for legacy/high-contrast labels |
For JSON/template rendering, the default remains "badge" for backward compatibility. Set "label_style": "offset" on individual arrows when you want offset-first labels without background rects.
Optimization steps:
- Read the existing SVG — identify which arrows overlap, cross nodes, or look misaligned
- Find those arrows in the JSON data by
source / target pair
- Add
source_port / target_port if the exit/entry direction is wrong; add corridor_x / corridor_y to space parallel arrows apart; use route_points only when hints alone cannot resolve the path
- Re-run
generate-from-template.py with the updated JSON and validate with validate-svg.sh
Example — spacing two overlapping arrows into separate corridors:
{ "source": "nodeA", "target": "nodeB", "corridor_y": [280] }
{ "source": "nodeC", "target": "nodeD", "corridor_y": [320] }
Line Overlap Prevention (CRITICAL - most common bug on Codex):
When two arrows must cross each other, ALWAYS use jump-over arcs to prevent visual overlap:
- Crossing horizontal arrows: add a small semicircle arc (radius 5px, stroke same color as arrow, fill none) that "jumps over" the other line
- SVG pattern for jump-over: use a white/matching-background arc on the lower layer, then draw the upper arc on top
- Multiple crossings: stagger arc radii (5px, 7px, 9px) so arcs don't overlap each other
- Never let two arrows' straight-line segments cross without a jump-over arc
Validation Checklist (run before finalizing):
- Arrow-Component Collision: Arrows MUST NOT pass through component interiors (route around with orthogonal paths)
- Text Overflow: All text MUST fit with 8px padding (estimate:
text.length × 7px ≤ shape_width - 16px)
- Arrow-Text Alignment: Arrow endpoints MUST connect to shape edges (not floating); arrow labels should not overlap arrow lines (use offset positioning or background rects)
- Container Discipline: Prefer arrows entering and leaving section containers through open gaps between components, not through inner component bodies
- Filter Boundary Safety: For every element with
filter="url(...)", verify (element_x + element_width + filter_extension) ≤ viewBox_width AND element_x ≥ filter_extension. The default filter region extends 10-20% beyond bbox; staying near viewBox edges causes Chrome/cairosvg to clip the element's edge-side stroke (one side of the border vanishes while other sides render correctly)
- Arrow-Title Collision: Arrows MUST NOT cross through section/container title text or region labels (font-size ≥ 13px). For smaller annotations (< 13px), prefer routing around but tolerate if layout constraints require it. (Visual self-review check — not covered by
validate-svg.sh automated checks)
- Frame Label–Arrow Alignment (sequence diagrams): Section/frame label badges MUST be vertically centered with their first message arrow. Compute
badge_y = first_arrow_y - (badge_height / 2). When appending new sections to an existing diagram, verify alignment matches the existing sections — this is the most common regression when adding content incrementally. Use variables in Python list generation to enforce the constraint: sec_y = 840; badge_y = sec_y - 9 # for height=18 badge
SVG Technical Rules
- ViewBox:
0 0 960 600 default; 0 0 960 800 tall; 0 0 1200 600 wide
- Fonts: embed via
<style>font-family: ...</style> — no external @import (cairosvg / rsvg-convert cannot fetch external URLs)
<defs>: arrow markers, gradients, filters, clip paths
- Text: minimum 12px, prefer 13-14px labels, 11px sub-labels, 16-18px titles
- All arrows:
<marker> with markerEnd, sized markerWidth="10" markerHeight="7"
- Drop shadows:
<feDropShadow> in <filter>, apply sparingly (key nodes only)
- Curved paths: use
M x1,y1 C cx1,cy1 cx2,cy2 x2,y2 cubic bezier for loops/feedback arrows
- Clip content: use
<clipPath> if text might overflow a node box
- Z-order (drawing order): SVG uses painter's model — later elements cover earlier ones. Recommended layer order (bottom → top): ① canvas background ② dashed containers / region backgrounds ③ arrows and connection lines ④ node shapes (rects, circles) ⑤ text labels and annotations ⑥ legends and overlays. When arrows pass near text, draw arrows BEFORE text so text stays readable. Adjust per diagram needs — this is guidance, not rigid.
SVG Generation & Error Prevention
MANDATORY: Python List Method (ALWAYS use this):
python3 << 'EOF'
lines = []
lines.append('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">')
lines.append(' <defs>')
# ... each line separately
lines.append('</svg>')
with open('/path/to/output.svg', 'w') as f:
f.write('\n'.join(lines))
print("SVG generated successfully")
EOF
Why mandatory: Prevents character truncation, typos, and syntax errors. Each line is independent and easy to verify.
Pre-Tool-Call Checklist (CRITICAL - use EVERY time):
- ✅ Can I write out the COMPLETE command/content right now?
- ✅ Do I have ALL required parameters ready?
- ✅ Have I checked for syntax errors in my prepared content?
If ANY answer is NO: STOP. Do NOT call the tool. Prepare the content first.
Error Recovery Protocol:
- First error: Analyze root cause, apply targeted fix
- Second error: Switch method entirely (Python list → chunked generation)
- Third error: STOP and report to user - do NOT loop endlessly
- Never: Retry the same failing command or call tools with empty parameters
Validation (run after generation):
python3 -c "import xml.etree.ElementTree as ET; ET.parse('file.svg')" && echo "✓ Valid XML"
# Or use cairosvg as a render-time check:
python3 -c "import cairosvg; cairosvg.svg2png(url='file.svg', write_to='/tmp/test.png')" && echo "✓ Renders" && rm /tmp/test.png
If using generate-from-template.py:
- Prefer
source / target node ids in arrow JSON so the generator can snap to node edges
- Keep
x1,y1,x2,y2 as hints or fallback coordinates, not the main routing primitive
- Let the generator choose orthogonal routes; avoid hardcoding center-to-center straight lines unless the path is guaranteed clear
Common Syntax Errors to Avoid:
- ❌
yt-anchor → ✅ y="60" text-anchor="middle"
- ❌
x="390 (missing y) → ✅ x="390" y="250"
- ❌
fill=#fff → ✅ fill="#ffffff"
- ❌
marker-end= → ✅ marker-end="url(#arrow)"
- ❌
L 29450 → ✅ L 290,220
- ❌ Missing
</svg> at end
- ❌ Element with
filter near viewBox edge — filter region extends 20% (default) or more beyond bbox; if that region exceeds viewBox, Chrome/cairosvg clip the filter rendering AND can drop the element's own stroke on that side. Keep filtered elements at least max(20% of element size, shadow blur radius × 3) away from viewBox edges, or omit the filter.
Output
- Default:
./[derived-name].svg and ./[derived-name].png in current directory
- Custom: user specifies path with
--output /path/ or 输出到 /path/
- PNG export: see SVG → PNG Conversion below
SVG → PNG Conversion
Method Comparison
| Tool |
Install |
Render Quality |
Notes |
rsvg-convert |
System (often preinstalled) |
⚠️ Fair |
Drops some CSS styles and <foreignObject> elements — missing borders/text on complex SVGs |
cairosvg (recommended) |
pip install cairosvg |
✅ Good |
Solid CSS support; clearly better than rsvg-convert |
puppeteer (headless Chrome) |
npm install puppeteer |
✅✅ Best |
Real browser engine; 100% fidelity but heavy (Node + Chromium) |
Recommended: cairosvg (Python one-liner)
# Single file (2x resolution for retina/docs)
python3 -c "import cairosvg; cairosvg.svg2png(url='input.svg', write_to='output.png', scale=2)"
# Batch convert all SVGs in a directory
python3 -c "
import cairosvg, os, glob
d = 'docs/00-core'
for svg in sorted(glob.glob(os.path.join(d, '*.svg'))):
png = svg.replace('.svg', '.png')
cairosvg.svg2png(url=svg, write_to=png, scale=2)
print(f'Done: {os.path.basename(svg)} -> {os.path.basename(png)}')
"
scale=2 produces 2x resolution PNG, ideal for high-DPI screens and embedded docs.
Fallback: rsvg-convert (simple but may drop styles)
# Single file
rsvg-convert -w 1920 file.svg -o file.png
# Batch (not recommended — complex SVGs may lose elements)
for f in docs/00-core/*.svg; do rsvg-convert -o "${f%.svg}.png" "$f"; done
# 2x resolution
for f in docs/00-core/*.svg; do rsvg-convert -z 2 -o "${f%.svg}.png" "$f"; done
Highest Fidelity: puppeteer (headless Chrome)
npm install puppeteer # auto-downloads Chromium
node svg2png.js [directory]
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
(async () => {
const dir = process.argv[2] || '.';
const svgFiles = fs.readdirSync(dir).filter(f => f.endsWith('.svg'));
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
for (const file of svgFiles) {
const svgPath = path.resolve(dir, file);
const pngPath = svgPath.replace(/\.svg$/, '.png');
const svgContent = fs.readFileSync(svgPath, 'utf-8');
const wMatch = svgContent.match(/width="(\d+)/);
const hMatch = svgContent.match(/height="(\d+)/);
const vbMatch = svgContent.match(/viewBox="[^"]*\s(\d+)\s(\d+)"/);
let width = wMatch ? parseInt(wMatch[1]) : (vbMatch ? parseInt(vbMatch[1]) : 1200);
let height = hMatch ? parseInt(hMatch[1]) : (vbMatch ? parseInt(vbMatch[2]) : 800);
const scale = 2;
const page = await browser.newPage();
await page.setViewport({ width, height, deviceScaleFactor: scale });
const html = `<!DOCTYPE html>
<html><head><style>
body { margin: 0; padding: 0; background: transparent; }
img { display: block; }
</style></head>
<body>
<img src="data:image/svg+xml;base64,${Buffer.from(svgContent).toString('base64')}" width="${width}" height="${height}" />
</body></html>`;
await page.setContent(html, { waitUntil: 'networkidle0' });
await page.screenshot({ path: pngPath, type: 'png', omitBackground: true });
await page.close();
console.log(`Done: ${file} -> ${path.basename(pngPath)} (${width}x${height} @${scale}x)`);
}
await browser.close();
})();
Gotchas (lessons learned)
rsvg-convert renders SVGs containing <foreignObject>, CSS filter, or complex <style> blocks incompletely — missing borders / missing text are the typical symptoms
cairosvg (built on Cairo) has much better CSS support than rsvg and is sufficient for most cases
cairosvg may fail to render CJK characters and emoji in <text> elements — Cairo's font API (cairo_select_font_face) does not reliably perform system fontconfig fallback, so glyphs not present in the matched font face render as □ (empty box). This commonly affects Chinese/Japanese/Korean text and emoji, depending on system font configuration. Workaround: use SVG as primary format for web/GitHub rendering (browsers handle CJK natively); reserve PNG export for Latin-only diagrams, or switch to the puppeteer path for full CJK+emoji fidelity
- If the SVG was generated by a browser (D3.js, Mermaid, etc.), only headless Chrome (puppeteer) renders it 100% faithfully
- Chrome headless CLI
--window-size=W,H is not the drawable area — even in --headless=new mode, browser chrome (scrollbars, internal UI surfaces) consumes ~15-20% of both width and height, so the actual SVG viewport is only ~0.84×W by ~0.84×H. Symptom: SVG content past x ≈ 0.84 × W or y ≈ 0.84 × H is cut off and renders as a solid white band, even though the SVG file itself is correct. Typical failure modes: a Legend in the top-right corner loses its right border; a bottom-row container loses its bottom dashed line. Fix: pass window dimensions ≥ SVG width × 1.2 AND SVG height × 1.2, then crop the raw screenshot back to (SVG_width × scale, SVG_height × scale) with PIL or ImageMagick. Example: for a 1280×580 SVG at 3× DPR, use --window-size=1600,800 then crop the output to 3840×1740. The Puppeteer / page.setViewport() path does NOT have this issue — it sets a precise viewport regardless of window UI.
Picking a Method
- Default →
cairosvg (pip install once, one-line conversion, good fidelity)
- No Python available →
rsvg-convert (acceptable for simple flat-color diagrams)
- Browser-generated SVG or pixel-perfect required →
puppeteer
Styles
| # |
Name |
Background |
Best For |
| 1 |
Flat Icon (default) |
White |
Blogs, docs, presentations |
| 2 |
Dark Terminal |
#0f0f1a |
GitHub, dev articles |
| 3 |
Blueprint |
#0a1628 |
Architecture docs |
| 4 |
Notion Clean |
White, minimal |
Notionnce |
| 5 |
Glassmorphism |
Dark gradient |
Product sites, keynotes |
| 6 |
Claude Official |
Warm cream #f8f6f3 |
Anthropic-style diagrams |
| 7 |
OpenAI Official |
Pure white #ffffff |
OpenAI-style diagrams |
| 8 |
Dark Luxury (AI-authored) |
#0a0a0a deep black |
Architecture docs, premium editorial — hand-craft SVG from references/style-8-dark-luxury.md |
Load references/style-N.md for exact color tokens and SVG patterns.
Style Selection
Default: Style 1 (Flat Icon) for most diagrams. Load references/style-diagram-matrix.md for detailed style-to-diagram-type recommendations.
These patterns appear frequently — internalize them:
RAG Pipeline: Query → Embed → VectorSearch → Retrieve → Augment → LLM → Response
Agentic RAG: adds Agent loop with Tool use between Query and LLM
Agentic Search: Query → Planner → [Search Tool / Calculator / Code] → Synthesizer → Response
Mem0 / Memory Layer: Input → Memory Manager → [Write: VectorDB + GraphDB] / [Read: Retrieve+Rank] → Context
Agent Memory Types: Sensory (raw input) → Working (context window) → Episodic (past interactions) → Semantic (facts) → Procedural (skills)
Multi-Agent: Orchestrator → [SubAgent A / SubAgent B / SubAgent C] → Aggregator → Output
Tool Call Flow: LLM → Tool Selector → Tool Execution → Result Parser → LLM (loop)
依赖与降级
| 依赖 |
必需性 |
缺失时行为 |
| Python 3 |
必需(运行 scripts/generate-from-template.py) |
无法用脚本从模板生成 SVG;可降级为「直接手写 SVG」(参考 templates/*.svg 模板) |
cairosvg(Python 包) |
可选 |
跳过 PNG 导出,仅输出 SVG 文件。提示:「装 pip install cairosvg 后可导出 PNG」 |
rsvg-convert |
可选(cairosvg 的替代) |
同上 — cairosvg 不可用时可作为 PNG 导出的备选,但 CSS 支持差 |
puppeteer(Node.js) |
可选(高级备选) |
同上;适合浏览器生成的 SVG 或需像素级精确渲染时(CJK+emoji 也最可靠) |
xmllint(libxml2) |
可选(SVG 校验增强) |
validate-svg.sh 仍可运行,但部分高级 XML 校验跳过 |
关键:SVG 文件永远可生成 — Python 3 + 手写 SVG 即可。所有 PNG 导出依赖都是可选的,缺失时降级为「只输出 SVG」,并打印一条提示告知如何安装以启用 PNG 导出。
各依赖的选用建议
- 默认 →
cairosvg(pip install cairosvg 一次,命令行一键转换,保真度好)
- 无 Python →
rsvg-convert(适合简单平面色图,复杂 CSS 支持差)
- 浏览器生成的 SVG 或像素级精确 →
puppeteer(完整 Chrome 渲染管线,但装得最重)
- CJK 文本 → 浏览器渲染 SVG(GitHub/HTML 内嵌),或用 puppeteer 路径(cairosvg 对 CJK 字体回退不可靠,详见上文 SVG → PNG Conversion 节)
输出自检清单
交付前的最终检查清单(关键项;详细规则见上文 Validation Checklist 与 Workflow 第 11 步 Visual self-review):
SVG 语法合法性
视觉正确性
PNG 导出(如装了 cairosvg/rsvg/puppeteer)
如以上任一项失败,参考上文相应的修复指南("Common fixes" / "Validation Checklist" / "SVG → PNG Conversion")。
相关技能
本 skill 是 diagram 技能家族的一员,按输出格式分工,4 个 skill 互补但不重叠:
| Skill |
输出形态 |
主用途 |
diagram-mermaid |
Mermaid 代码块(内联 Markdown) |
GitHub README/issue/PR 嵌入,零依赖,GitHub 直接渲染 |
diagram-plantuml |
PlantUML 代码块(内联 Markdown) |
UML/云架构/网络拓扑/安全/ArchiMate/BPMN/数据管道/IoT 等专业图 |
diagram-html |
独立 HTML 文件 |
可分享的成品图,浏览器打开即用,双主题切换 + 浏览器导出菜单 |
diagram-image(本 skill) |
SVG + PNG 文件 |
命令行直接产出图片文件,适合 CI/批处理/嵌入不支持 SVG 的环境 |
选用决策:
- 在 Markdown 里嵌入图、要源码可读、可 diff →
diagram-mermaid 或 diagram-plantuml
- 要可交互的 HTML 成品、双主题切换、点按钮导出 →
diagram-html
- 要命令行直接出 SVG/PNG 文件、CI/批处理 → 本 skill(
diagram-image)
与 diagram-html 的关键区别:虽然 archify(diagram-html)也能通过浏览器手动导出 PNG,但本 skill 是命令行直接产出文件——适合 CI/批处理/无浏览器环境。本 skill 独有:8 种视觉风格(flat-icon/dark-terminal/blueprint/notion-clean/glassmorphism/claude-official/openai/dark-luxury)、ER/use-case/timeline/comparison-matrix/agent-architecture 5 种图类型。本 skill 不如 diagram-html 的:无双主题切换、无 HTML 内导出菜单、不接受 Mermaid 输入。
1---2name: diagram-image3description: Generate production-quality SVG and PNG technical diagrams via direct SVG authoring plus Python helper scripts. Use when the user wants any technical diagram — architecture, data flow, flowchart, sequence, agent/memory, ER, state machine, use case, timeline, comparison matrix — exported as standalone SVG and/or PNG files (NOT inline Markdown code blocks, NOT interactive HTML). Trigger on: "画图" "帮我画" "生成图" "做个图" "架构图" "流程图" "可视化一下" "出图" "导出 SVG" "导出 PNG" "生成图片文件" "generate diagram" "draw diagram" "visualize" "export SVG" "export PNG" or any system/flow description the user wants illustrated as a file. Part of the diagram skill family (diagram-mermaid / diagram-plantuml / diagram-html / diagram-image) — pick this skill when the user wants SVG/PNG files (vs. inline Markdown code blocks or interactive HTML), needs command-line/CI/batch image generation, or wants one of the 8 visual styles (flat-icon/dark-terminal/blueprint/notion-clean/ glassmorphism/claude-official/openai/dark-luxury).4---56# diagram-image (based on Fireworks Tech Graph)78Generate production-quality SVG technical diagrams exported as PNG via `cairosvg` (recommended), `rsvg-convert`, or `puppeteer`.910## Helper Scripts (Recommended)1112Four helper scripts in `scripts/` directory provide stable SVG generation and validation:1314### 1. `generate-diagram.sh` - Validate SVG + export PNG15```bash16./scripts/generate-diagram.sh -t architecture -s 1 -o ./output/arch.svg17```18- Validates an existing SVG file19- Exports PNG after validation20- Example: `./scripts/generate-diagram.sh -t architecture -s 1 -o ./output/arch.svg`2122### 2. `generate-from-template.py` - Create starter SVG from template23```bash24python3 ./scripts/generate-from-template.py architecture ./output/arch.svg '{"title":"My Diagram","nodes":[],"arrows":[]}'25```26- Loads a built-in SVG template27- Renders nodes, arrows, and legend entries from JSON input28- Escapes text content to keep output XML-valid2930### 3. `validate-svg.sh` - Validate SVG syntax31```bash32./scripts/validate-svg.sh <svg-file>33```34- Checks XML syntax35- Verifies tag balance36- Validates marker references37- Checks attribute completeness38- Validates path data3940### 4. `test-all-styles.sh` - Batch test all styles41```bash42./scripts/test-all-styles.sh43```44- Tests multiple diagram sizes45- Validates all generated SVGs46- Generates test report4748**When to use scripts:**49- Use scripts when generating complex SVGs to avoid syntax errors50- Scripts provide automatic validation and error reporting51- Recommended for production diagrams5253**When to generate SVG directly:**54- Simple diagrams with few elements55- Quick prototypes56- When you need full control over SVG structure5758## Workflow (Always Follow This Order)59601. **Classify** the diagram type (see Diagram Types below)612. **Extract structure** — identify layers, nodes, edges, flows, and semantic groups from user description623. **Plan layout** — apply the layout rules for the diagram type634. **Load style reference** — always load `references/style-1-flat-icon.md` unless user specifies another; load the matching `references/style-N.md` for exact color tokens and SVG patterns645. **Map nodes to shapes** — use Shape Vocabulary below656. **Check icon needs** — load `references/icons.md` for known products667. **Write SVG** with adaptive strategy (see SVG Generation Strategy below)678. **Validate**: Run `python3 -c "import xml.etree.ElementTree as ET; ET.parse('file.svg')"` to check XML syntax689. **Export PNG**: Use `cairosvg` (recommended). See **SVG → PNG Conversion** section below for full method comparison6910. **Report** the generated file paths7011. **(Optional) Visual self-review** — if your runtime can read images, load the exported PNG back and inspect it. Syntactic validity does not guarantee visual correctness: arrows may cross through component interiors, labels may collide with lifelines or other labels, boxes may overlap, alt-frame text may sit on top of a message, or a legend may cover content. If you see any of these, revise the SVG and re-export; repeat until the rendered image is clean. Common fixes:71 - Route arrows through gaps between boxes, not through box interiors72 - Move arrow labels 6-8px away from the arrow line (offset-first); add background rects only when offset is insufficient73 - Widen inter-row/inter-column gutters so same-layer arrows have clear corridors74 - Collapse repeated cross-layer arrows into a single "delegates down" rail outside the content area75 - Move legend/notes out of any region where arrows or labels land76 - Increase viewBox height/width rather than packing elements tighter77 - If a filtered element (drop-shadow, blur) is missing one side of its border, move it ≥30px away from that viewBox edge, or remove the filter and rely on color/contrast for visual separation78 Skip this step silently if image reading is unavailable — do not guess.7980## Diagram Types & Layout Rules8182### Architecture Diagram83Nodes = services/components. Group into **horizontal layers** (top→bottom or left→right).84- Typical layers: Client → Gateway/LB → Services → Data/Storage85- Use `<rect>` dashed containers to group related services in the same layer86- Arrow direction follows data/request flow87- ViewBox: `0 0 960 600` standard, `0 0 960 800` for tall stacks8889### Data Flow Diagram90Emphasizes **what data moves where**. Focus on data transformation.91- Label every arrow with the data type (e.g., "embeddings", "query", "context")92- Use wider arrows (`stroke-width: 2.5`) for primary data paths93- Dashed arrows for control/trigger flows94- Color arrows by data category (not just Agent/RAG — use semantics)9596### Flowchart / Process Flow97Sequential decision/process steps.98- Top-to-bottom preferred; left-to-right for wide flows99- Diamond shapes for decisions, rounded rects for processes, parallelograms for I/O100- Keep node labels short (≤3 words); put detail in sub-labels101- Align nodes on a grid: x positions snap to 120px intervals, y to 80px102103### Agent Architecture Diagram104Shows how an AI agent reasons, uses tools, and manages memory.105Key conceptual layers to always consider:106- **Input layer**: User, query, trigger107- **Agent core**: LLM, reasoning loop, planner108- **Memory layer**: Short-term (context window), Long-term (vector/graph DB), Episodic109- **Tool layer**: Tool calls, APIs, search, code execution110- **Output layer**: Response, action, side-effects111Use cyclic arrows (loop arcs) to show iterative reasoning. Separate memory types visually.112113### Memory Architecture Diagram (Mem0, MemGPT-style)114Specialized agent diagram focused on memory operations.115- Show memory **write path** and **read path** separately (different arrow colors)116- Memory tiers: Working Memory → Short-term → Long-term → External Store117- Label memory operations: `store()`, `retrieve()`, `forget()`, `consolidate()`118- Use stacked rects or layered cylinders for storage tiers119120### Sequence Diagram121Time-ordered message exchanges between participants.122- Participants as vertical **lifelines** (top labels + vertical dashed lines)123- Messages as horizontal arrows between lifelines, top-to-bottom time order124- Activation boxes (thin filled rects on lifeline) show active processing125- Group with `<rect>` loop/alt frames with label in top-left corner126- ViewBox height = 80 + (num_messages × 50)127128### Comparison / Feature Matrix129Side-by-side comparison of approaches, systems, or components.130- Column headers = systems, row headers = attributes131- Row height: 40px; column width: min 120px; header row height: 50px132- Checked cell: tinted background (e.g. `#dcfce7`) + `✓` checkmark; unsupported: `#f9fafb` fill133- Alternating row fills (`#f9fafb` / `#ffffff`) for readability134- Max readable columns: 5; beyond that, split into two diagrams135136### Timeline / Gantt137Horizontal time axis showing durations, phases, and milestones.138- X-axis = time (weeks/months/quarters); Y-axis = items/tasks/phases139- Bars: rounded rects, colored by category, labeled inside or beside140- Milestone markers: diamond or filled circle at specific x position with label above141- ViewBox: `0 0 960 400` typical; wider for many time periods: `0 0 1200 400`142143### Mind Map / Concept Map144Radial layout from central concept.145- Central node at `cx=480, cy=280`146- First-level branches: evenly distributed around center (360/N degrees)147- Second-level branches: branch off first-level at 30-45° offset148- Use curved `<path>` with cubic bezier for branches, not straight lines149150### Class Diagram (UML)151Static structure showing classes, attributes, methods, and relationships.152- **Class box**: 3-compartment rect (name / attributes / methods), min width 160px153 - Top compartment: class name, bold, centered (abstract = *italic*)154 - Middle: attributes with visibility (`+` public, `-` private, `#` protected)155 - Bottom: method signatures, same visibility notation156- **Relationships**:157 - Inheritance (extends): solid line + hollow triangle arrowhead, child → parent158 - Implementation (interface): dashed line + hollow triangle, class → interface159 - Association: solid line + open arrowhead, label with multiplicity (1, 0..*, 1..*)160 - Aggregation: solid line + hollow diamond on container side161 - Composition: solid line + filled diamond on container side162 - Dependency: dashed line + open arrowhead163- **Interface**: `<<interface>>` stereotype above name, or circle/lollipop notation164- **Enum**: compartment rect with `<<enumeration>>` stereotype, values in bottom165- Layout: parent classes top, children below; interfaces to the left/right of implementors166- ViewBox: `0 0 960 600` standard; `0 0 960 800` for deep hierarchies167168### Use Case Diagram (UML)169System functionality from user perspective.170- **Actor**: stick figure (circle head + body line) placed outside system boundary171 - Label below figure, 13-14px172 - Primary actors on left, secondary/supporting on right173- **Use case**: ellipse with label centered inside, min 140×60px174 - Keep names verb phrases: "Create Order", "Process Payment"175- **System boundary**: large rect with dashed border + system name in top-left176- **Relationships**:177 - Include: dashed arrow `<<include>>` from base to included use case178 - Extend: dashed arrow `<<extend>>` from extension to base use case179 - Generalization: solid line + hollow triangle (specialized → general)180- Layout: system boundary centered, actors outside, use cases inside181- ViewBox: `0 0 960 600` standard182183### State Machine Diagram (UML)184Lifecycle states and transitions of an entity.185- **State**: rounded rect with state name, min 120×50px186 - Internal activities: small text `entry/ action`, `exit/ action`, `do/ activity`187 - **Initial state**: filled black circle (r=8), one outgoing arrow188 - **Final state**: filled circle (r=8) inside hollow circle (r=12)189 - **Choice**: small hollow diamond, guard labels on outgoing arrows `[condition]`190- **Transition**: arrow with optional label `event [guard] / action`191 - Guard conditions in square brackets192 - Actions after `/`193- **Composite/nested state**: larger rect containing sub-states, with name tab194- **Fork/join**: thick horizontal or vertical black bar (synchronization)195- Layout: initial state top-left, final state bottom-right, flow top-to-bottom196- ViewBox: `0 0 960 600` standard197198### ER Diagram (Entity-Relationship)199Database schema and data relationships.200- **Entity**: rect with entity name in header (bold), attributes below201 - Primary key attribute: underlined202 - Foreign key: italic or marked with (FK)203 - Min width: 160px; attribute font-size: 12px204- **Relationship**: diamond shape on connecting line205 - Label inside diamond: "has", "belongs to", "enrolls in"206 - Cardinality labels near entity: `1`, `N`, `0..1`, `0..*`, `1..*`207- **Weak entity**: double-bordered rect with double diamond relationship208- **Associative entity**: diamond + rect hybrid (rect with diamond inside)209- Line style: solid for identifying relationships, dashed for non-identifying210- Layout: entities in 2-3 rows, relationships between related entities211- ViewBox: `0 0 960 600` standard; wider `0 0 1200 600` for many entities212213### Network Topology214Physical or logical network infrastructure.215- **Devices**: icon-like rects or rounded rects216 - Router: circle with cross arrows217 - Switch: rect with arrow grid218 - Server: stacked rect (rack icon)219 - Firewall: brick-pattern rect or shield shape220 - Load Balancer: horizontal split rect with arrows221 - Cloud: cloud path (overlapping arcs)222- **Connections**: lines between device centers223 - Ethernet/wired: solid line, label bandwidth224 - Wireless: dashed line with WiFi symbol225 - VPN: dashed line with lock icon226- **Subnets/Zones**: dashed rect containers with zone label (DMZ, Internal, External)227- **Labels**: device hostname + IP below, 12-13px228- Layout: tiered top-to-bottom (Internet → Edge → Core → Access → Endpoints)229- ViewBox: `0 0 960 600` standard230231## UML Coverage Map232233Full mapping of UML 14 diagram types to supported diagram types:234235| UML Diagram | Supported As | Notes |236|-------------|-------------|-------|237| Class | Class Diagram | Full UML notation |238| Component | Architecture Diagram | Use colored fills per component type |239| Deployment | Architecture Diagram | Add node/instance labels |240| Package | Architecture Diagram | Use dashed grouping containers |241| Composite Structure | Architecture Diagram | Nested rects within components |242| Object | Class Diagram | Instance boxes with underlined name |243| Use Case | Use Case Diagram | Full actor/ellipse/relationship |244| Activity | Flowchart / Process Flow | Add fork/join bars |245| State Machine | State Machine Diagram | Full UML notation |246| Sequence | Sequence Diagram | Add alt/opt/loop frames |247| Communication | — | Approximate with Sequence (swap axes) |248| Timing | Timeline | Adapt time axis |249| Interaction Overview | Flowchart | Combine activity + sequence fragments |250| ER Diagram | ER Diagram | Chen/Crow's foot notation |251252## Shape Vocabulary253254Map semantic concepts to consistent shapes across all diagram types:255256| Concept | Shape | Notes |257|---------|-------|-------|258| User / Human | Circle + body path | Stick figure or avatar |259| LLM / Model | Rounded rect with brain/spark icon or gradient fill | Use accent color |260| Agent / Orchestrator | Hexagon or rounded rect with double border | Signals "active controller" |261| Memory (short-term) | Rounded rect, dashed border | Ephemeral = dashed |262| Memory (long-term) | Cylinder (database shape) | Persistent = solid cylinder |263| Vector Store | Cylinder with grid lines inside | Add 3 horizontal lines |264| Graph DB | Circle cluster (3 overlapping circles) | |265| Tool / Function | Gear-like rect or rect with wrench icon | |266| API / Gateway | Hexagon (single border) | |267| Queue / Stream | Horizontal tube (pipe shape) | |268| File / Document | Folded-corner rect | |269| Browser / UI | Rect with 3-dot titlebar | |270| Decision | Diamond | Flowcharts only |271| Process / Step | Rounded rect | Standard box |272| External Service | Rect with cloud icon or dashed border | |273| Data / Artifact | Parallelogram | I/O in flowcharts |274275## Arrow Semantics276277Always assign arrow meaning, not just color:278279| Flow Type | Color | Stroke | Dash | Meaning |280|-----------|-------|--------|------|---------|281| Primary data flow | blue `#2563eb` | 2px solid | none | Main request/response path |282| Control / trigger | orange `#ea580c` | 1.5px solid | none | One system triggering another |283| Memory read | green `#059669` | 1.5px solid | none | Retrieval from store |284| Memory write | green `#059669` | 1.5px | `5,3` | Write/store operation |285| Async / event | gray `#6b7280` | 1.5px | `4,2` | Non-blocking, event-driven |286| Embedding / transform | purple `#7c3aed` | 1px solid | none | Data transformation |287| Feedback / loop | purple `#7c3aed` | 1.5px curved | none | Iterative reasoning loop |288289Always include a **legend** when 2+ arrow types are used.290291## Layout Rules & Validation292293**Spacing**:294- Same-layer nodes: 80px horizontal, 120px vertical between layers295- Canvas margins: 40px minimum, 60px between node edges296- Snap to 8px grid: horizontal 120px intervals, vertical 120px intervals297298**Arrow Labels** (CRITICAL):299- **Offset-first** (default): place label 6-8px above horizontal arrows, or 8px left/right of vertical arrows — do not overlap the arrow line300- **Background fallback**: add `<rect fill="canvas_bg" opacity="0.95"/>` only when the offset label still crosses another visual element (another arrow, a node edge, etc.)301- Place mid-arrow, ≤3 words, stagger by 15-20px when multiple arrows converge302- Maintain 10px safety distance from nodes303304**Arrow Routing**:305- Prefer orthogonal (L-shaped) paths to minimize crossings306- Anchor arrows on component edges, not geometric centers307- Route around dense node clusters, use different y-offsets for parallel arrows308- Jump-over arcs (5px radius) for unavoidable crossings309310**Post-Generation Arrow Optimization**:311312When a user asks to "优化箭头" / "fix arrow routing" / "optimize the diagram" on an already-generated diagram, preserve all nodes, containers, styles, and layout — only modify the `arrows` entries in the JSON data, then re-render with `generate-from-template.py`.313314Available arrow override fields (in recommended order of use):315316| Field | Type | When to Use |317|-------|------|-------------|318| `source_port` / `target_port` | `"left"` / `"right"` / `"top"` / `"bottom"` | Arrow exits/enters from the wrong edge |319| `corridor_x` | `[x, ...]` | Hint vertical segments toward this x lane (soft preference) |320| `corridor_y` | `[y, ...]` | Hint horizontal segments toward this y lane (soft preference) |321| `route_points` | `[[x1,y1], [x2,y2], ...]` | Force exact waypoints (bypasses auto-routing); keep segments orthogonal |322| `routing_padding` | number (default: 24) | *(Advanced)* Adjust obstacle clearance for this arrow |323| `port_clearance` | number | *(Advanced)* Adjust first-segment offset from node edge |324| `label_style` | `"badge"` / `"offset"` | Choose `"offset"` when badge backgrounds create visual clutter; keep `"badge"` (default) for legacy/high-contrast labels |325326For JSON/template rendering, the default remains `"badge"` for backward compatibility. Set `"label_style": "offset"` on individual arrows when you want offset-first labels without background rects.327328Optimization steps:3291. Read the existing SVG — identify which arrows overlap, cross nodes, or look misaligned3302. Find those arrows in the JSON data by `source` / `target` pair3313. Add `source_port` / `target_port` if the exit/entry direction is wrong; add `corridor_x` / `corridor_y` to space parallel arrows apart; use `route_points` only when hints alone cannot resolve the path3324. Re-run `generate-from-template.py` with the updated JSON and validate with `validate-svg.sh`333334Example — spacing two overlapping arrows into separate corridors:335```json336{ "source": "nodeA", "target": "nodeB", "corridor_y": [280] }337{ "source": "nodeC", "target": "nodeD", "corridor_y": [320] }338```339340**Line Overlap Prevention** (CRITICAL - most common bug on Codex):341When two arrows must cross each other, ALWAYS use jump-over arcs to prevent visual overlap:342- Crossing horizontal arrows: add a small semicircle arc (radius 5px, stroke same color as arrow, fill none) that "jumps over" the other line343- SVG pattern for jump-over: use a white/matching-background arc on the lower layer, then draw the upper arc on top344- Multiple crossings: stagger arc radii (5px, 7px, 9px) so arcs don't overlap each other345- Never let two arrows' straight-line segments cross without a jump-over arc346347**Validation Checklist** (run before finalizing):3481. **Arrow-Component Collision**: Arrows MUST NOT pass through component interiors (route around with orthogonal paths)3492. **Text Overflow**: All text MUST fit with 8px padding (estimate: `text.length × 7px ≤ shape_width - 16px`)3503. **Arrow-Text Alignment**: Arrow endpoints MUST connect to shape edges (not floating); arrow labels should not overlap arrow lines (use offset positioning or background rects)3514. **Container Discipline**: Prefer arrows entering and leaving section containers through open gaps between components, not through inner component bodies3525. **Filter Boundary Safety**: For every element with `filter="url(...)"`, verify `(element_x + element_width + filter_extension) ≤ viewBox_width` AND `element_x ≥ filter_extension`. The default filter region extends 10-20% beyond bbox; staying near viewBox edges causes Chrome/cairosvg to clip the element's edge-side stroke (one side of the border vanishes while other sides render correctly)3536. **Arrow-Title Collision**: Arrows MUST NOT cross through section/container title text or region labels (font-size ≥ 13px). For smaller annotations (< 13px), prefer routing around but tolerate if layout constraints require it. *(Visual self-review check — not covered by `validate-svg.sh` automated checks)*3547. **Frame Label–Arrow Alignment** (sequence diagrams): Section/frame label badges MUST be vertically centered with their first message arrow. Compute `badge_y = first_arrow_y - (badge_height / 2)`. When appending new sections to an existing diagram, verify alignment matches the existing sections — this is the most common regression when adding content incrementally. Use variables in Python list generation to enforce the constraint: `sec_y = 840; badge_y = sec_y - 9 # for height=18 badge`355356## SVG Technical Rules357358- ViewBox: `0 0 960 600` default; `0 0 960 800` tall; `0 0 1200 600` wide359- Fonts: embed via `<style>font-family: ...</style>` — no external `@import` (cairosvg / rsvg-convert cannot fetch external URLs)360- `<defs>`: arrow markers, gradients, filters, clip paths361- Text: minimum 12px, prefer 13-14px labels, 11px sub-labels, 16-18px titles362- All arrows: `<marker>` with `markerEnd`, sized `markerWidth="10" markerHeight="7"`363- Drop shadows: `<feDropShadow>` in `<filter>`, apply sparingly (key nodes only)364- Curved paths: use `M x1,y1 C cx1,cy1 cx2,cy2 x2,y2` cubic bezier for loops/feedback arrows365- Clip content: use `<clipPath>` if text might overflow a node box366- Z-order (drawing order): SVG uses painter's model — later elements cover earlier ones. Recommended layer order (bottom → top): ① canvas background ② dashed containers / region backgrounds ③ arrows and connection lines ④ node shapes (rects, circles) ⑤ text labels and annotations ⑥ legends and overlays. When arrows pass near text, draw arrows BEFORE text so text stays readable. Adjust per diagram needs — this is guidance, not rigid.367368## SVG Generation & Error Prevention369370**MANDATORY: Python List Method** (ALWAYS use this):371```python372python3 << 'EOF'373lines = []374lines.append('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">')375lines.append(' <defs>')376# ... each line separately377lines.append('</svg>')378379with open('/path/to/output.svg', 'w') as f:380 f.write('\n'.join(lines))381print("SVG generated successfully")382EOF383```384385**Why mandatory**: Prevents character truncation, typos, and syntax errors. Each line is independent and easy to verify.386387**Pre-Tool-Call Checklist** (CRITICAL - use EVERY time):3881. ✅ Can I write out the COMPLETE command/content right now?3892. ✅ Do I have ALL required parameters ready?3903. ✅ Have I checked for syntax errors in my prepared content?391392**If ANY answer is NO**: STOP. Do NOT call the tool. Prepare the content first.393394**Error Recovery Protocol**:395- **First error**: Analyze root cause, apply targeted fix396- **Second error**: Switch method entirely (Python list → chunked generation)397- **Third error**: STOP and report to user - do NOT loop endlessly398- **Never**: Retry the same failing command or call tools with empty parameters399400**Validation** (run after generation):401```bash402python3 -c "import xml.etree.ElementTree as ET; ET.parse('file.svg')" && echo "✓ Valid XML"403# Or use cairosvg as a render-time check:404python3 -c "import cairosvg; cairosvg.svg2png(url='file.svg', write_to='/tmp/test.png')" && echo "✓ Renders" && rm /tmp/test.png405```406407**If using `generate-from-template.py`**:408- Prefer `source` / `target` node ids in arrow JSON so the generator can snap to node edges409- Keep `x1,y1,x2,y2` as hints or fallback coordinates, not the main routing primitive410- Let the generator choose orthogonal routes; avoid hardcoding center-to-center straight lines unless the path is guaranteed clear411412**Common Syntax Errors to Avoid**:413- ❌ `yt-anchor` → ✅ `y="60" text-anchor="middle"`414- ❌ `x="390` (missing y) → ✅ `x="390" y="250"`415- ❌ `fill=#fff` → ✅ `fill="#ffffff"`416- ❌ `marker-end=` → ✅ `marker-end="url(#arrow)"`417- ❌ `L 29450` → ✅ `L 290,220`418- ❌ Missing `</svg>` at end419- ❌ Element with `filter` near viewBox edge — filter region extends 20% (default) or more beyond bbox; if that region exceeds viewBox, Chrome/cairosvg clip the filter rendering AND can drop the element's own stroke on that side. Keep filtered elements at least `max(20% of element size, shadow blur radius × 3)` away from viewBox edges, or omit the filter.420421## Output422423- **Default**: `./[derived-name].svg` and `./[derived-name].png` in current directory424- **Custom**: user specifies path with `--output /path/` or `输出到 /path/`425- **PNG export**: see **SVG → PNG Conversion** below426427## SVG → PNG Conversion428429### Method Comparison430431| Tool | Install | Render Quality | Notes |432|------|---------|----------------|-------|433| `rsvg-convert` | System (often preinstalled) | ⚠️ Fair | Drops some CSS styles and `<foreignObject>` elements — missing borders/text on complex SVGs |434| **`cairosvg` (recommended)** | `pip install cairosvg` | ✅ Good | Solid CSS support; clearly better than rsvg-convert |435| `puppeteer` (headless Chrome) | `npm install puppeteer` | ✅✅ Best | Real browser engine; 100% fidelity but heavy (Node + Chromium) |436437### Recommended: cairosvg (Python one-liner)438439```bash440# Single file (2x resolution for retina/docs)441python3 -c "import cairosvg; cairosvg.svg2png(url='input.svg', write_to='output.png', scale=2)"442443# Batch convert all SVGs in a directory444python3 -c "445import cairosvg, os, glob446d = 'docs/00-core'447for svg in sorted(glob.glob(os.path.join(d, '*.svg'))):448 png = svg.replace('.svg', '.png')449 cairosvg.svg2png(url=svg, write_to=png, scale=2)450 print(f'Done: {os.path.basename(svg)} -> {os.path.basename(png)}')451"452```453454> `scale=2` produces 2x resolution PNG, ideal for high-DPI screens and embedded docs.455456### Fallback: rsvg-convert (simple but may drop styles)457458```bash459# Single file460rsvg-convert -w 1920 file.svg -o file.png461462# Batch (not recommended — complex SVGs may lose elements)463for f in docs/00-core/*.svg; do rsvg-convert -o "${f%.svg}.png" "$f"; done464465# 2x resolution466for f in docs/00-core/*.svg; do rsvg-convert -z 2 -o "${f%.svg}.png" "$f"; done467```468469### Highest Fidelity: puppeteer (headless Chrome)470471```bash472npm install puppeteer # auto-downloads Chromium473node svg2png.js [directory]474```475476<details>477<summary>svg2png.js — full puppeteer script</summary>478479```javascript480const puppeteer = require('puppeteer');481const fs = require('fs');482const path = require('path');483484(async () => {485 const dir = process.argv[2] || '.';486 const svgFiles = fs.readdirSync(dir).filter(f => f.endsWith('.svg'));487488 const browser = await puppeteer.launch({489 headless: 'new',490 args: ['--no-sandbox', '--disable-setuid-sandbox']491 });492493 for (const file of svgFiles) {494 const svgPath = path.resolve(dir, file);495 const pngPath = svgPath.replace(/\.svg$/, '.png');496 const svgContent = fs.readFileSync(svgPath, 'utf-8');497498 const wMatch = svgContent.match(/width="(\d+)/);499 const hMatch = svgContent.match(/height="(\d+)/);500 const vbMatch = svgContent.match(/viewBox="[^"]*\s(\d+)\s(\d+)"/);501502 let width = wMatch ? parseInt(wMatch[1]) : (vbMatch ? parseInt(vbMatch[1]) : 1200);503 let height = hMatch ? parseInt(hMatch[1]) : (vbMatch ? parseInt(vbMatch[2]) : 800);504505 const scale = 2;506 const page = await browser.newPage();507 await page.setViewport({ width, height, deviceScaleFactor: scale });508509 const html = `<!DOCTYPE html>510<html><head><style>511 body { margin: 0; padding: 0; background: transparent; }512 img { display: block; }513</style></head>514<body>515 <img src="data:image/svg+xml;base64,${Buffer.from(svgContent).toString('base64')}" width="${width}" height="${height}" />516</body></html>`;517518 await page.setContent(html, { waitUntil: 'networkidle0' });519 await page.screenshot({ path: pngPath, type: 'png', omitBackground: true });520 await page.close();521522 console.log(`Done: ${file} -> ${path.basename(pngPath)} (${width}x${height} @${scale}x)`);523 }524525 await browser.close();526})();527```528529</details>530531### Gotchas (lessons learned)532533- `rsvg-convert` renders SVGs containing `<foreignObject>`, CSS `filter`, or complex `<style>` blocks **incompletely** — missing borders / missing text are the typical symptoms534- `cairosvg` (built on Cairo) has much better CSS support than rsvg and is sufficient for most cases535- `cairosvg` **may fail to render CJK characters and emoji** in `<text>` elements — Cairo's font API (`cairo_select_font_face`) does not reliably perform system fontconfig fallback, so glyphs not present in the matched font face render as □ (empty box). This commonly affects Chinese/Japanese/Korean text and emoji, depending on system font configuration. **Workaround**: use SVG as primary format for web/GitHub rendering (browsers handle CJK natively); reserve PNG export for Latin-only diagrams, or switch to the puppeteer path for full CJK+emoji fidelity536- If the SVG was generated by a browser (D3.js, Mermaid, etc.), only headless Chrome (puppeteer) renders it 100% faithfully537- **Chrome headless CLI `--window-size=W,H` is not the drawable area** — even in `--headless=new` mode, browser chrome (scrollbars, internal UI surfaces) consumes ~15-20% of both width and height, so the actual SVG viewport is only ~0.84×W by ~0.84×H. Symptom: SVG content past `x ≈ 0.84 × W` or `y ≈ 0.84 × H` is cut off and renders as a solid white band, even though the SVG file itself is correct. Typical failure modes: a Legend in the top-right corner loses its right border; a bottom-row container loses its bottom dashed line. Fix: pass window dimensions **≥ SVG width × 1.2 AND SVG height × 1.2**, then crop the raw screenshot back to `(SVG_width × scale, SVG_height × scale)` with PIL or ImageMagick. Example: for a 1280×580 SVG at 3× DPR, use `--window-size=1600,800` then crop the output to 3840×1740. The Puppeteer / `page.setViewport()` path does NOT have this issue — it sets a precise viewport regardless of window UI.538539### Picking a Method5405411. **Default** → `cairosvg` (pip install once, one-line conversion, good fidelity)5422. **No Python available** → `rsvg-convert` (acceptable for simple flat-color diagrams)5433. **Browser-generated SVG or pixel-perfect required** → `puppeteer`544545## Styles546547| # | Name | Background | Best For |548|---|------|-----------|----------|549| 1 | **Flat Icon** (default) | White | Blogs, docs, presentations |550| 2 | **Dark Terminal** | `#0f0f1a` | GitHub, dev articles |551| 3 | **Blueprint** | `#0a1628` | Architecture docs |552| 4 | **Notion Clean** | White, minimal | Notionnce |553| 5 | **Glassmorphism** | Dark gradient | Product sites, keynotes |554| 6 | **Claude Official** | Warm cream `#f8f6f3` | Anthropic-style diagrams |555| 7 | **OpenAI Official** | Pure white `#ffffff` | OpenAI-style diagrams |556| 8 | **Dark Luxury** *(AI-authored)* | `#0a0a0a` deep black | Architecture docs, premium editorial — hand-craft SVG from `references/style-8-dark-luxury.md` |557558Load `references/style-N.md` for exact color tokens and SVG patterns.559560## Style Selection561562**Default**: Style 1 (Flat Icon) for most diagrams. Load `references/style-diagram-matrix.md` for detailed style-to-diagram-type recommendations.563564These patterns appear frequently — internalize them:565566**RAG Pipeline**: Query → Embed → VectorSearch → Retrieve → Augment → LLM → Response567**Agentic RAG**: adds Agent loop with Tool use between Query and LLM568**Agentic Search**: Query → Planner → [Search Tool / Calculator / Code] → Synthesizer → Response569**Mem0 / Memory Layer**: Input → Memory Manager → [Write: VectorDB + GraphDB] / [Read: Retrieve+Rank] → Context570**Agent Memory Types**: Sensory (raw input) → Working (context window) → Episodic (past interactions) → Semantic (facts) → Procedural (skills)571**Multi-Agent**: Orchestrator → [SubAgent A / SubAgent B / SubAgent C] → Aggregator → Output572**Tool Call Flow**: LLM → Tool Selector → Tool Execution → Result Parser → LLM (loop)573574## 依赖与降级575576| 依赖 | 必需性 | 缺失时行为 |577|---|---|---|578| Python 3 | 必需(运行 `scripts/generate-from-template.py`) | 无法用脚本从模板生成 SVG;可降级为「直接手写 SVG」(参考 `templates/*.svg` 模板) |579| `cairosvg`(Python 包) | 可选 | 跳过 PNG 导出,仅输出 SVG 文件。提示:「装 `pip install cairosvg` 后可导出 PNG」 |580| `rsvg-convert` | 可选(cairosvg 的替代) | 同上 — cairosvg 不可用时可作为 PNG 导出的备选,但 CSS 支持差 |581| `puppeteer`(Node.js) | 可选(高级备选) | 同上;适合浏览器生成的 SVG 或需像素级精确渲染时(CJK+emoji 也最可靠) |582| `xmllint`(libxml2) | 可选(SVG 校验增强) | `validate-svg.sh` 仍可运行,但部分高级 XML 校验跳过 |583584**关键:SVG 文件永远可生成** — Python 3 + 手写 SVG 即可。所有 PNG 导出依赖都是可选的,缺失时降级为「只输出 SVG」,并打印一条提示告知如何安装以启用 PNG 导出。585586### 各依赖的选用建议5875881. **默认** → `cairosvg`(`pip install cairosvg` 一次,命令行一键转换,保真度好)5892. **无 Python** → `rsvg-convert`(适合简单平面色图,复杂 CSS 支持差)5903. **浏览器生成的 SVG 或像素级精确** → `puppeteer`(完整 Chrome 渲染管线,但装得最重)5914. **CJK 文本** → 浏览器渲染 SVG(GitHub/HTML 内嵌),或用 puppeteer 路径(cairosvg 对 CJK 字体回退不可靠,详见上文 SVG → PNG Conversion 节)592593## 输出自检清单594595交付前的最终检查清单(关键项;详细规则见上文 `Validation Checklist` 与 Workflow 第 11 步 `Visual self-review`):596597### SVG 语法合法性598- [ ] `python3 -c "import xml.etree.ElementTree as ET; ET.parse('file.svg')"` 通过599- [ ] 标签闭合、属性完整(运行 `./scripts/validate-svg.sh <svg-file>`)600- [ ] 箭头 marker 引用正确(`url(#arrowhead-...)`)601- [ ] 路径数据有效(无空 `d`、无悬空命令)602603### 视觉正确性604- [ ] 箭头不穿过组件内部605- [ ] 标签不与箭头线/其他标签碰撞606- [ ] 容器框不重叠607- [ ] 文本不溢出(`text.length × 7px ≤ shape_width - 16px`)608- [ ] 滤镜边界安全(`(element_x + element_width + filter_ext) ≤ viewBox_width`)609610### PNG 导出(如装了 cairosvg/rsvg/puppeteer)611- [ ] PNG 文件大小 > 0612- [ ] 视觉与 SVG 一致(如装了图像查看器,肉眼对比)613- [ ] CJK 字符正确渲染(cairosvg 路径下注意 CJK 字体回退问题,必要时切到 puppeteer 路径)614615如以上任一项失败,参考上文相应的修复指南("Common fixes" / "Validation Checklist" / "SVG → PNG Conversion")。616617## 相关技能618619本 skill 是 diagram 技能家族的一员,按输出格式分工,4 个 skill 互补但不重叠:620621| Skill | 输出形态 | 主用途 |622|---|---|---|623| `diagram-mermaid` | Mermaid 代码块(内联 Markdown) | GitHub README/issue/PR 嵌入,零依赖,GitHub 直接渲染 |624| `diagram-plantuml` | PlantUML 代码块(内联 Markdown) | UML/云架构/网络拓扑/安全/ArchiMate/BPMN/数据管道/IoT 等专业图 |625| `diagram-html` | 独立 HTML 文件 | 可分享的成品图,浏览器打开即用,双主题切换 + 浏览器导出菜单 |626| `diagram-image`(本 skill) | SVG + PNG 文件 | 命令行直接产出图片文件,适合 CI/批处理/嵌入不支持 SVG 的环境 |627628**选用决策**:629- 在 Markdown 里嵌入图、要源码可读、可 diff → `diagram-mermaid` 或 `diagram-plantuml`630- 要可交互的 HTML 成品、双主题切换、点按钮导出 → `diagram-html`631- 要命令行直接出 SVG/PNG 文件、CI/批处理 → 本 skill(`diagram-image`)632633**与 diagram-html 的关键区别**:虽然 archify(diagram-html)也能通过浏览器手动导出 PNG,但本 skill 是命令行直接产出文件——适合 CI/批处理/无浏览器环境。本 skill 独有:8 种视觉风格(flat-icon/dark-terminal/blueprint/notion-clean/glassmorphism/claude-official/openai/dark-luxury)、ER/use-case/timeline/comparison-matrix/agent-architecture 5 种图类型。本 skill 不如 diagram-html 的:无双主题切换、无 HTML 内导出菜单、不接受 Mermaid 输入。