excalidraw
npx machina-cli add skill tslateman/duet/excalidraw --openclawExcalidraw Diagram Generator
Generate Excalidraw diagrams programmatically using Python. Produces professional-looking, editable .excalidraw files instead of ASCII art.
Output format: .excalidraw JSON files that can be:
- Opened at https://excalidraw.com (drag and drop the file)
- Edited in VS Code with the Excalidraw extension
- Exported to SVG/PNG for embedding in documentation
Token cost note: Excalidraw JSON is verbose (4,000-22,000+ tokens per file). Delegate diagram generation to subagents when context is tight.
Quick Start
Method 1: Direct Python Script (Recommended)
Write a Python script using the generator library and run it:
#!/usr/bin/env python3
import sys, os
sys.path.insert(0, os.path.expanduser("~/.claude/plugins/duet/skills/excalidraw/scripts"))
from excalidraw_generator import Diagram, Flowchart, ArchitectureDiagram
# Create your diagram
d = Diagram()
box1 = d.box(100, 100, "Step 1", color="blue")
box2 = d.box(300, 100, "Step 2", color="green")
d.arrow_between(box1, box2, "next")
d.save("my_diagram.excalidraw")
Run with:
python3 /path/to/your_script.py
Method 2: Inline Python Execution
python3 -c "
import sys, os
sys.path.insert(0, os.path.expanduser('~/.claude/plugins/duet/skills/excalidraw/scripts'))
from excalidraw_generator import Diagram
d = Diagram()
a = d.box(100, 100, 'Hello', color='blue')
b = d.box(300, 100, 'World', color='green')
d.arrow_between(a, b)
d.save('hello.excalidraw')
print('Created: hello.excalidraw')
"
API Reference
Diagram Class
The base class for all diagrams.
from excalidraw_generator import Diagram
d = Diagram(background="#ffffff") # white background
Methods
box(x, y, label, width=150, height=60, color="blue", shape="rectangle", font_size=18)
Create a labeled shape. Returns an Element for connecting.
x, y: Position (top-left corner)label: Text to displaycolor: "blue", "green", "red", "yellow", "orange", "violet", "cyan", "teal", "gray", "black"shape: "rectangle", "ellipse", "diamond"
box1 = d.box(100, 100, "Process A", color="blue")
box2 = d.box(100, 200, "Decision?", color="yellow", shape="diamond")
text_box(x, y, content, font_size=20, color="black")
Create standalone text.
d.text_box(100, 50, "System Architecture", font_size=28, color="black")
arrow_between(source, target, label=None, color="black", from_side="auto", to_side="auto")
Draw an arrow between two elements.
from_side,to_side: "auto", "left", "right", "top", "bottom"
d.arrow_between(box1, box2, "sends data")
d.arrow_between(box1, box3, from_side="bottom", to_side="top")
line_between(source, target, color="black")
Draw a line (no arrowhead) between elements.
save(path)
Save the diagram. Extension .excalidraw added if not present.
d.save("output/my_diagram") # Creates output/my_diagram.excalidraw
Flowchart Class
Specialized for flowcharts with automatic positioning.
from excalidraw_generator import Flowchart
fc = Flowchart(direction="vertical", spacing=80)
fc.start("Begin")
fc.process("p1", "Process Data")
fc.decision("d1", "Valid?")
fc.process("p2", "Save")
fc.end("Done")
fc.connect("__start__", "p1")
fc.connect("p1", "d1")
fc.connect("d1", "p2", label="Yes")
fc.connect("d1", "__end__", label="No")
fc.save("flowchart.excalidraw")
Methods
start(label="Start")- Green ellipseend(label="End")- Red ellipseprocess(node_id, label, color="blue")- Blue rectangledecision(node_id, label, color="yellow")- Yellow diamondnode(node_id, label, shape, color, width, height)- Generic nodeconnect(from_id, to_id, label=None)- Arrow between nodesposition_at(x, y)- Set position for next node
AutoLayoutFlowchart Class
For complex flowcharts with automatic hierarchical layout. Requires grandalf package (pip install grandalf).
from excalidraw_generator import AutoLayoutFlowchart, DiagramStyle, FlowchartStyle, LayoutConfig
fc = AutoLayoutFlowchart(
diagram_style=DiagramStyle(roughness=0),
flowchart_style=FlowchartStyle(decision_color="orange"),
layout_config=LayoutConfig(vertical_spacing=100, horizontal_spacing=80)
)
fc.add_node("start", "Start", shape="ellipse", color="green", node_type="terminal")
fc.add_node("process1", "Validate Input", node_type="process")
fc.add_node("check", "Is Valid?", shape="diamond", color="yellow", node_type="decision")
fc.add_node("success", "Process Data", node_type="process")
fc.add_node("error", "Show Error", color="red", node_type="process")
fc.add_node("end", "End", shape="ellipse", color="red", node_type="terminal")
fc.add_edge("start", "process1")
fc.add_edge("process1", "check")
fc.add_edge("check", "success", label="Yes")
fc.add_edge("check", "error", label="No")
fc.add_edge("success", "end")
fc.add_edge("error", "process1", label="Retry")
result = fc.compute_layout(two_column=True, target_aspect_ratio=0.8)
fc.save("auto_flowchart.excalidraw")
ArchitectureDiagram Class
For system architecture diagrams.
from excalidraw_generator import ArchitectureDiagram
arch = ArchitectureDiagram()
arch.user("user", "User", x=100, y=200)
arch.component("frontend", "React App", x=250, y=200, color="blue")
arch.service("api", "API Gateway", x=450, y=200, color="violet")
arch.database("db", "PostgreSQL", x=650, y=200, color="green")
arch.connect("user", "frontend", "HTTPS")
arch.connect("frontend", "api", "REST")
arch.connect("api", "db", "SQL")
arch.save("architecture.excalidraw")
Methods
component(id, label, x, y, width=150, height=80, color="blue")database(id, label, x, y, color="green")- Ellipse shapeservice(id, label, x, y, color="violet")user(id, label="User", x=100, y=100)- Gray ellipseconnect(from_id, to_id, label=None, bidirectional=False)
Configuration & Styling
DiagramStyle - Global Appearance
from excalidraw_generator import Diagram, DiagramStyle
d = Diagram(diagram_style=DiagramStyle(
roughness=0, # 0=clean, 1=hand-drawn, 2=rough sketch
stroke_style="solid", # "solid", "dashed", "dotted"
stroke_width=2, # Line thickness (1-4)
color_scheme="corporate" # Named color scheme
))
Roughness levels:
0- Architect: Clean, precise lines1- Artist: Normal hand-drawn look (default)2- Cartoonist: Rough, sketchy appearance
Color Schemes
d = Diagram(diagram_style=DiagramStyle(color_scheme="vibrant"))
primary = d.scheme_color("primary")
secondary = d.scheme_color("secondary")
accent = d.scheme_color("accent")
warning = d.scheme_color("warning")
danger = d.scheme_color("danger")
neutral = d.scheme_color("neutral")
| Scheme | Primary | Secondary | Accent | Warning | Danger |
|---|---|---|---|---|---|
| default | blue | green | violet | yellow | red |
| monochrome | black | gray | gray | gray | black |
| corporate | blue | teal | violet | orange | red |
| vibrant | violet | cyan | orange | yellow | red |
| earth | teal | green | orange | yellow | red |
Color Reference
| Color | Stroke Hex | Use For |
|---|---|---|
blue | #1971c2 | Primary components |
green | #2f9e44 | Success, databases |
red | #e03131 | Errors, end states |
yellow | #f08c00 | Warnings, decisions |
orange | #e8590c | Highlights |
violet | #6741d9 | Services |
cyan | #0c8599 | Network |
teal | #099268 | Secondary |
gray | #868e96 | Users, actors |
black | #1e1e1e | Text, arrows |
Complete Examples
Example 1: Simple Flow
import sys, os
sys.path.insert(0, os.path.expanduser("~/.claude/plugins/duet/skills/excalidraw/scripts"))
from excalidraw_generator import Diagram
d = Diagram()
d.text_box(200, 30, "Data Processing Pipeline", font_size=24)
input_box = d.box(100, 100, "Input", color="gray")
process = d.box(300, 100, "Process", color="blue")
output = d.box(500, 100, "Output", color="green")
d.arrow_between(input_box, process, "raw data")
d.arrow_between(process, output, "results")
d.save("pipeline.excalidraw")
Example 2: Decision Flowchart
import sys, os
sys.path.insert(0, os.path.expanduser("~/.claude/plugins/duet/skills/excalidraw/scripts"))
from excalidraw_generator import Flowchart
fc = Flowchart(direction="vertical", spacing=100)
fc.start("User Request")
fc.process("auth", "Authenticate")
fc.decision("valid", "Valid Token?")
fc.position_at(300, 340)
fc.process("proc", "Process Request")
fc.process("resp", "Return Response")
fc.position_at(100, 340)
fc.process("err", "Return 401")
fc.connect("__start__", "auth")
fc.connect("auth", "valid")
fc.connect("valid", "proc", "Yes")
fc.connect("valid", "err", "No")
fc.connect("proc", "resp")
fc.save("auth_flow.excalidraw")
Example 3: Microservices Architecture
import sys, os
sys.path.insert(0, os.path.expanduser("~/.claude/plugins/duet/skills/excalidraw/scripts"))
from excalidraw_generator import ArchitectureDiagram
arch = ArchitectureDiagram()
arch.user("client", "Client", x=400, y=50)
arch.service("gateway", "API Gateway", x=350, y=180, color="violet")
arch.service("auth", "Auth Service", x=100, y=350, color="blue")
arch.service("users", "User Service", x=300, y=350, color="blue")
arch.service("orders", "Order Service", x=500, y=350, color="blue")
arch.service("notify", "Notification", x=700, y=350, color="cyan")
arch.database("authdb", "Auth DB", x=100, y=500, color="green")
arch.database("userdb", "User DB", x=300, y=500, color="green")
arch.database("orderdb", "Order DB", x=500, y=500, color="green")
arch.component("queue", "Message Queue", x=600, y=450, color="orange")
arch.connect("client", "gateway", "HTTPS")
arch.connect("gateway", "auth", "gRPC")
arch.connect("gateway", "users", "gRPC")
arch.connect("gateway", "orders", "gRPC")
arch.connect("auth", "authdb", "SQL")
arch.connect("users", "userdb", "SQL")
arch.connect("orders", "orderdb", "SQL")
arch.connect("orders", "queue", "publish")
arch.connect("queue", "notify", "subscribe")
arch.save("microservices.excalidraw")
Viewing the Output
After generating a .excalidraw file:
- Excalidraw.com: Go to https://excalidraw.com and drag the file onto the canvas
- VS Code: Install the "Excalidraw" extension, then open the file
- CLI: Use
open filename.excalidrawon macOS
Exporting to PNG
# First time setup
cd ~/.claude/plugins/duet/skills/excalidraw/scripts
npm install
npx playwright install chromium
# Export
node ~/.claude/plugins/duet/skills/excalidraw/scripts/export_playwright.js diagram.excalidraw output.png
Tips
- Positioning: Use a grid system. Start shapes at multiples of 50 or 100 for alignment
- Spacing: Leave 50-100px between elements for clean arrows
- Labels: Keep labels short (2-3 words). Use text boxes for longer descriptions
- Colors: Use consistent colors for similar components (all databases green, all services blue)
- Layout patterns:
- Horizontal flow: x increases, y constant
- Vertical flow: y increases, x constant
- Grid: Combine both for complex diagrams
- After generation: Open in Excalidraw to fine-tune positions and add hand-drawn elements
See Also
/mermaid- For inline documentation diagrams that render natively on GitHub/design- Design thinking applies to diagram composition and layout/prose- Diagram labels benefit from the same concision rules as prose
Source
git clone https://github.com/tslateman/duet/blob/main/skills/excalidraw/SKILL.mdView on GitHub Overview
Excalidraw Diagram Generator creates editable .excalidraw JSON diagrams from Python. It targets architecture diagrams, system designs, and flowcharts with a hand-drawn aesthetic. Outputs are editable, drag-and-drop friendly, and exportable to SVG/PNG for docs.
How This Skill Works
Use the excalidraw_generator library to build a Diagram (and optionally a Flowchart) by adding boxes, text, and arrows, then call save('file.excalidraw') to emit a .excalidraw JSON. The produced file can be opened in Excalidraw at excalidraw.com or edited in VS Code with the Excalidraw extension.
When to Use It
- You need architecture diagrams with a hand-drawn aesthetic for architecture overviews and presentations.
- You want system-design or data-flow diagrams that are editable and easy to tweak.
- You prefer a visual, drag-and-drop diagram instead of text-only Mermaid diagrams.
- You need to produce flowcharts where elements can be repositioned without manual formatting.
- You require a shareable, exportable diagram (SVG/PNG) built from reusable code.
Quick Start
- Step 1: Install and import the excalidraw_generator library; create a Diagram and start adding elements.
- Step 2: Build your diagram using box(), text_box(), and arrow_between(), then call save('my_diagram.excalidraw').
- Step 3: Open the resulting my_diagram.excalidraw in Excalidraw (or VS Code) and tweak as needed.
Best Practices
- Use Diagram for generic visuals and Flowchart for automatically positioned flowcharts.
- Plan a concise label set and a limited color palette to keep diagrams readable.
- Label relationships clearly with arrow_between; prefer small, modular components.
- Save as .excalidraw and export to SVG/PNG for documentation and decks.
- Beware of large Excalidraw files; JSON can be verbose—delegate generation if context is tight.
Example Use Cases
- Architecture diagram of a microservices app showing services and data flows.
- System design diagram illustrating component interactions and data paths.
- User onboarding flowchart with decision points and outcomes.
- CI/CD deployment pipeline diagram with stages and approvals.
- Network topology diagram with hand-drawn style for a sprint deck.