Excalidraw Diagram Skill
Create Excalidraw scene JSON files and render them to SVG (and optionally PNG)
using the real Excalidraw engine. Output is hand-drawn style, vector, and the
SVG can be dragged back into excalidraw.com for further editing.
When to use
- User asks for a diagram, flowchart, architecture sketch, ER diagram, or
sequence diagram in a hand-drawn / sketchy style.
- User says "draw", "visualize", "diagram" and wants an image file out.
When NOT to use
- The user wants a pixel-perfect / corporate-clean diagram (use a vector tool).
- The user wants to EDIT interactively right now (point them to excalidraw.com).
- The diagram needs automatic layout (this skill does NOT auto-layout; you
compute coordinates by hand — see Known Limitations).
How it works (read this once)
- You write an
.excalidraw JSON scene file (elements with x/y/size/style).
scripts/render.py drives headless Chromium, loads the official
@excalidraw/excalidraw package, runs the scene through Excalidraw's
restore() + convertToExcalidrawElements() (to normalize fields and
recompute text metrics), then calls exportToSvg — so the render is the
genuine Excalidraw look, not a reimplementation.
- It outputs SVG (default) and/or PNG.
First-time setup
If rendering fails with a playwright/Chromium error, run the installer:
bash scripts/install.sh
This installs the playwright Python package and the Chromium binary
(~150MB, one-time). It does NOT require npm or node — Excalidraw itself is
loaded from the esm.sh CDN at render time (so an internet connection is needed
on render).
Creating a diagram
Plan the layout. Decide the shapes and how they connect. Sketch the
coordinates on paper first — this skill does not auto-layout, so you are
responsible for non-overlapping positions.
Build the scene JSON. Use references/element-templates.md for
copy-paste templates of each element type (rectangle, ellipse, diamond,
arrow, text). Start from references/examples/flowchart.excalidraw as a
working skeleton. Before laying out coordinates from scratch, check
references/examples/real-world/ — 16 production diagrams from published
articles (timelines, mental models, ladders, pipelines, gates), indexed by
diagram type in real-world/index.md. Copy the closest match as your
skeleton and edit it; their coordinates, spacing, and arrow routing are
field-tested.
ALIGNMENT HARD RULE (do not skip): For any text with a non-null
containerId, set x/y to the CENTER of the container
(container.x + container.width/2, container.y + container.height/2),
NOT the top-left corner. Excalidraw treats x/y as the text anchor when
textAlign="center"/verticalAlign="middle". Wrong coordinates = text
rendered outside the box. Free-floating text (containerId: null) keeps
top-left x/y. Two verification gates:
# Gate 1 — before rendering: anchors equal container centers
python3 scripts/check_alignment.py <file.excalidraw>
# Gate 2 — after rendering: text centers equal container centers
# (--scene filters out free-floating texts; omit it to check everything)
python3 scripts/render.py <file.excalidraw> --format svg
python3 scripts/verify_svg_alignment.py <file>.svg --scene <file.excalidraw>
Gate 2 is the authoritative check: exportToSvg renders each bound-text
group's visual center at translate + (rx, ry), so the renderer template
repositions labels to (container center - measured/2) before export.
Leave seed as null. Do not hardcode seed values. The render script
injects a random seed per element so identical shapes wobble differently —
that variation IS the hand-drawn look. Hardcoded seeds make the diagram
look stamped and dead.
Write the file with the .excalidraw extension, e.g. login-flow.excalidraw.
Render it:
python3 scripts/render.py login-flow.excalidraw
By default this produces login-flow.svg AND login-flow.png next to the
input. Options:
--format svg or --format png to get only one
--output path/stem to control output location (stem, no extension)
--scale 3 for higher-resolution PNG (SVG is always vector)
--keep-seed to reproduce a previous render exactly
Open the result (the SVG is preferred — crisp, editable). If you want
to revise, edit the .excalidraw JSON and re-render. You can also drag the
SVG back into excalidraw.com to edit interactively.
Layout tips (since there's no auto-layout)
- Give each shape ~40-80px of padding around it.
- Vertical flowcharts: stack shapes 150px apart vertically.
- Arrows: set
points relative to the arrow's own x,y, and bind both ends
via startBinding/endBinding so the arrow tracks the shapes.
- Use free-floating text (containerId null) for titles and section labels
rather than wrapping everything in boxes.
- See
examples/flowchart.excalidraw for concrete coordinate values that work.
Element types at a glance
| Type |
Use for |
rectangle |
processes, components, services (rounded via roundness:{type:3}) |
ellipse |
start/end states, external systems |
diamond |
decisions, conditionals |
arrow |
directed connections (binds to shapes) |
line |
undirected structural lines |
text |
labels inside shapes (containerId) or free-floating titles |
Full templates + the binding recipe: references/element-templates.md.
Default colors
Unless the user specifies a palette, use Excalidraw defaults:
#1e1e1e strokes; fills green #b2f2bb, blue #a5d8ff, yellow #ffec99,
red #ffc9c9, purple #eebefa. See the palette table in element-templates.md.
Known limitations (be honest with the user)
- No auto-layout. You compute all x/y coordinates. For >10 elements this
gets tedious; keep diagrams modest or the user should edit in excalidraw.com.
- Requires network on render (loads Excalidraw from esm.sh CDN). Offline
rendering is not supported by this version.
- No batch rendering. One file at a time.
- No built-in overlap detection. If shapes overlap, the render will show
it — review the output SVG and adjust coordinates.
Files
| Path |
Purpose |
scripts/render.py |
The renderer (run this) |
scripts/render_template.html |
Browser page that loads Excalidraw (don't edit casually) |
scripts/install.sh |
One-time dependency installer |
references/element-templates.md |
JSON templates for every element type |
references/examples/flowchart.excalidraw |
Working example scene |
references/examples/real-world/ |
16 production diagrams from published articles (index inside) |
1---2name: excalidraw3description: Use when the user wants to create or render hand-drawn style diagrams (flowcharts, architecture diagrams, ER diagrams, sequence diagrams, wireframes) as Excalidraw scenes, and export them to SVG/PNG. Triggers on words like "diagram", "flowchart", "draw", "architecture diagram", "excalidraw", or a request to visualize a system or process.4---56# Excalidraw Diagram Skill78Create Excalidraw scene JSON files and render them to SVG (and optionally PNG)9using the real Excalidraw engine. Output is hand-drawn style, vector, and the10SVG can be dragged back into excalidraw.com for further editing.1112## When to use1314- User asks for a diagram, flowchart, architecture sketch, ER diagram, or15 sequence diagram in a hand-drawn / sketchy style.16- User says "draw", "visualize", "diagram" and wants an image file out.1718## When NOT to use1920- The user wants a pixel-perfect / corporate-clean diagram (use a vector tool).21- The user wants to EDIT interactively right now (point them to excalidraw.com).22- The diagram needs automatic layout (this skill does NOT auto-layout; you23 compute coordinates by hand — see Known Limitations).2425## How it works (read this once)26271. You write an `.excalidraw` JSON scene file (elements with x/y/size/style).282. `scripts/render.py` drives headless Chromium, loads the official29 `@excalidraw/excalidraw` package, runs the scene through Excalidraw's30 `restore()` + `convertToExcalidrawElements()` (to normalize fields and31 recompute text metrics), then calls `exportToSvg` — so the render is the32 genuine Excalidraw look, not a reimplementation.333. It outputs SVG (default) and/or PNG.3435## First-time setup3637If rendering fails with a playwright/Chromium error, run the installer:3839```40bash scripts/install.sh41```4243This installs the `playwright` Python package and the Chromium binary44(~150MB, one-time). It does NOT require npm or node — Excalidraw itself is45loaded from the esm.sh CDN at render time (so an internet connection is needed46on render).4748## Creating a diagram49501. **Plan the layout.** Decide the shapes and how they connect. Sketch the51 coordinates on paper first — this skill does not auto-layout, so you are52 responsible for non-overlapping positions.53542. **Build the scene JSON.** Use `references/element-templates.md` for55 copy-paste templates of each element type (rectangle, ellipse, diamond,56 arrow, text). Start from `references/examples/flowchart.excalidraw` as a57 working skeleton. **Before laying out coordinates from scratch, check58 `references/examples/real-world/`** — 16 production diagrams from published59 articles (timelines, mental models, ladders, pipelines, gates), indexed by60 diagram type in `real-world/index.md`. Copy the closest match as your61 skeleton and edit it; their coordinates, spacing, and arrow routing are62 field-tested.63643. **ALIGNMENT HARD RULE (do not skip):** For any text with a non-null65 `containerId`, set `x`/`y` to the **CENTER of the container**66 (`container.x + container.width/2`, `container.y + container.height/2`),67 NOT the top-left corner. Excalidraw treats x/y as the text anchor when68 `textAlign="center"`/`verticalAlign="middle"`. Wrong coordinates = text69 rendered outside the box. Free-floating text (`containerId: null`) keeps70 top-left x/y. Two verification gates:7172 ```73 # Gate 1 — before rendering: anchors equal container centers74 python3 scripts/check_alignment.py <file.excalidraw>7576 # Gate 2 — after rendering: text centers equal container centers77 # (--scene filters out free-floating texts; omit it to check everything)78 python3 scripts/render.py <file.excalidraw> --format svg79 python3 scripts/verify_svg_alignment.py <file>.svg --scene <file.excalidraw>80 ```8182 Gate 2 is the authoritative check: exportToSvg renders each bound-text83 group's visual center at translate + (rx, ry), so the renderer template84 repositions labels to (container center - measured/2) before export.85864. **Leave `seed` as `null`.** Do not hardcode seed values. The render script87 injects a random seed per element so identical shapes wobble differently —88 that variation IS the hand-drawn look. Hardcoded seeds make the diagram89 look stamped and dead.90915. **Write the file** with the `.excalidraw` extension, e.g. `login-flow.excalidraw`.92936. **Render it:**9495 ```96 python3 scripts/render.py login-flow.excalidraw97 ```9899 By default this produces `login-flow.svg` AND `login-flow.png` next to the100 input. Options:101 - `--format svg` or `--format png` to get only one102 - `--output path/stem` to control output location (stem, no extension)103 - `--scale 3` for higher-resolution PNG (SVG is always vector)104 - `--keep-seed` to reproduce a previous render exactly1051067. **Open the result** (the SVG is preferred — crisp, editable). If you want107 to revise, edit the `.excalidraw` JSON and re-render. You can also drag the108 SVG back into excalidraw.com to edit interactively.109110## Layout tips (since there's no auto-layout)111112- Give each shape ~40-80px of padding around it.113- Vertical flowcharts: stack shapes 150px apart vertically.114- Arrows: set `points` relative to the arrow's own `x,y`, and bind both ends115 via `startBinding`/`endBinding` so the arrow tracks the shapes.116- Use free-floating text (containerId null) for titles and section labels117 rather than wrapping everything in boxes.118- See `examples/flowchart.excalidraw` for concrete coordinate values that work.119120## Element types at a glance121122| Type | Use for |123|------|---------|124| `rectangle` | processes, components, services (rounded via `roundness:{type:3}`) |125| `ellipse` | start/end states, external systems |126| `diamond` | decisions, conditionals |127| `arrow` | directed connections (binds to shapes) |128| `line` | undirected structural lines |129| `text` | labels inside shapes (`containerId`) or free-floating titles |130131Full templates + the binding recipe: `references/element-templates.md`.132133## Default colors134135Unless the user specifies a palette, use Excalidraw defaults:136`#1e1e1e` strokes; fills green `#b2f2bb`, blue `#a5d8ff`, yellow `#ffec99`,137red `#ffc9c9`, purple `#eebefa`. See the palette table in element-templates.md.138139## Known limitations (be honest with the user)140141- **No auto-layout.** You compute all x/y coordinates. For >10 elements this142 gets tedious; keep diagrams modest or the user should edit in excalidraw.com.143- **Requires network on render** (loads Excalidraw from esm.sh CDN). Offline144 rendering is not supported by this version.145- **No batch rendering.** One file at a time.146- **No built-in overlap detection.** If shapes overlap, the render will show147 it — review the output SVG and adjust coordinates.148149## Files150151| Path | Purpose |152|------|---------|153| `scripts/render.py` | The renderer (run this) |154| `scripts/render_template.html` | Browser page that loads Excalidraw (don't edit casually) |155| `scripts/install.sh` | One-time dependency installer |156| `references/element-templates.md` | JSON templates for every element type |157| `references/examples/flowchart.excalidraw` | Working example scene |158| `references/examples/real-world/` | 16 production diagrams from published articles (index inside) |