Skip to content

Diagrams and charts

diagrams and charts on the site: one viewer for every Mermaid diagram (zoom, pan, full screen, download, tracing), the addresses `#diagram-<name>` and `#diagram-<name>:<node>`, node links inferred at build from the identities the generated data carries, and charts drawn from the tables a page already renders

Rendered from docs/DIAGRAMS.md — the same Markdown GitHub shows.

Every diagram this site publishes is drawn by one viewer, and every chart by one component. Neither is configured per page. A diagram is a ```mermaid fence in the one document that states the relationship, or Mermaid source a template writes from generated data; a chart is a table the page already renders. What makes them interactive, addressable and linked is derived at build time from what the repository already knows. The decision is ADR 0152; the rule that a diagram is drawn and never typed is project.a-diagram-is-drawn-not-typed.

The path of one diagram

flowchart LR
    fence["a mermaid fence<br/><small>docs, a decision, a rule</small>"]
    data["site/data/generated<br/><small>diagrams.json, plan.json</small>"]
    zola["Zola<br/><small>pre class=mermaid</small>"]
    pass["scripts/lib/diagrams.mjs<br/><small>name, nodes, toolbar, links</small>"]
    check["scripts/ci/link-check<br/><small>every link and every address</small>"]
    viewer["site/diagrams.js<br/><small>draw, zoom, pan, trace, address</small>"]
    fence --> zola
    data --> zola
    zola --> pass
    data -- "identities and routes" --> pass
    pass --> check
    pass --> viewer

Nothing in that path is typed twice. The fence is the only place the relationship is written; the identities a node can link to are the ones scripts/generate-site-data already wrote; and the viewer reads what the build prepared rather than a configuration of its own.

What the build adds to a diagram

scripts/site-build runs scripts/lib/diagrams.mjs over the pages Zola wrote. For each <pre class="mermaid"> it adds four things:

AddedFromWhy
id="diagram-<name>"the data-diagram name a template declared, else the id of the heading the diagram sits under, else its ordinal on the page; a second diagram under one heading is <name>-2an address a link can land on, with or without JavaScript
data-nodesthe node ids the source declares (flowcharts and state diagrams)a link to one node can be refused when the diagram has no such node
a toolbar, written hiddenthe pass itselfa control the markup declares is one scripts/ci/interaction-check can hold to a behaviour; the viewer reveals it once there is a drawing to control
a list of links beside itthe identities in site/data/generatedthe links work without JavaScript and are checked like every other link

A page that would carry two diagrams under one declared name is refused, and the build stops (exit 10). The diagram's source is never changed.

A node becomes a link when its id, its label, or one line of its label is the identity of an object this build wrote a page for:

Identity in the diagramLinks toRead from
I2653, M003the issue or the milestone in the planplan.json
ADR 0152, adr-0152the decisionentities.json
a rule id, with or without its versionthe ruleentities.json
majordomus doctor, majordomus plan nextthe commandcommands.json
a capability id such as mesh.claimthe capabilityexecutable.json
a doctrine idthe doctrinedoctrines.json
docs/DESIGN.mdthe documentdocs.json

An identity inside a longer label resolves too, but only when the label names one object. A label that names two, or that names an object this site has no page for, is linked to neither: a link that picked the one it could resolve would be a guess. A bare file name inside a sentence is not an identity. An identity whose page the build did not write is not offered at all.

Nobody writes an href into a diagram. Mermaid's click directive is not used: a link exists because an identity appears in a diagram, and it disappears at the next build when the object does.

The viewer

site/diagrams.js is loaded only by pages that carry a diagram, and fetches the vendored Mermaid build after the page has been parsed. It draws each diagram in the page's own colours, read from the design tokens, and draws them again when the theme changes.

ToDo
zoomthe toolbar's − and +; + and - on the keyboard; Ctrl or Cmd with the wheel; a pinch
pandrag; the arrow keys
see the whole diagramFit; 0; a double click on empty space
fill the screenExpand; F; Escape leaves
keep the drawingSVG saves <name>.svg
follow a nodeclick it, or move the focus to it and press Enter, when the build linked it
trace a nodepoint at it or move the focus to it: its edges and neighbours stay, the rest steps back
select a nodeclick a node that is not a link; Alt and click, or S with the focus on it, for one that is
copy an addressLink copies the diagram's address, or the selected node's

A diagram too large to be read whole, such as the dependency graph of every issue, opens at a readable size from its top left corner and is panned from there. A plain wheel always scrolls the page.

The frame is the diagram's own <pre>: it keeps its id and its place in the tab order. A diagram that fails to draw keeps its source visible, gets no controls, and reports the error on the browser console, which scripts/interaction-probe treats as a finding.

Addresses

AddressOpens
#diagram-<name>the page at that diagram
#diagram-<name>:<node>that diagram with the node selected, centred and traced

scripts/ci/link-check decides both offline. The first is an ordinary fragment: the id must exist on the page. The second resolves only when the page carries the diagram and the diagram declares the node, so a link to a node that was renamed fails the build that renamed it.

Charts

A chart is a table the page already renders, declared as one:

<figure id="chart-milestones" data-chart="bar" data-chart-stack data-chart-horizontal data-chart-unit="issues">
  <table>
    <thead><tr><th>milestone</th><th data-series="done">…</th></tr></thead>
    <tbody><tr id="chart-milestones:m000"><td><a href="…">M000</a></td><td>15</td></tr></tbody>
  </table>
</figure>

site/charts.js draws the table with Apache ECharts: the first column is the category and every column whose header carries data-series is a series. The numbers are read from the cells the page shows, so a chart cannot disagree with its table and there is no second copy of the data. The table stays on the page; it is what a reader without JavaScript, a screen reader and a printout get.

DeclarationMeaning
data-chart="bar" or "line"what to draw
data-chart-stackthe series are parts of one whole
data-chart-horizontalcategories run down the side
data-chart-unitthe unit, on the axis and in the tooltip
data-chart-labelwhat the picture is of, for a reader who cannot see it
data-series on a header cellthis column is drawn
data-value on a cellthe unrounded number, when the cell shows a rounded one
a link in a row's first cellthe row's mark opens the same page
id="chart-<name>:<row>" on a rowthe row's address, which also highlights its mark

A series takes the colour its header is drawn in when the header carries a status badge, so a state is drawn in the colour the design declares for it; any other series takes the next of the design's series colours. ECharts is vendored at build from the pinned npm package and is fetched the first time a chart nears the viewport.

Two charts are drawn this way today:

ChartPageTable it readsData
#chart-milestones/plan/issues of each milestone by derived stateplan.json
#chart-context-history/economics/the context reduction ratio at each recorded runeconomics.json

What is checked, and by what

ClaimCheck
what a source declares and what a node resolves tonode --test scripts/lib/diagrams.test.mjs
names, nodes, toolbar, links, idempotence, the refusal of a duplicate name, and both kinds of address through link-checkbash test/run.sh 3006_diagrams_are_interactive_and_linkable
every link the pass wrote resolvesscripts/ci/link-check, on every build
the toolbar, the keys, the address and the linked nodes behave in a browserthe diagram spec of scripts/interaction-probe
no relationship is typed as box artscripts/ci/diagram-check

The charts have no behaviour spec yet: they declare no control, so the probe has nothing to claim, and what a chart read from its table is asserted by no gate. That is issue I2654.

Limits

  • Node links and node addresses exist for flowcharts and state diagrams. A sequence diagram or any other kind is named, drawn, zoomed and addressable as a whole, and has no nodes to link.
  • Edges are traced in flowcharts only.
  • The homepage carries no diagram and no chart. Its sections and its byte budget are declared in site/data/homepage.toml, and adding either is a change to that declaration (issue I2655).
  • The Cockpit and majordomus ui draw their own graphs and do not use this viewer (issue I2656).

Claims this document defines

Each links to its own page with implementation, test and where it is used.

Searches the titles and descriptions of every page this site publishes.