Trending-skills diagram-design-editorial
Generate editorial-quality HTML+SVG diagrams (13 types) for blog posts and documentation using Claude Code, with brand-matched styling and no external dependencies.
git clone https://github.com/Aradotso/trending-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/Aradotso/trending-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/diagram-design-editorial" ~/.claude/skills/aradotso-trending-skills-diagram-design-editorial && rm -rf "$T"
skills/diagram-design-editorial/SKILL.mdDiagram Design — Editorial HTML+SVG Diagrams
Skill by 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
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:
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:
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:
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:
- Fetch your homepage
- Extract dominant palette + font stack
- Map values to semantic roles:
,paper
,ink
,muted
,accentlink - Run WCAG AA contrast checks (auto-adjusts failures)
- Show a proposed diff → write tokens to
references/style-guide.md
What gets extracted
| Detected from your site | Becomes |
|---|---|
background | token |
| Primary text color | token |
| Secondary / caption text | token |
| Cards or containers | token |
| Most-used brand color (CTA, link, heading) | token |
font family | font |
font family | font |
/ font | font |
Manual token override
Edit
references/style-guide.md directly:
| 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
,mutedpaper-2 - Target visual density: 4/10 — ruthlessly sparse
Focal nodes (coral tint)
<!-- 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)
<!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
<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
<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:
<!-- 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:
<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 | + |
| Onboarding | + + |
| Add annotation | + |
| Hand-drawn variant | + |
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
; the rest should bevar(--accent)var(--paper-2)
Colors don't match my site
- Run onboarding:
"onboard diagram-design to https://yoursite.com" - Or edit
directly with your hex valuesreferences/style-guide.md
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
for exact rendering:<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">
WCAG contrast failing on my brand colors
- Onboarding runs contrast checks automatically and proposes adjustments
- Manual fix: darken
or lightenink
until ratio ≥ 4.5:1 at 12pxpaper
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