16 KiB
SVG Template
Every diagram this skill produces starts with the same boilerplate: root <svg> element, an embedded <style> block that defines all color classes (including dark mode), and a <defs> block with the arrow marker. Copy this template verbatim into every diagram, then write your visual elements after the closing </defs>.
Why we embed the styles. In claude.ai's Imagine runtime, classes like c-blue, t, ts, th are pre-loaded by the host. A standalone SVG dropped into a WeChat article or a Notion page has no such host — it has to carry its own styles. The <style> block below reproduces the Imagine class system as self-contained CSS so every SVG renders correctly anywhere.
The template
Fill in H with the actual viewBox height computed from your content (see layout-math.md). Leave everything else exactly as written.
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 680 H" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif">
<style>
.t { font-size: 14px; font-weight: 400; fill: #2C2C2A; }
.ts { font-size: 12px; font-weight: 400; fill: #5F5E5A; }
.th { font-size: 14px; font-weight: 500; fill: #2C2C2A; }
.title { font-size: 20px; font-weight: 600; fill: #2C2C2A; }
.eyebrow { font-size: 10px; font-weight: 500; fill: #888780; letter-spacing: 1.2px; text-transform: uppercase; }
.caption { font-size: 12px; font-weight: 400; fill: #888780; font-style: italic; }
.anno { font-size: 12px; font-weight: 400; fill: #888780; }
.box { fill: #F1EFE8; stroke: #B4B2A9; stroke-width: 0.5; }
.row-alt { fill: #FFFFFF; stroke: #D3D1C7; stroke-width: 0.5; }
.arr { fill: none; stroke: #5F5E5A; stroke-width: 1.5; }
.arr-alt { fill: none; stroke: #5F5E5A; stroke-width: 1.5; stroke-dasharray: 5 4; }
.leader{ fill: none; stroke: #B4B2A9; stroke-width: 0.5; stroke-dasharray: 3 3; }
.lifeline { fill: none; stroke: #B4B2A9; stroke-width: 1; stroke-dasharray: 4 4; }
.arr-gray { fill: none; stroke: #5F5E5A; stroke-width: 1.5; }
.arr-blue { fill: none; stroke: #185FA5; stroke-width: 1.5; }
.arr-teal { fill: none; stroke: #0F6E56; stroke-width: 1.5; }
.arr-purple { fill: none; stroke: #534AB7; stroke-width: 1.5; }
.arr-coral { fill: none; stroke: #993C1D; stroke-width: 1.5; }
.arr-pink { fill: none; stroke: #993556; stroke-width: 1.5; }
.arr-amber { fill: none; stroke: #854F0B; stroke-width: 1.5; }
.arr-green { fill: none; stroke: #3B6D11; stroke-width: 1.5; }
.arr-red { fill: none; stroke: #A32D2D; stroke-width: 1.5; }
.c-gray > rect, .c-gray > circle, .c-gray > ellipse, rect.c-gray, circle.c-gray, ellipse.c-gray { fill: #F1EFE8; stroke: #5F5E5A; stroke-width: 0.5; }
.c-gray .th, .c-gray .t { fill: #444441; }
.c-gray .ts { fill: #5F5E5A; }
.c-blue > rect, .c-blue > circle, .c-blue > ellipse, rect.c-blue, circle.c-blue, ellipse.c-blue { fill: #E6F1FB; stroke: #185FA5; stroke-width: 0.5; }
.c-blue .th, .c-blue .t { fill: #0C447C; }
.c-blue .ts { fill: #185FA5; }
.c-teal > rect, .c-teal > circle, .c-teal > ellipse, rect.c-teal, circle.c-teal, ellipse.c-teal { fill: #E1F5EE; stroke: #0F6E56; stroke-width: 0.5; }
.c-teal .th, .c-teal .t { fill: #085041; }
.c-teal .ts { fill: #0F6E56; }
.c-purple > rect, .c-purple > circle, .c-purple > ellipse, rect.c-purple, circle.c-purple, ellipse.c-purple { fill: #EEEDFE; stroke: #534AB7; stroke-width: 0.5; }
.c-purple .th, .c-purple .t { fill: #3C3489; }
.c-purple .ts { fill: #534AB7; }
.c-coral > rect, .c-coral > circle, .c-coral > ellipse, rect.c-coral, circle.c-coral, ellipse.c-coral { fill: #FAECE7; stroke: #993C1D; stroke-width: 0.5; }
.c-coral .th, .c-coral .t { fill: #712B13; }
.c-coral .ts { fill: #993C1D; }
.c-pink > rect, .c-pink > circle, .c-pink > ellipse, rect.c-pink, circle.c-pink, ellipse.c-pink { fill: #FBEAF0; stroke: #993556; stroke-width: 0.5; }
.c-pink .th, .c-pink .t { fill: #72243E; }
.c-pink .ts { fill: #993556; }
.c-amber > rect, .c-amber > circle, .c-amber > ellipse, rect.c-amber, circle.c-amber, ellipse.c-amber { fill: #FAEEDA; stroke: #854F0B; stroke-width: 0.5; }
.c-amber .th, .c-amber .t { fill: #633806; }
.c-amber .ts { fill: #854F0B; }
.c-green > rect, .c-green > circle, .c-green > ellipse, rect.c-green, circle.c-green, ellipse.c-green { fill: #EAF3DE; stroke: #3B6D11; stroke-width: 0.5; }
.c-green .th, .c-green .t { fill: #27500A; }
.c-green .ts { fill: #3B6D11; }
.c-red > rect, .c-red > circle, .c-red > ellipse, rect.c-red, circle.c-red, ellipse.c-red { fill: #FCEBEB; stroke: #A32D2D; stroke-width: 0.5; }
.c-red .th, .c-red .t { fill: #791F1F; }
.c-red .ts { fill: #A32D2D; }
@media (prefers-color-scheme: dark) {
.t, .th { fill: #F1EFE8; }
.ts { fill: #B4B2A9; }
.title { fill: #F1EFE8; }
.eyebrow { fill: #888780; }
.caption { fill: #888780; }
.anno { fill: #888780; }
.box { fill: #2C2C2A; stroke: #888780; }
.row-alt { fill: #444441; stroke: #5F5E5A; }
.arr { stroke: #B4B2A9; }
.arr-alt { stroke: #B4B2A9; }
.leader { stroke: #888780; }
.lifeline { stroke: #5F5E5A; }
.arr-gray { stroke: #B4B2A9; }
.arr-blue { stroke: #85B7EB; }
.arr-teal { stroke: #5DCAA5; }
.arr-purple { stroke: #AFA9EC; }
.arr-coral { stroke: #F0997B; }
.arr-pink { stroke: #ED93B1; }
.arr-amber { stroke: #EF9F27; }
.arr-green { stroke: #97C459; }
.arr-red { stroke: #F09595; }
.c-gray > rect, .c-gray > circle, .c-gray > ellipse, rect.c-gray, circle.c-gray, ellipse.c-gray { fill: #444441; stroke: #B4B2A9; }
.c-gray .th, .c-gray .t { fill: #F1EFE8; }
.c-gray .ts { fill: #D3D1C7; }
.c-blue > rect, .c-blue > circle, .c-blue > ellipse, rect.c-blue, circle.c-blue, ellipse.c-blue { fill: #0C447C; stroke: #85B7EB; }
.c-blue .th, .c-blue .t { fill: #B5D4F4; }
.c-blue .ts { fill: #85B7EB; }
.c-teal > rect, .c-teal > circle, .c-teal > ellipse, rect.c-teal, circle.c-teal, ellipse.c-teal { fill: #085041; stroke: #5DCAA5; }
.c-teal .th, .c-teal .t { fill: #9FE1CB; }
.c-teal .ts { fill: #5DCAA5; }
.c-purple > rect, .c-purple > circle, .c-purple > ellipse, rect.c-purple, circle.c-purple, ellipse.c-purple { fill: #3C3489; stroke: #AFA9EC; }
.c-purple .th, .c-purple .t { fill: #CECBF6; }
.c-purple .ts { fill: #AFA9EC; }
.c-coral > rect, .c-coral > circle, .c-coral > ellipse, rect.c-coral, circle.c-coral, ellipse.c-coral { fill: #712B13; stroke: #F0997B; }
.c-coral .th, .c-coral .t { fill: #F5C4B3; }
.c-coral .ts { fill: #F0997B; }
.c-pink > rect, .c-pink > circle, .c-pink > ellipse, rect.c-pink, circle.c-pink, ellipse.c-pink { fill: #72243E; stroke: #ED93B1; }
.c-pink .th, .c-pink .t { fill: #F4C0D1; }
.c-pink .ts { fill: #ED93B1; }
.c-amber > rect, .c-amber > circle, .c-amber > ellipse, rect.c-amber, circle.c-amber, ellipse.c-amber { fill: #633806; stroke: #EF9F27; }
.c-amber .th, .c-amber .t { fill: #FAC775; }
.c-amber .ts { fill: #EF9F27; }
.c-green > rect, .c-green > circle, .c-green > ellipse, rect.c-green, circle.c-green, ellipse.c-green { fill: #27500A; stroke: #97C459; }
.c-green .th, .c-green .t { fill: #C0DD97; }
.c-green .ts { fill: #97C459; }
.c-red > rect, .c-red > circle, .c-red > ellipse, rect.c-red, circle.c-red, ellipse.c-red { fill: #791F1F; stroke: #F09595; }
.c-red .th, .c-red .t { fill: #F7C1C1; }
.c-red .ts { fill: #F09595; }
}
</style>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</marker>
</defs>
<!-- your visual elements go here -->
</svg>
Poster-flowchart utility classes
Four classes are available for poster-style flowcharts (see flowchart.md → "Poster flowchart pattern"). These are optional — simple flowcharts, structural, illustrative, and sequence diagrams should ignore them and pay nothing beyond ~300 bytes of unused CSS.
| Class | Size | Use for |
|---|---|---|
.title |
20px 600 | Diagram-level title. Used ONCE at the top when the topic has a short mechanism name. |
.eyebrow |
10px 500 | Small uppercase section dividers between groups of stages. Letter-spaced, muted gray. |
.caption |
12px italic | Footer hook line at the bottom of the diagram. One line, italic, muted gray. |
.anno |
12px | Side-column annotation text — "sees: X / fresh context" notes beside a box. Muted gray. |
All four work in both light and dark mode via the template's @media block. Never use .title, .eyebrow, or .caption inside a regular box — they're meta-labels for the whole diagram, not cell content.
Sequence-diagram utility classes
The <style> block also defines .lifeline (dashed vertical lifeline for sequence diagrams) and nine .arr-{ramp} colored-arrow utilities (arr-gray, arr-blue, arr-teal, arr-purple, arr-coral, arr-pink, arr-amber, arr-green, arr-red). These are only used by sequence diagrams, where each actor's messages inherit the actor's ramp color. Flowchart, structural, and illustrative diagrams ignore them and pay nothing beyond ~600 bytes of unused CSS. Arrow marker url(#arrow) uses context-stroke so arrowheads automatically match the colored stroke — never set fill on these paths.
The .row-alt alternating-row utility
A paired companion to .box for comparison-matrix tables (see structural.md → "Comparison-matrix sub-pattern"). The two classes alternate to create zebra striping across rows of a matrix so the eye can follow a row across 4–5 columns without drifting into the next row.
- Light mode:
.box= cream#F1EFE8,.row-alt= pure white#FFFFFF— the contrast between the two fills is deliberately low (one ramp stop) so the striping is legible but doesn't compete with the cell text. - Dark mode:
.box= near-black#2C2C2A,.row-alt= one step lighter#444441— same principle, inverted.
Alternate rows by applying .box to odd rows and .row-alt to even rows, or vice versa. Do not use either class to hint at semantic status (active / inactive / warning) — that's what c-{ramp} is for. .row-alt is purely for visual rhythm.
The .arr-alt alternative-flow utility
The <style> block also defines .arr-alt — a 1.5px dashed connector for alternative, optional, or weak flows. Same weight as .arr, but the dash pattern (5 4) visually demotes the connector so a reader scans the solid arrows first.
Use it when semantics call for it, not as decoration:
- Flowchart — the Fail branch out of a Gate, the unchosen paths in a router fan-out, the "Stop" return from an agent loop, or any conditional/optional edge that only fires part of the time.
- Illustrative — the spokes in a central-subject-plus-radial-attachments layout (LLM hub to Retrieval / Tools / Memory), where the attachments are available capabilities rather than guaranteed steps.
Do not use .arr-alt as a decorative stroke, and do not use it inside sequence diagrams (every sequence message is either there or not — there is no "maybe" in a protocol). .arr-alt is distinct from .leader: .leader is 0.5px hair-dashed for illustrative callout lines, .arr-alt is 1.5px mid-dashed for connectors that carry meaning.
Rules for using the template
- viewBox width is always 680. Never change it. This is the container width every diagram is sized against. If your content is narrow, keep the width at 680 and center your content inside — do not shrink the viewBox to hug the drawing.
- viewBox height is computed from content. See
layout-math.mdfor the formula. Rule of thumb:H = max_y + 20wheremax_yis the lowest point of any element (bottom of the lowest rect, baseline + 4px descent of the lowest text). - Arrow marker uses
context-stroke. This means the arrowhead automatically matches the color of whichever line it's attached to. Usemarker-end="url(#arrow)"on any<line>or<path>connector. - Add a
<clipPath>to<defs>only if an illustrative diagram needs one. Nothing else belongs in<defs>. - Add a single
<linearGradient>to<defs>only for illustrative diagrams showing a continuous physical property (temperature stratification, pressure drop). Between two stops from the same ramp. Never more than one gradient per SVG.
Using the color classes
Apply c-{ramp} to the <g> wrapper that contains both the shape and its text:
<g class="c-blue">
<rect x="100" y="20" width="180" height="44" rx="6"/>
<text class="th" x="190" y="42" text-anchor="middle" dominant-baseline="central">Login service</text>
</g>
Or directly to the shape itself if there's no wrapping <g>:
<rect class="c-blue" x="100" y="20" width="180" height="44" rx="6"/>
Do not nest c-* groups. The CSS uses direct-child selectors — <g class="c-blue"><g>...</g></g> won't apply the fill to the inner shapes. If you need a click handler (future), put it on the same group that carries the color class, not a wrapper.
Optional background grid
For structural diagrams with a technical/blueprint feel, an optional background grid can reinforce the engineering aesthetic. This is rare — most diagrams should keep the transparent background for seamless embedding. Only consider the grid when the diagram shows infrastructure, network topology, or hardware architecture where the grid reads as "engineering paper" rather than decoration.
Add the pattern to <defs> and a full-viewport rect as the first visual element:
<defs>
<!-- arrow marker (always present) -->
<marker id="arrow" .../>
<!-- grid pattern (optional, structural diagrams only) -->
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="var(--grid-stroke, rgba(0,0,0,0.06))" stroke-width="0.5"/>
</pattern>
</defs>
<!-- Grid background (first visual element, behind everything) -->
<rect width="680" height="H" fill="url(#grid)"/>
Define the CSS variable in both modes so the value is explicit and discoverable (not buried in an inline fallback). Add these inside the existing <style> block:
svg { --grid-stroke: rgba(0,0,0,0.06); }
@media (prefers-color-scheme: dark) {
svg { --grid-stroke: rgba(255,255,255,0.05); }
/* ... existing dark-mode overrides ... */
}
With the explicit light-mode declaration, the inline fallback in the <pattern> stroke is redundant but harmless — keep it as a safety net for renderers that strip <style> blocks.
Rules:
- Grid stroke opacity must stay ≤0.08 in both modes — the grid is a texture, not a visual element
- The grid rect is always the first child after
</defs>, so every other element paints on top - Never use the grid on illustrative, sequence, or class diagrams — it fights with their visual language
- If the grid competes with the diagram's lines for visual attention, remove it
What to emit after the template
Visual elements in this order:
- Background decorations (optional grid rect, dashed frame for a schematic container)
- Containers (outer group rectangles for structural diagrams)
- Connectors and arrows (so they sit behind the boxes they connect, preventing visible overlap) — both solid
.arr/.arr-{ramp}primary flows and.arr-altalternative/optional/weak flows belong in this layer - Nodes (rects with text)
- Labels outside boxes (legend swatches, leader callouts)
When connectors and nodes fight for z-order, nodes win — draw the connectors first so the boxes paint on top of any line that crosses their edge.