---
title: "Diagrams"
description: "A diagram carries an explanation that prose alone shows slower, and the set is the system's visual leitmotif."
canonical: diagrams.html
navigation-title: "Diagrams"
---

<a id="diagrams"></a>

# Diagrams

- [The numbers](#the-numbers)
- [On a slide](#on-a-slide)
- [Drawing rules](#drawing-rules)
- [Worked examples](#worked-examples)
- [Another one](#another-one)

A diagram carries an explanation that prose alone shows slower, and the set
is the system's visual leitmotif. A shared grammar keeps them from one-off
drawings whose colour, geometry and meaning a reader learns again each time.

**One claim per diagram.** The title states it, the closing line states its
consequence. Two claims are two diagrams.

**If the drawing still works as a bulleted list, it is not a diagram.**
Position, length or alignment carries the meaning. Boxes and arrows are the
last resort, not the first vocabulary.

Solid means there. A dashed outline of the same shape means absent or not yet
reachable, so a shortfall has a *size*, not a sentence. Where the absent part
is a degradation, not a precondition, the dashed outline carries
`--status-warn`.

Orange marks the one thing the diagram is about: exactly one element per
drawing, often a connector, since the claim is usually a relation. When the
drawing is about degradation or failure, status colour replaces the accent
and orange stays out.

<a id="the-numbers"></a>

## The numbers

| | |
| --- | --- |
| Canvas | `viewBox="0 0 1200 H"`, always 1200 wide, height to fit. No radius, shadow, gradient or texture |
| Margin | 60 units every side. Nothing enters it, labels included |
| Type | Source Sans 3; identifiers, paths and flags in Source Code Pro. Title 36 · lead 17 · node title 16 · node body 14 · label 13. **13 is the floor** |
| Stroke | 1 node outline, 1.5 connector or boundary, 2 for the one accented connector |
| Radius | 6 node or boundary, 4 bar, 2 unit square. Never above 6 |
| Node | `--surface-raised`, 1px `--border-subtle`, radius 6. Peers share one treatment; their names tell them apart, not their hues |
| Boundary | Hairline only, **no fill**. A filled container makes depth out of colour |
| Connector | 1.5px, orthogonal, one arrowhead, `--text-muted`. No curves. Dashed means optional or not yet, and nothing else |

> [!WARNING]
> **Colour is an attribute**, never a `<style>` block, which GitHub
> strips. Each attribute is the token with the light hex behind it,
> `fill="var(--text-primary, #1C1A17)"`. The hex is what a page shows, and
> the token is ready for the day a page can read it. Ship that one file and
> wrap its shapes in `<g id="soul-ref">`, the handle `make diagrams`
> reads them out from under for the specimen cards. [Artwork](artwork.md) holds
> the whole file contract.

A diagram sits on `--surface-sunken`. The drawing brings its own canvas,
which makes it read as a figure with clear space. On `--surface-canvas` it
dissolves into the page.

<a id="on-a-slide"></a>

## On a slide

A drawing for a slide keeps the grammar and leaves the frame. It has no
eyebrow, no title and no closing line: the slide's head says them. It has
no margin, as the slide's margin is its margin. Its canvas is the room of
its layout in the frame's pixels, which [Slides](slides.md) states, and not 1200
wide. A drawing in parts is a row of drawings: the slide gives each its
plane, its word and its caption as text. `slide-lookup.svg` is one
drawing for `wide`, the three `slide-cache-*.svg` a row.

<a id="drawing-rules"></a>

## Drawing rules

[Drawing rules · 980x650](../_cards/guidelines/diagrams-rules.card.html)

<a id="worked-examples"></a>

## Worked examples

Different shapes of claim need different structures. The examples below use
an axis, a sequence and containment instead of boxes joined by arrows.

[System overview — a map with no axis · 1400x966](../_cards/guidelines/diagrams-overview.card.html)

[Worked example · 1400x1014](../_cards/guidelines/diagrams-example.card.html)

[Fallback — a sequence without a flowchart · 1400x1034](../_cards/guidelines/diagrams-fallback.card.html)

<a id="another-one"></a>

## Another one

The rules above as an instruction for a drawing tool, with the file contract
and the negative constraints. It stands here in full because it is a thing
to hand over. Copy the whole block and replace `[CLAIM]` and
`[CONSEQUENCE]`, the only two fields that change. New numbers or new states
start a second grammar, and a set in two grammars costs a reader at every
drawing.

A diagram is the one drawing that does not come back as a picture. The
result is the SVG itself, because its colours are tokens and \``make
diagrams`\` reads its shapes out for the cards above.

The diagram prompt — replace only the claim and its consequence

````markdown
# Explanatory diagrams

A diagram carries a claim. An illustration only sets a register beside the
heading it stands under. If a reader need not understand a position, a
connection or a quantity in the image, draw an illustration instead:
`docs/design-system/illustration-prompt.md` is that prompt.

A diagram does not come back as a picture. It is one SVG file in the grammar
below, shipped as source. The colours in it are tokens a page can reach into,
and `make diagrams` reads the shapes back out for the specimen cards.

## The fixed language

- **Canvas:** `viewBox="0 0 1200 H"`, always 1200 wide, the height to fit. A
  flat rectangle at `var(--surface-canvas, #FBFAF7)` fills it. No radius,
  shadow, gradient or texture.
- **Margin:** 60 units every side. Nothing enters it, labels included.
- **Type:** Source Sans 3, with identifiers, paths and flags in Source Code
  Pro. Title 36 · lead 17 · node title 16 · node body 14 · label 13. **13 is
  the floor.** A diagram that needs smaller type carries too much.
- **Stroke:** 1 node outline, 1.5 connector or boundary, 2 for the one
  accented connector.
- **Radius:** 6 node or boundary, 4 bar, 2 unit square. Never above 6.
- **The two states:** solid means there. A dashed outline of the same shape
  in the same place means absent or not yet reachable. So a shortfall has a
  *size*, not a sentence. Dashed means nothing else.
- **Colour:** names tell peers apart, never hue. Exactly one element carries
  the accent, often a connector, since the claim is usually a relation.
- **Accessibility:** the drawing is the explanation, never decoration. The
  root names a `<title>` with the claim and a `<desc>` with the axes.

## Prompt

Replace `[CLAIM]` and `[CONSEQUENCE]` and leave the rest unchanged:

```text
Use case: explanatory diagram
Asset type: one hand-written SVG file, 1200 units wide, height to fit

Primary request: Draw a diagram that makes this single claim visible:
[CLAIM]. The line it closes on is: [CONSEQUENCE].

Canvas: viewBox="0 0 1200 H", H chosen to fit the drawing. A flat rectangle at
var(--surface-canvas, #FBFAF7) fills it. 60 units of margin on every side, and
nothing enters that margin, labels included. No outer radius, no shadow, no
gradient, no texture anywhere in the file.

Structure: the claim is carried by position, length or alignment — an axis, a
sequence, containment, a span across a scale. Boxes joined by arrows are the
last resort, not the starting vocabulary. If the drawing would still work as a
bulleted list, change the structure rather than adding detail to it.

Frame: an eyebrow in Source Code Pro at 13, uppercase and letter-spaced, in
var(--accent, #FF8700); the title under it at 36 bold in
var(--text-primary, #1C1A17); one lead line at 17 in
var(--text-secondary, #4A453D); a 1-unit rule in
var(--border-subtle, #E3DFD6) across the full width. At the foot, a 1-unit
rule in var(--border-strong, #C9C3B7), the consequence at 16 semibold, and one
line under it at 14.

Type: 'Source Sans 3' with a system-ui fallback for prose, 'Source Code Pro'
with a monospace fallback for identifiers, paths and flags. Node title 16
semibold, node body 14, label 13. 13 is the floor and nothing goes under it.

Shapes: node radius 6, bar radius 4, unit square radius 2, never above 6. A
node is var(--surface-raised, #FFFFFF) behind a 1-unit
var(--border-subtle, #E3DFD6) outline. A boundary is a hairline with no fill —
a filled container makes depth out of colour. A connector is 1.5 units,
orthogonal, one arrowhead, var(--text-muted, #726C63), and never curved.

The two states: a filled shape is what you get. A dashed outline of that same
shape, in that same place, is what is missing or not yet reachable, drawn in
var(--text-muted, #726C63). Dashed carries no other meaning. Where the missing
part is a degradation rather than a precondition, the dashed outline takes
var(--status-warn, #986200) instead.

Colour: peers share one treatment and are distinguished by their names, never
by hue. Ink is var(--text-primary, #1C1A17), a quieter line
var(--text-secondary, #4A453D), a label var(--text-muted, #726C63). Exactly
one element in the whole drawing carries var(--accent, #FF8700), and it is the
one thing the diagram is about. Where the diagram is about degradation or
failure, status colour replaces the accent and orange stays out entirely.

File contract: every colour is a presentation attribute written as a var()
with the light hex behind it. No style block, and no fill or color on the root
element. The root carries role="img" and aria-labelledby pointing at a title
and a desc inside it. Every drawn shape sits inside one group with the id
soul-ref. No comment in the file may contain two dashes in a row: that is
malformed XML, and such a file draws nothing wherever it is fetched.

Constraints: one claim and no second one; no legend repeating what the shapes
already say, no colour key, no hue palette, no icon set, no screenshot of an
interface, no logo, no watermark.

Avoid: flowcharts of everything, decorative or double-headed arrows, curved
connectors, drop shadows, elevation, rounded canvases, multicoloured node
sets, isometric or three-dimensional treatment, clip art, dense small type,
fine hatching and decorative clutter.
```

## The claim

Write the claim as a sentence before you draw. A topic, "how the sources
work", has nothing to draw. A claim, "bundled knowledge is the only source
that spans the whole axis", decides the structure by itself. It names the
thing under comparison and the scale of the comparison.

The title states the claim and the closing line states its consequence. Two
claims are two diagrams. A drawing that carries both ends up as boxes joined
by arrows, the shape of a claim that has stopped being one.

Then pick the structure from the claim, not from the shapes. A span along a
scale wants an axis. A thing that must happen before another wants a
sequence. A thing that holds others wants containment. Boxes and arrows are
what remains when none of those fits.

Which drawings a set holds is a property of that set, not of this prompt.
`packages/frontend/assets/diagrams/` owns that list. A copy here is an
inventory that falls behind the files.

## What to hand back

One file in `packages/frontend/assets/diagrams/`, named after the claim, not
the drawing. Then `make diagrams`. It reads the shapes out from under
`soul-ref` for the specimen cards. It refuses a file without the group or
the `viewBox`, and a file with a comment that is not valid XML.

Look at it twice. At 1200 wide, where a reader reads the type. And at the
width a card gives it, where only position, length and alignment survive. If
the second view no longer makes the claim, the claim was in the labels.
````
