Awesome-omni-skill authoring-excalidraw-files
Generate architecture diagrams as .excalidraw files. Use when the user asks to create architecture diagrams, system diagrams, visualize codebase structure, infrastructure diagrams, or generate excalidraw files.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/authoring-excalidraw-files" ~/.claude/skills/diegosouzapw-awesome-omni-skill-authoring-excalidraw-files && rm -rf "$T"
skills/development/authoring-excalidraw-files/SKILL.mdExcalidraw Architecture Diagram Generator
Generate architecture diagrams as
.excalidraw files from codebase analysis or user specifications.
Prerequisites
- No prerequisites - generates raw JSON
- For visual inspection: Open
files in excalidraw.com or VS Code extension.excalidraw
Quick Start
User asks:
"Generate an architecture diagram for this project" "Create an excalidraw diagram of the system" "Visualize this codebase structure" "Draw the infrastructure architecture"
Claude will:
- Analyze the codebase (any language/framework)
- Identify components, services, databases, APIs
- Map relationships and data flows
- Generate valid
JSON.excalidraw - Validate the structure
- User opens in excalidraw.com or VS Code for visual inspection
Critical Rules
1. NEVER Use Diamond Shapes
Diamond arrow connections are broken in raw Excalidraw JSON. Use styled rectangles instead:
| Semantic Meaning | Rectangle Style |
|---|---|
| Orchestrator/Hub | Coral (/) + strokeWidth: 3 |
| Decision Point | Orange (/) + dashed stroke |
2. Labels Require TWO Elements
The
label property does NOT work in raw JSON. Every labeled shape needs:
// 1. Shape with boundElements reference { "id": "my-box", "type": "rectangle", "boundElements": [{ "type": "text", "id": "my-box-text" }] } // 2. Separate text element with containerId { "id": "my-box-text", "type": "text", "containerId": "my-box", "text": "My Label" }
3. Elbow Arrows Need Three Properties
For 90-degree corners (not curved):
{ "type": "arrow", "roughness": 0, // Clean lines "roundness": null, // Sharp corners "elbowed": true // 90-degree mode }
4. Arrow Position at Shape Edge
Arrows must start/end at shape edges, not centers:
| Edge | Formula |
|---|---|
| Top | |
| Bottom | |
| Left | |
| Right | |
5. Arrow width/height = Bounding Box
points = [[0, 0], [-440, 0], [-440, 70]] width = 440 // max(abs(point[0])) height = 70 // max(abs(point[1]))
Minimal Working Example
Two boxes connected by an arrow (copy and adapt for any diagram):
{ "type": "excalidraw", "version": 2, "source": "claude-code-excalidraw-skill", "elements": [ { "id": "box-a", "type": "rectangle", "x": 100, "y": 100, "width": 160, "height": 80, "angle": 0, "strokeColor": "#1971c2", "backgroundColor": "#a5d8ff", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "groupIds": [], "frameId": null, "roundness": { "type": 3 }, "seed": 1, "version": 1, "versionNonce": 1, "isDeleted": false, "boundElements": [{ "type": "text", "id": "box-a-text" }], "updated": 1, "link": null, "locked": false }, { "id": "box-a-text", "type": "text", "x": 105, "y": 125, "width": 150, "height": 30, "angle": 0, "strokeColor": "#1e1e1e", "backgroundColor": "transparent", "fillStyle": "solid", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "groupIds": [], "frameId": null, "roundness": null, "seed": 2, "version": 1, "versionNonce": 2, "isDeleted": false, "boundElements": null, "updated": 1, "link": null, "locked": false, "text": "Frontend", "fontSize": 16, "fontFamily": 1, "textAlign": "center", "verticalAlign": "middle", "containerId": "box-a", "originalText": "Frontend", "lineHeight": 1.25 }, { "id": "box-b", "type": "rectangle", "x": 100, "y": 280, "width": 160, "height": 80, "angle": 0, "strokeColor": "#7048e8", "backgroundColor": "#d0bfff", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "groupIds": [], "frameId": null, "roundness": { "type": 3 }, "seed": 3, "version": 1, "versionNonce": 3, "isDeleted": false, "boundElements": [{ "type": "text", "id": "box-b-text" }], "updated": 1, "link": null, "locked": false }, { "id": "box-b-text", "type": "text", "x": 105, "y": 305, "width": 150, "height": 30, "angle": 0, "strokeColor": "#1e1e1e", "backgroundColor": "transparent", "fillStyle": "solid", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "groupIds": [], "frameId": null, "roundness": null, "seed": 4, "version": 1, "versionNonce": 4, "isDeleted": false, "boundElements": null, "updated": 1, "link": null, "locked": false, "text": "API Server", "fontSize": 16, "fontFamily": 1, "textAlign": "center", "verticalAlign": "middle", "containerId": "box-b", "originalText": "API Server", "lineHeight": 1.25 }, { "id": "arrow-a-b", "type": "arrow", "x": 180, "y": 180, "width": 0, "height": 100, "angle": 0, "strokeColor": "#1971c2", "backgroundColor": "transparent", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 0, "opacity": 100, "groupIds": [], "frameId": null, "roundness": null, "seed": 5, "version": 1, "versionNonce": 5, "isDeleted": false, "boundElements": null, "updated": 1, "link": null, "locked": false, "points": [[0, 0], [0, 100]], "lastCommittedPoint": null, "startBinding": null, "endBinding": null, "startArrowhead": null, "endArrowhead": "arrow", "elbowed": true } ], "appState": { "gridSize": 20, "viewBackgroundColor": "#ffffff" }, "files": {} }
Key structure notes:
- Each labeled shape needs TWO elements (shape + text with
)containerId - Arrow
is at source edge:x,y
=(100 + 160/2, 100 + 80)(180, 180) - Arrow
matches the vertical distance:height
=280 - 180100 - Elbow arrows:
,roughness: 0
,roundness: nullelbowed: true
Workflow
Step 1: Analyze Codebase
Discover components by looking for:
| Codebase Type | What to Look For |
|---|---|
| Monorepo | , workspace configs |
| Microservices | , k8s manifests |
| IaC | Terraform/Pulumi resource definitions |
| Backend API | Route definitions, controllers, DB models |
| Frontend | Component hierarchy, API calls |
Use tools:
forGlob
,**/package.json
,**/Dockerfile**/*.tf
forGrep
,app.get
,@ControllerCREATE TABLE
for README, config files, entry pointsRead
Step 2: Plan Layout
Vertical flow (most common):
Row 1: Users/Entry points (y: 100) Row 2: Frontend/Gateway (y: 250) Row 3: Orchestration (y: 400) Row 4: Services (y: 550) Row 5: Data layer (y: 700) Columns: x = 100, 300, 500, 700, 900 Element size: 160-200px x 80-90px
Step 3: Generate Elements
For each component:
- Create shape with unique
id - Add
referencing textboundElements - Create text with
containerId - Choose color based on type (see
)references/colors.md
Step 4: Add Connections
For each relationship:
- Calculate source edge point
- Calculate target edge point
- Determine routing pattern
- Create arrow with
arraypoints - Set width/height from bounding box
See
references/arrows.md for routing patterns.
Step 5: Validate
Run validation script before finalizing:
uv run scripts/validate_excalidraw.py diagram.excalidraw
Checks performed:
- Valid JSON structure
- boundElements/containerId pairs match
- No duplicate IDs
- No diamond shapes
- Elbow arrows have required properties
- Arrow width/height matches points
Step 6: Visual Inspection and Iterate
Open the
.excalidraw file for visual inspection:
- Web: Drag file to excalidraw.com
- VS Code: Install "Excalidraw" extension and open file
Note: Claude cannot see the visual output. The user must review the diagram and report any issues.
If the user reports issues:
- Identify the problem element from their description
- Fix the JSON
- Re-validate
- Ask user to re-inspect
- Repeat until correct
Validation Checklist
Before writing file:
- Every shape with label has boundElements + text element
- Text elements have containerId matching shape
- Multi-point arrows have
,elbowed: true
,roundness: nullroughness: 0 - Arrow x,y = source shape edge point
- Arrow final point offset reaches target edge
- Arrow width/height = bounding box of points
- No diamond shapes
- No duplicate IDs
- File is valid JSON
Common Issues
| Issue | Fix |
|---|---|
| Labels don't appear | Use TWO elements (shape + text), not property |
| Arrows curved | Add , , |
| Arrows floating | Calculate x,y from shape edge, not center |
| Arrows overlapping | Stagger start positions across edge |
| Arrows clipped | Set width/height to bounding box of points |
Reference Files
| File | Contents |
|---|---|
| JSON format, element types, text bindings, frames |
| Routing algorithm, patterns, bindings, staggering |
| Default, AWS, Azure, GCP, Kubernetes palettes |
Scripts
| Script | Purpose |
|---|---|
| Validate JSON structure before saving |
Usage:
# Validate uv run scripts/validate_excalidraw.py diagram.excalidraw # Validate with verbose arrow checks uv run scripts/validate_excalidraw.py diagram.excalidraw --verbose # Output as JSON uv run scripts/validate_excalidraw.py diagram.excalidraw --json
Output
- Location:
or user-specifieddocs/architecture/ - Filename: Descriptive, e.g.,
system-architecture.excalidraw - Testing: Open in https://excalidraw.com or VS Code extension