Diagrams
The inline SVGs that ship inside estate pages carry load. These are the editorial rules for drawing one: the container it sits in, the attributes it needs, and the grammar of nodes, arrows, and type. Four specimens below show the rules applied. The gallery holds the full catalogue: one for each type in cathrynlavery's diagram-design typology, a consultant variant of the quadrant, and the estate originals.
The container
Every inline diagram in the estate sits in a
<div class="cat-explainer"> with a caption paragraph
beside it, or under it once the row runs out. The caption says what the diagram is saying, not
what each line means. The canvas is 660 × 200 for a short
diagram, a one-row umbrella or a simple flow, and
660 × 240 where the content needs the height: state
machines, multi-row pipelines, captioned figures. A single-concept
object, a ladder, a spectrum, a chain walked end to end, a
side-by-side comparison, stays one figure at whatever height its
structure needs: 660 × 400 to 660 × 480
covers most of them. An outer <rect> starts
at (20, 20) and runs 620 wide, holding a
consistent 20px margin off the viewBox edge. The box has a hairline
of padding, so the border sits close to the drawn
frame; the canvas's own 20-unit margin is the only breathing room.
site.css ships the container rules, so a site consuming
the chrome writes no .cat-explainer CSS of its own. A
tokens-only site carries the three rules locally. Tutti is the case:
its own chrome collides with the canonical class names.
.cat-explainer { display: flex; flex-wrap: wrap; gap: var(--space-5); align-items: end; max-width: 100%; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-2); margin: var(--space-4) 0 var(--space-5) 0; clear: both; }
.cat-explainer svg { display: block; width: var(--fig-w, 41.25rem); max-width: 100%; height: auto; margin: 0; }
.cat-explainer p { flex: 1 1 16rem; margin: 0; font-size: var(--text-sm); color: var(--text-2); }
The skeleton
Two nodes and one labelled connector, carrying every attribute the rules below turn on:
<svg viewBox="0 0 660 200" role="img" font-family="'IBM Plex Sans', system-ui, sans-serif"
aria-label="The collector writes into the store, and nothing else reaches it.">
<defs>
<marker id="collect-arrow" markerUnits="userSpaceOnUse" markerWidth="9" markerHeight="7" refX="9" refY="3.5" orient="auto"><path d="M0,0 L9,3.5 L0,7 Z" fill="var(--text-2)"/></marker>
</defs>
<g font-family="'IBM Plex Sans', system-ui, sans-serif">
<rect x="20" y="20" width="620" height="160" rx="6" fill="var(--bg)" stroke="var(--border)"/>
<path d="M180,100 H300" fill="none" stroke="var(--text-2)" stroke-width="1.5" marker-end="url(#collect-arrow)"/>
<rect x="216" y="76" width="48" height="16" fill="var(--bg)"/>
<text x="240" y="88" text-anchor="middle" font-family="'IBM Plex Mono', monospace" font-size="8" fill="var(--text-2)">writes</text>
<rect x="60" y="70" width="120" height="60" rx="6" fill="var(--accent)"/>
<text x="120" y="88" text-anchor="middle" font-family="'IBM Plex Mono', monospace" font-size="8" letter-spacing="0.08em" fill="var(--accent-contrast)" opacity="0.8">SERVICE</text>
<text x="120" y="105" text-anchor="middle" font-size="12" font-weight="600" fill="var(--accent-contrast)">collector</text>
<text x="120" y="119" text-anchor="middle" font-family="'IBM Plex Mono', monospace" font-size="9" fill="var(--accent-contrast)" opacity="0.85">:8080</text>
<rect x="300" y="70" width="120" height="60" rx="6" fill="var(--surface)" stroke="var(--border)"/>
<text x="360" y="88" text-anchor="middle" font-family="'IBM Plex Mono', monospace" font-size="8" letter-spacing="0.08em" fill="var(--text-muted)">STORE</text>
<text x="360" y="105" text-anchor="middle" font-size="12" font-weight="600" fill="var(--text-2)">disk</text>
<text x="360" y="119" text-anchor="middle" font-family="'IBM Plex Mono', monospace" font-size="9" fill="var(--text-muted)">one writer</text>
</g>
</svg>
Required attributes
role="img"on the root, plus a non-emptyaria-labelthat is one sentence of content: what the diagram shows in the reader's terms, never shape by shape. Four sentences is worse than one.- An outer
<rect>filling the canvas, so the artwork carries its own background and survives host CSS. font-familyon the<svg>root and on the wrapping<g>, so text inheritance survives.<defs>marker IDs prefixed with a per-diagram slug, so two inlined SVGs on one page do not collide, each withmarkerUnits="userSpaceOnUse". The default scales with stroke width and overshoots the head into the target rect.- An SVG loaded through
<img src>keeps the host'saltand carries noaria-label; the inner one is hidden and rots unread. Inline it.
No blank lines inside the markup
Every markdown processor the estate ships through (remark, MDX,
GitHub's CommonMark, GitLab's) reads a blank line inside an inline
<svg> as a paragraph break. It closes the SVG early
and wraps the trailing elements in a <p> outside the
diagram. Group with HTML comments instead, and check the built page:
curl -s "$url" | grep -E '<p><(text|path|rect|g|circle|line)'
Any hit is a broken SVG.
The rules
Trim before you add
Every node, arrow, and label in an estate diagram has to do work the surrounding prose can't. The four-tile FLOW/DISCIPLINE cluster at the top of every hero is this rule made literal: four facets, never six, never ten. Bairn's vendor-survives diagram carries one downstream direction plus three disruption arrows that terminate at a barrier, nothing else. Patinate's pipeline carries the four CLI commands and their three caches, no more.
Before adding a node to an existing diagram, ask which node it replaces. Diagrams that grew got worse; diagrams that shed got better.
When one is already over budget, cut in a fixed order: decoration, exact duplicates, leaf clusters, degree-1 sinks, cross-cutting infrastructure, and only then split the diagram. A collapsed cluster becomes one node carrying its count, named in the caption.
Fill and stroke rank the node
The focal node wears the accent. A service is surface on ink. A
store, or anything outside the boundary, fades back to
--surface behind a --border hairline.
Identical boxes for every node erase the hierarchy the reader came
for, and no amount of labelling puts it back.
The accent is a budget
Moss #4a6741 is the single brand accent across the estate.
Inside a diagram it is a budget: one or two elements wear it,
and they are the elements you want the reader to look at first. Everything
else renders in --text, --text-2,
--text-muted, or --border.
If you find three things needing accent in a single diagram, the diagram is doing two jobs: split it.
Coordinates snap
Estate diagram SVGs snap structural coordinates to a
four-unit grid. Boxes start at x=20, never
x=23. Gaps are 16, never 15.
Heights and widths are multiples of 4. The exception is intra-element
geometry (curve control points, arrowhead apices, path tangents), which
lands where it needs to.
Stroke, radius, shadow
- Borders and rules are 1px hairlines. Content lines (arrows, flow paths) are 1.5–2px.
- Border-radius caps at
var(--radius)(10px). Super-rounded corners snap straight into template-flavor territory. - No drop shadows. Depth comes from the contrast between
--bgand--surface, never from blurred copies of the element.
Five roles, one type ramp
Size in a diagram is a role, not a taste call. At 660 wide the ramp is fixed, and sans carries meaning while mono carries technical fact.
- Eyebrow. 8px
IBM Plex Mono, tracked caps,--text-muted. What kind of thing this node is. - Name. 12px
IBM Plex Sans600,--text. The word the reader takes away. - Sublabel. 9px
IBM Plex Mono,--text-2. Port, path, command, count. - Arrow label. 8px
IBM Plex Mono,--text-2, sitting on its own opaque mask. - Caption.
--text-smin--text-2, prose under the SVG, never a legend.
A node stacks at most three of these rows. A fourth row is a sublabel that wants to be its own node.
Arrows stay traceable
A reader has to follow any one connector from source to target without losing it. No two connectors share a path or an attach point: fan the arrows leaving a box across its edge instead of stacking them on one anchor, hold parallel runs 12px apart end to end, and where two lines must cross, hop the less important one.
Nodes sharing no axis connect through a rounded right-angle elbow at
r=6, never a diagonal, and return legs route around boxes
along the row's bottom edge rather than through them. A diagonal that
clips a box is the line the reader loses.
Fan the arrows leaving one edge at L*k/(N+1), and open
parallel runs to 14px where a label has to sit between them.
Three arrow kinds, no fourth
Muted for an internal hop, moss for the one focal path, dashed for optional, async, return or transit. A fourth colour would be a second accent, and the budget is already spent.
Every connector ends in an arrowhead. A line with no
marker-end is a wire, not a flow, and the reader has to
guess which way the thing moves.
Paint order is fixed
Background, zones, arrows, labels, nodes. Arrows before boxes is what makes every label rule checkable: a connector that would have crossed a node is visibly clipped by it instead of floating over the top, so the routing error shows up while you are drawing.
Arrow labels get an opaque mask
Each arrow label sits on its own opaque rect: 8px between mask edge and stroke, clearing any node painted after it, and clear of the arrowhead's ~10px range. Length is the constraint the mask cannot fix: "GET descriptor" fits beside its arrow, "GET descriptor.xml" overruns.
Detail-rich diagrams ship as a pair
Anything carrying more than six labeled elements at hero scale ships as a
.diagram.figure-pair: a wide horizontal SVG for desktop,
a stacked vertical one for mobile. The chrome swaps at the 900px
breakpoint. Patinate's pipeline diagram is the worked example.
A 660×200 canvas tops out near six nodes and eight arrows. Past that, a diagram of two mechanisms the prose treats separately ships as a pair, or two figures with a caption each, never a denser canvas. A single-concept object, a ladder, a spectrum, a matrix, a chain the post walks end to end, a side-by-side comparison, is not two mechanisms: it stays one figure however many nodes it carries, growing the canvas height instead of splitting.
Every specimen, the four below and the rest in the gallery, is single-figure by design: each one shows a type at its simplest legible density, so none of them reaches the threshold that earns a pair.
The specimens
Four types, drawn against the rules above: one structural, one flow, one comparison, one estate-original. The gallery carries the rest, one line of context each, plus these same four in its index.
Architecture
Components and their connections. Use when the reader needs to understand what exists and how it wires together, not how it runs.
Fall back: Without connections between the boxes, the components are a tile-grid.
Flowchart
Decision logic with branches. Use when a yes/no gate or conditional path is the substance of the explanation.
Fall back: Without a branch, the steps are a state-flow.
Quadrant
Items positioned on two independent axes. Use when the goal is comparative placement, not ranking.
Fall back: Without a second independent axis, the items rank as a tile-list.
Vendor-survives
estate-originalWhat disruption stops at our boundary. Use when the diagram's job is to show what a vendor outage cannot reach. Canonical example: bairn's Famly outages terminating at the disk barrier.
Fall back: Without disruption stopping at a barrier, the boundary is an architecture.
Acknowledgement
The single-accent budget, the structural-grid discipline, and the framing of trim-before-add were sharpened by reading cathrynlavery/diagram-design, which builds a deeper diagram-typology skill for general use, with worked examples for each type shipped as separate HTML assets rather than inside the type files themselves. The gallery now carries her full typology, every type drawn in the estate's own convention, alongside the originals grown from diagrams actually shipping across tutti, bairn, patinate, and pipeline. The editorial rules above are the ones that survived being tried against real artifacts. Cathryn's work helped clarify which ones were load-bearing.
The node-treatment ramp, the connector rules, the per-role type scale
and the accessible-figure test above were sharpened by a second reading
of cathrynlavery/diagram-design at commit 4451ead; the
rules are restated here for a 660-wide inline SVG, and upstream's
canvas, palette and fonts are not adopted.