Get the FREE Ultimate OpenClaw Setup Guide →

excalidraw

npx machina-cli add skill tslateman/duet/excalidraw --openclaw
Files (1)
SKILL.md
12.0 KB

Excalidraw 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 display
  • color: "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 ellipse
  • end(label="End") - Red ellipse
  • process(node_id, label, color="blue") - Blue rectangle
  • decision(node_id, label, color="yellow") - Yellow diamond
  • node(node_id, label, shape, color, width, height) - Generic node
  • connect(from_id, to_id, label=None) - Arrow between nodes
  • position_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 shape
  • service(id, label, x, y, color="violet")
  • user(id, label="User", x=100, y=100) - Gray ellipse
  • connect(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 lines
  • 1 - 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")
SchemePrimarySecondaryAccentWarningDanger
defaultbluegreenvioletyellowred
monochromeblackgraygraygrayblack
corporatebluetealvioletorangered
vibrantvioletcyanorangeyellowred
earthtealgreenorangeyellowred

Color Reference

ColorStroke HexUse For
blue#1971c2Primary components
green#2f9e44Success, databases
red#e03131Errors, end states
yellow#f08c00Warnings, decisions
orange#e8590cHighlights
violet#6741d9Services
cyan#0c8599Network
teal#099268Secondary
gray#868e96Users, actors
black#1e1e1eText, 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:

  1. Excalidraw.com: Go to https://excalidraw.com and drag the file onto the canvas
  2. VS Code: Install the "Excalidraw" extension, then open the file
  3. CLI: Use open filename.excalidraw on 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

  1. Positioning: Use a grid system. Start shapes at multiples of 50 or 100 for alignment
  2. Spacing: Leave 50-100px between elements for clean arrows
  3. Labels: Keep labels short (2-3 words). Use text boxes for longer descriptions
  4. Colors: Use consistent colors for similar components (all databases green, all services blue)
  5. Layout patterns:
    • Horizontal flow: x increases, y constant
    • Vertical flow: y increases, x constant
    • Grid: Combine both for complex diagrams
  6. 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

  1. Step 1: Install and import the excalidraw_generator library; create a Diagram and start adding elements.
  2. Step 2: Build your diagram using box(), text_box(), and arrow_between(), then call save('my_diagram.excalidraw').
  3. 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.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers