Generate editorial-quality HTML+SVG diagrams (13 types) for blog posts and documentation using Claude Code, with brand-matched styling and no external dependencies.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add Aradotso/trending-skills --skill diagram-design-editorial --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Diagram Design Editorial?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aradotso-diagram-design-editorial-trending-skills)More formats (shields.io, HTML) on the badges page.
---
name: diagram-design-editorial
description: Generate editorial-quality HTML+SVG diagrams (13 types) for blog posts and documentation using Claude Code, with brand-matched styling and no external dependencies.
triggers:
- make me a diagram
- create an architecture diagram
- generate a flowchart
- I need a sequence diagram
- draw a state machine
- make an ER diagram
- create a timeline diagram
- onboard diagram-design to my site
---
# Diagram Design — Editorial HTML+SVG Diagrams
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
Editorial-quality diagrams for blog posts and documentation. 13 types, self-contained HTML+SVG, no build step, no Mermaid, no shadows. Brand-matched in 60 seconds by reading your website.
---
## Installation
```bash
git clone git@github.com:cathrynlavery/diagram-design.git ~/.claude/skills/diagram-design
# restart Claude Code — skill registers as `diagram-design`
```
Or symlink from another location:
```bash
git clone git@github.com:cathrynlavery/diagram-design.git ~/code/diagram-design
ln -s ~/code/diagram-design ~/.claude/skills/diagram-design
```
Browse all 13 types locally:
```bash
open ~/.claude/skills/diagram-design/assets/index.html
```
---
## The 13 Diagram Types
| 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 |
**Selection rule:** ask "would a reader learn more from this than from a well-written paragraph?" If no, don't draw. Default to deletion over addition.
---
## Quickstart
```
# 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."
```
Claude picks the right type, builds HTML, saves the file. To use a template directly:
```bash
cp assets/template.html my-diagram.html # minimal light
cp assets/template-full.html my-diagram.html # editorial with summary cards
```
---
## Brand Onboarding (60 seconds)
Without onboarding, diagrams render in neutral stone + rust (warm off-white paper, charcoal ink, rust-orange accent). Run onboarding to match your site:
```
"onboard diagram-design to https://yoursite.com"
```
Claude will:
1. Fetch your homepage
2. Extract dominant palette + font stack
3. Map values to semantic roles: `paper`, `ink`, `muted`, `accent`, `link`
4. Run WCAG AA contrast checks (auto-adjusts failures)
5. Show a proposed diff → write tokens to `references/style-guide.md`
### What gets extracted
| Detected from your site | Becomes |
|---|---|
| `<body>` background | `paper` token |
| Primary text color | `ink` token |
| Secondary / caption text | `muted` token |
| Cards or containers | `paper-2` token |
| Most-used brand color (CTA, link, heading) | `accent` token |
| `<h1>` font family | `title` font |
| `<body>` font family | `node-name` font |
| `<code>` / `<pre>` font | `sublabel` font |
### Manual token override
Edit `references/style-guide.md` directly:
```markdown
| 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 |
```
**First-run gate:** on first use in a new project, if `style-guide.md` is still at default, Claude pauses and asks: *"Run onboarding, paste tokens manually, or proceed with default?"*
---
## Design System Rules
Every diagram generated by this skill follows these non-negotiable constraints:
### Grid
- All coordinates, widths, gaps divisible by **4px** — prevents the AI-generated jitter
- No shadows anywhere
- Max border-radius: **10px**
- Borders: **1px hairline** only
### Typography (three families, three roles)
```
Instrument Serif → titles, italic editorial callouts
Geist Sans → node names, labels (primary UI text)
Geist Mono → technical sublabels (ports, URLs, field types, IDs)
```
Mono is for technical content specifically — not a blanket "dev aesthetic."
### Color discipline
- **One accent color** per diagram
- Accent reserved for **1–2 focal nodes** — the things the reader looks at first
- Everything else: `ink`, `muted`, `paper-2`
- Target visual density: **4/10** — ruthlessly sparse
### Focal nodes (coral tint)
```html
<!-- 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>
```
---
## Code Examples
### Architecture Diagram (minimal structure)
```html
<!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>
```
### Quadrant Diagram
```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>
```
### Sequence Diagram
```html
<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>
```
---
## Primitives
### Annotation Callout
Italic Instrument Serif + dashed Bézier leader for editorial asides in diagram margins:
```html
<!-- 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>
```
### Sketchy Filter (hand-drawn variant)
For essays and informal posts — not technical docs:
```html
<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)"/>
```
---
## File Structure
```
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/
```
**Context loading (what Claude reads per request):**
| Request | Files loaded |
|---|---|
| Any specific type | `SKILL.md` + `references/type-<name>.md` |
| Onboarding | `SKILL.md` + `onboarding.md` + `style-guide.md` |
| Add annotation | `SKILL.md` + `primitive-annotation.md` |
| Hand-drawn variant | `SKILL.md` + `primitive-sketchy.md` |
Only the relevant reference file loads — keeps context tight regardless of how many types exist.
---
## Common Patterns
### Choosing the right type
```
# 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
```
### Controlling focal emphasis
```
# 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)
```
### Density calibration
```
# 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 point
```
---
## Troubleshooting
**Diagrams look generic / AI-generated**
- Check all coordinates are divisible by 4 — misaligned grids are the tell
- Reduce node count; every node must earn its place
- Confirm only 1–2 nodes use `var(--accent)`; the rest should be `var(--paper-2)`
**Colors don't match my site**
- Run onboarding: `"onboard diagram-design to https://yoursite.com"`
- Or edit `references/style-guide.md` directly with your hex values
**Fonts not loading**
- Diagrams use system fallbacks by default — Geist and Instrument Serif only load if available
- Add Google Fonts or Bunny Fonts link in `<head>` for exact rendering:
```html
<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">
```
**WCAG contrast failing on my brand colors**
- Onboarding runs contrast checks automatically and proposes adjustments
- Manual fix: darken `ink` or lighten `paper` until ratio ≥ 4.5:1 at 12px
**Diagram too dense / cluttered**
- Delete nodes until it hurts, then delete one more
- Split into two diagrams: overview + detail
- Use a nested or layers type if you need to show hierarchy without individual connections
**Wrong type chosen**
- Override explicitly: `"Make this a swimlane, not a flowchart — rows for Design, Eng, PM"`
---
## When NOT to use this skill
- Quick ASCII/unicode diagrams for terminal or tweets → use wiretext
- Before/after comparisons → use a table
- Simple lists → use bullets
- Single-shape "diagrams" (one box, one label) → write the sentence instead
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!