Loading...
Loading...
Generate editorial-quality HTML+SVG diagrams (13 types) for blog posts and documentation using Claude Code, with brand-matched styling and no external dependencies.
npx skill4agent add aradotso/trending-skills diagram-design-editorialSkill by ara.so — Daily 2026 Skills collection.
git clone git@github.com:cathrynlavery/diagram-design.git ~/.claude/skills/diagram-design
# restart Claude Code — skill registers as `diagram-design`git clone git@github.com:cathrynlavery/diagram-design.git ~/code/diagram-design
ln -s ~/code/diagram-design ~/.claude/skills/diagram-designopen ~/.claude/skills/diagram-design/assets/index.html| Type | Use when… |
|---|---|
| Architecture | Components + connections (services, APIs, infra) |
| Flowchart | Decision logic, yes/no branches |
| Sequence | Messages over time (OAuth, API calls, user flows) |
| State machine | States + transitions (order lifecycle, auth states) |
| ER / data model | Entities + fields + relationships |
| Timeline | Events on a horizontal or vertical axis |
| Swimlane | Cross-functional flows (who does what, when) |
| Quadrant | Two-axis positioning (impact vs effort, risk vs value) |
| Nested | Hierarchy by containment (layers inside layers) |
| Tree | Parent → children (org chart, file tree, decision tree) |
| Layer stack | Stacked abstractions (OSI model, tech stack) |
| Venn | Set overlap (2–3 circles) |
| Pyramid / funnel | Ranked hierarchy or conversion drop-off |
# In Claude Code — just describe what you need:
"Make me an architecture diagram: frontend, backend, Postgres, Redis cache."
"I need a quadrant of Q2 projects by impact vs effort."
"Give me a sequence diagram of the OAuth 2.0 handshake."
"Draw a state machine for an e-commerce order: pending → paid → shipped → delivered."
"Timeline of the Roman Empire's key turning points."cp assets/template.html my-diagram.html # minimal light
cp assets/template-full.html my-diagram.html # editorial with summary cards"onboard diagram-design to https://yoursite.com"paperinkmutedaccentlinkreferences/style-guide.md| Detected from your site | Becomes |
|---|---|
| |
| Primary text color | |
| Secondary / caption text | |
| Cards or containers | |
| Most-used brand color (CTA, link, heading) | |
| |
| |
| |
references/style-guide.md| Token | Value | Role |
|------------|-----------|-------------------------------|
| paper | #F8F5F0 | diagram background |
| ink | #1A1A1A | primary text, borders |
| muted | #6B6560 | secondary labels, grid lines |
| paper-2 | #EEEAE4 | card fills, lane backgrounds |
| accent | #B5523A | focal nodes, 1–2 per diagram |
| accent-fg | #FFFFFF | text on accent-colored nodes |style-guide.mdInstrument Serif → titles, italic editorial callouts
Geist Sans → node names, labels (primary UI text)
Geist Mono → technical sublabels (ports, URLs, field types, IDs)inkmutedpaper-2<!-- Accent node — use sparingly, 1–2 per diagram -->
<rect width="160" height="48" rx="6" fill="var(--accent)"/>
<text fill="var(--accent-fg)" font-family="Geist, sans-serif" font-size="13">
Primary Component
</text>
<!-- Standard node -->
<rect width="160" height="48" rx="6" fill="var(--paper-2)" stroke="var(--ink)" stroke-width="1"/>
<text fill="var(--ink)" font-family="Geist, sans-serif" font-size="13">
Secondary Component
</text><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
:root {
--paper: #F8F5F0;
--ink: #1A1A1A;
--muted: #6B6560;
--paper-2: #EEEAE4;
--accent: #B5523A;
--accent-fg:#FFFFFF;
}
body { background: var(--paper); margin: 0; padding: 40px; }
svg { display: block; }
</style>
</head>
<body>
<svg width="640" height="400" viewBox="0 0 640 400"
xmlns="http://www.w3.org/2000/svg"
font-family="Geist, system-ui, sans-serif">
<!-- Background -->
<rect width="640" height="400" fill="var(--paper)"/>
<!-- Title -->
<text x="32" y="40" font-size="15" font-weight="600" fill="var(--ink)">
Application Architecture
</text>
<!-- Focal node: API Gateway (accent) -->
<rect x="240" y="80" width="160" height="48" rx="6" fill="var(--accent)"/>
<text x="320" y="100" text-anchor="middle" font-size="12"
font-weight="600" fill="var(--accent-fg)">API Gateway</text>
<text x="320" y="116" text-anchor="middle" font-size="10"
fill="var(--accent-fg)" opacity="0.8">:443</text>
<!-- Standard node: Frontend -->
<rect x="60" y="196" width="160" height="48" rx="6"
fill="var(--paper-2)" stroke="var(--ink)" stroke-width="1"/>
<text x="140" y="216" text-anchor="middle" font-size="12"
font-weight="600" fill="var(--ink)">Frontend</text>
<text x="140" y="232" text-anchor="middle" font-size="10"
font-family="'Geist Mono', monospace" fill="var(--muted)">Next.js</text>
<!-- Standard node: Auth Service -->
<rect x="420" y="196" width="160" height="48" rx="6"
fill="var(--paper-2)" stroke="var(--ink)" stroke-width="1"/>
<text x="500" y="216" text-anchor="middle" font-size="12"
font-weight="600" fill="var(--ink)">Auth Service</text>
<text x="500" y="232" text-anchor="middle" font-size="10"
font-family="'Geist Mono', monospace" fill="var(--muted)">JWT / OAuth</text>
<!-- Standard node: Database -->
<rect x="240" y="312" width="160" height="48" rx="6"
fill="var(--paper-2)" stroke="var(--ink)" stroke-width="1"/>
<text x="320" y="332" text-anchor="middle" font-size="12"
font-weight="600" fill="var(--ink)">Postgres</text>
<text x="320" y="348" text-anchor="middle" font-size="10"
font-family="'Geist Mono', monospace" fill="var(--muted)">:5432</text>
<!-- Connections — 1px hairline, muted -->
<line x1="320" y1="128" x2="140" y2="196"
stroke="var(--muted)" stroke-width="1"/>
<line x1="320" y1="128" x2="500" y2="196"
stroke="var(--muted)" stroke-width="1"/>
<line x1="320" y1="128" x2="320" y2="312"
stroke="var(--muted)" stroke-width="1" stroke-dasharray="4 3"/>
<!-- Arrow markers -->
<defs>
<marker id="arrow" markerWidth="6" markerHeight="6"
refX="5" refY="3" orient="auto">
<path d="M0,0 L6,3 L0,6 Z" fill="var(--muted)"/>
</marker>
</defs>
</svg>
</body>
</html><svg width="520" height="520" viewBox="0 0 520 520"
xmlns="http://www.w3.org/2000/svg"
font-family="Geist, system-ui, sans-serif">
<rect width="520" height="520" fill="var(--paper)"/>
<!-- Axes -->
<line x1="64" y1="456" x2="456" y2="456"
stroke="var(--ink)" stroke-width="1"/> <!-- x-axis -->
<line x1="64" y1="64" x2="64" y2="456"
stroke="var(--ink)" stroke-width="1"/> <!-- y-axis -->
<!-- Quadrant dividers -->
<line x1="260" y1="64" x2="260" y2="456"
stroke="var(--muted)" stroke-width="1" stroke-dasharray="4 3"/>
<line x1="64" y1="260" x2="456" y2="260"
stroke="var(--muted)" stroke-width="1" stroke-dasharray="4 3"/>
<!-- Axis labels -->
<text x="260" y="488" text-anchor="middle" font-size="11"
fill="var(--muted)">← Low Effort · High Effort →</text>
<text x="20" y="260" text-anchor="middle" font-size="11"
fill="var(--muted)" transform="rotate(-90, 20, 260)">
← Low Impact · High Impact →
</text>
<!-- Quadrant labels -->
<text x="162" y="88" text-anchor="middle" font-size="10"
font-weight="600" fill="var(--muted)" letter-spacing="0.05em">QUICK WINS</text>
<text x="358" y="88" text-anchor="middle" font-size="10"
font-weight="600" fill="var(--muted)" letter-spacing="0.05em">MAJOR PROJECTS</text>
<text x="162" y="448" text-anchor="middle" font-size="10"
font-weight="600" fill="var(--muted)" letter-spacing="0.05em">FILL-INS</text>
<text x="358" y="448" text-anchor="middle" font-size="10"
font-weight="600" fill="var(--muted)" letter-spacing="0.05em">THANKLESS TASKS</text>
<!-- Focal item (accent) -->
<circle cx="148" cy="148" r="28" fill="var(--accent)" opacity="0.9"/>
<text x="148" y="144" text-anchor="middle" font-size="10"
font-weight="600" fill="var(--accent-fg)">Auth</text>
<text x="148" y="158" text-anchor="middle" font-size="9"
fill="var(--accent-fg)" opacity="0.85">redesign</text>
<!-- Standard items -->
<circle cx="200" cy="200" r="22" fill="var(--paper-2)"
stroke="var(--ink)" stroke-width="1"/>
<text x="200" y="196" text-anchor="middle" font-size="9"
fill="var(--ink)">Dark</text>
<text x="200" y="208" text-anchor="middle" font-size="9"
fill="var(--ink)">mode</text>
<circle cx="340" cy="160" r="26" fill="var(--paper-2)"
stroke="var(--ink)" stroke-width="1"/>
<text x="340" y="156" text-anchor="middle" font-size="9"
fill="var(--ink)">API v2</text>
<text x="340" y="168" text-anchor="middle" font-size="9"
fill="var(--ink)">migration</text>
</svg><svg width="600" height="360" viewBox="0 0 600 360"
xmlns="http://www.w3.org/2000/svg"
font-family="Geist, system-ui, sans-serif">
<rect width="600" height="360" fill="var(--paper)"/>
<!-- Actor boxes -->
<rect x="40" y="40" width="100" height="36" rx="6"
fill="var(--accent)"/>
<text x="90" y="63" text-anchor="middle" font-size="12"
font-weight="600" fill="var(--accent-fg)">Browser</text>
<rect x="248" y="40" width="100" height="36" rx="6"
fill="var(--paper-2)" stroke="var(--ink)" stroke-width="1"/>
<text x="298" y="63" text-anchor="middle" font-size="12"
font-weight="600" fill="var(--ink)">Auth Server</text>
<rect x="456" y="40" width="100" height="36" rx="6"
fill="var(--paper-2)" stroke="var(--ink)" stroke-width="1"/>
<text x="506" y="63" text-anchor="middle" font-size="12"
font-weight="600" fill="var(--ink)">API</text>
<!-- Lifelines -->
<line x1="90" y1="76" x2="90" y2="340"
stroke="var(--muted)" stroke-width="1" stroke-dasharray="4 3"/>
<line x1="298" y1="76" x2="298" y2="340"
stroke="var(--muted)" stroke-width="1" stroke-dasharray="4 3"/>
<line x1="506" y1="76" x2="506" y2="340"
stroke="var(--muted)" stroke-width="1" stroke-dasharray="4 3"/>
<!-- Messages -->
<defs>
<marker id="seq-arrow" markerWidth="6" markerHeight="6"
refX="5" refY="3" orient="auto">
<path d="M0,0 L6,3 L0,6 Z" fill="var(--ink)"/>
</marker>
</defs>
<!-- 1: redirect to auth -->
<line x1="90" y1="120" x2="292" y2="120"
stroke="var(--ink)" stroke-width="1"
marker-end="url(#seq-arrow)"/>
<text x="194" y="114" text-anchor="middle" font-size="10"
fill="var(--muted)">GET /authorize</text>
<!-- 2: login page -->
<line x1="298" y1="152" x2="96" y2="152"
stroke="var(--ink)" stroke-width="1" stroke-dasharray="4 3"
marker-end="url(#seq-arrow)"/>
<text x="194" y="146" text-anchor="middle" font-size="10"
fill="var(--muted)">302 → login page</text>
<!-- 3: credentials -->
<line x1="90" y1="188" x2="292" y2="188"
stroke="var(--ink)" stroke-width="1"
marker-end="url(#seq-arrow)"/>
<text x="194" y="182" text-anchor="middle" font-size="10"
fill="var(--muted)">POST credentials</text>
<!-- 4: code -->
<line x1="298" y1="220" x2="96" y2="220"
stroke="var(--ink)" stroke-width="1" stroke-dasharray="4 3"
marker-end="url(#seq-arrow)"/>
<text x="194" y="214" text-anchor="middle" font-size="10"
fill="var(--muted)">302 + code</text>
<!-- 5: exchange code -->
<line x1="90" y1="260" x2="500" y2="260"
stroke="var(--ink)" stroke-width="1"
marker-end="url(#seq-arrow)"/>
<text x="295" y="254" text-anchor="middle" font-size="10"
fill="var(--muted)">GET /resource + Bearer token</text>
<!-- 6: response -->
<line x1="506" y1="292" x2="96" y2="292"
stroke="var(--ink)" stroke-width="1" stroke-dasharray="4 3"
marker-end="url(#seq-arrow)"/>
<text x="295" y="286" text-anchor="middle" font-size="10"
fill="var(--muted)">200 OK + data</text>
</svg><!-- Editorial annotation callout -->
<defs>
<style>
.callout-text {
font-family: 'Instrument Serif', Georgia, serif;
font-style: italic;
font-size: 12px;
fill: var(--muted);
}
</style>
</defs>
<!-- Bézier leader line (dashed, 1px) -->
<path d="M 180,200 C 200,180 220,160 260,148"
stroke="var(--muted)" stroke-width="1"
stroke-dasharray="3 3" fill="none"/>
<!-- Callout text — sits in margin -->
<text x="80" y="204" class="callout-text">only runs on cold start</text><defs>
<filter id="sketchy" x="-5%" y="-5%" width="110%" height="110%">
<feTurbulence type="fractalNoise" baseFrequency="0.04"
numOctaves="3" seed="2" result="noise"/>
<feDisplacementMap in="SourceGraphic" in2="noise"
scale="2.5" xChannelSelector="R"
yChannelSelector="G"/>
</filter>
</defs>
<!-- Apply to any element -->
<rect x="100" y="100" width="160" height="48" rx="6"
fill="var(--paper-2)" stroke="var(--ink)" stroke-width="1.5"
filter="url(#sketchy)"/>diagram-design/
├── SKILL.md # type selection guide, design rules
├── references/
│ ├── style-guide.md # color + font tokens (edit for your brand)
│ ├── onboarding.md # URL-to-tokens extraction spec
│ ├── type-architecture.md
│ ├── type-flowchart.md
│ ├── type-sequence.md
│ ├── type-state.md
│ ├── type-er.md
│ ├── type-timeline.md
│ ├── type-swimlane.md
│ ├── type-quadrant.md
│ ├── type-nested.md
│ ├── type-tree.md
│ ├── type-layers.md
│ ├── type-venn.md
│ ├── type-pyramid.md
│ ├── primitive-annotation.md
│ └── primitive-sketchy.md
├── assets/
│ ├── index.html # live gallery, all 13 types, 3 variants each
│ ├── template.html # minimal light scaffold
│ ├── template-full.html # editorial with summary cards
│ └── example-<type>.html # 39 files: 3 variants × 13 types
└── docs/screenshots/| Request | Files loaded |
|---|---|
| Any specific type | |
| Onboarding | |
| Add annotation | |
| Hand-drawn variant | |
# Decision logic with yes/no branches → flowchart
"Should I use X?" branching → flowchart
# Time-ordered messages between actors → sequence
OAuth, webhooks, API calls → sequence
# Lifecycle with transitions → state machine
Order status, auth state, connection state → state machine
# Two-axis comparison → quadrant
Impact vs effort, risk vs value → quadrant
# Ranked importance → pyramid
Priority tiers, conversion funnel → pyramid
# System components and how they connect → architecture
Services, databases, queues → architecture# Accent = 1–2 nodes only — the main point of the diagram
# If everything is accent, nothing is accent
# Wrong: 5 accent nodes in a 7-node diagram
# Right: 1 accent node (the bottleneck / the thing that matters)# Target: 4/10 density
# 5 nodes is usually enough
# 8 nodes is usually too many
# 12 nodes → split into two diagrams or use layers/nested
# Eliminate any node the reader doesn't need to understand the pointvar(--accent)var(--paper-2)"onboard diagram-design to https://yoursite.com"references/style-guide.md<head><link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=instrument-serif:400,400i|geist:400,600&display=swap"
rel="stylesheet">inkpaper"Make this a swimlane, not a flowchart — rows for Design, Eng, PM"