Components

Annotation

Naming a part of a drawing. The system could already mark a found word and it could already draw an object; it had nothing in between — no way to say which part of an object you are looking at. Fifteen isometric objects ship with construction nodes on them, a black dot at a vertex, and not one of those dots said anything. This is the layer that gives them words.

The callout

An anchor on the drawing, a leader that is one lattice step, and a note standing on its own rule. Every annotation is drawn in contour; the one the reader is on is lit.

  • Lit face
  • Side face
  • Lattice cell 1 u
<figure class="cf-annot-fig">

  <!-- the drawing. It fills the figure, so --annot-x / --annot-y are
       fractions of its own viewBox and nothing has to be converted -->
  <svg class="cf-iso" viewBox="0 0 640 400" fill="none" aria-hidden="true">…</svg>

  <ul class="cf-annot-set">

    <!-- x = 200 / 640, y = 180 / 400 — the vertex the note points at -->
    <li class="cf-annot cf-annot--ne cf-annot--lit" style="--annot-x:31.25%; --annot-y:45%">
      <span class="cf-annot__label">Lit face</span>
    </li>

    <!-- with an optional measure after the note -->
    <li class="cf-annot cf-annot--se" style="--annot-x:68.75%; --annot-y:75%">
      <span class="cf-annot__label">Lattice cell <span class="cf-annot__value">1 u</span></span>
    </li>

  </ul>
</figure>
PartRequiredWhat it is
.cf-annot-figyesA <figure>. The positioning context and the container the layer is measured against. Give it no padding and no aspect ratio of its own — the drawing has to fill it exactly, or the percentages stop meaning viewBox fractions.
.cf-annot-setyesA <ul> laid over the drawing. Owns --annot-u and is the scroll subject the leaders are drawn against. pointer-events: none, so it never sits between the reader and anything below it.
.cf-annotyesOne <li>, one note. Carries --annot-x and --annot-y: where on the drawing it points, as a percentage of the figure.
.cf-annot--ne --se --nw --swyesWhich way the leader runs. One of the four, always — the default is --ne.
.cf-annot--steepnoPuts the leader on the steep isometric, 63.43°, instead of the shallow 26.57°. Composes with all four directions.
.cf-annot--litnoFills the anchor cell with the light ramp. At most one per figure, and only when a figure has a subject.
.cf-annot__labelyesThe note. Mono, 11 px, uppercase, --text-primary, standing on its own rule — that rule is the shoulder the leader runs into.
.cf-annot__valuenoA measure after the note. Tabular figures, --text-secondary. Goes inside the label so both stand on the one rule.
PropertyDefaultWhat it does
--annot-x / --annot-y50%Per annotation. Where the anchor sits, as a fraction of the figure — which is a fraction of the viewBox, so read the coordinate off the drawing and divide.
--annot-uclamp(0.875rem, 3.2cqi, 1.75rem)The lattice unit the leader is measured in. Reads the container, not the viewport: the same drawing in a narrow column gets a shorter leader.
--annot-mx / --annot-my2 / 1The step, in lattice units. The two sanctioned values are (2, 1) and (1, 2); the angle is read off them.
--annot-node0.5remThe anchor cell's width before the isometric transform squashes it.
--annot-draw1Set by the scroll animation, read by the leader and the label. 1 is the finished annotation, which is also what everything that cannot animate gets.

Four directions, two slopes

A leader may run in eight ways and no others. Technical drawing has required for a century that a leader be neither horizontal nor vertical, so the reader can tell it from the object it points at; this brand sanctions four angles, two of which are oblique. The two rules land on the same drawing.

  • nw
  • ne
  • sw
  • se
  • nw steep
  • ne steep
  • sw steep
  • se steep
The angle is read off the step, not typed in. A leader is declared as two across and one down — a lattice step, the same vector every object in this system is built from — and the stylesheet takes its slope from that step with atan2(--annot-my, --annot-mx). (2, 1) resolves to 26.565° and (1, 2) to 63.435°: the only two obliques the brand owns, and the only two a leader can be. A leader that is off the lattice is not expressible.

This is the first place the system states an isometric angle as the ratio it has always been rather than as a rounded degree. It is worth saying what that buys and what it does not: 26.57° against 26.565° is 0.005° and no screenshot will ever show it. What it buys is that the two numbers cannot come apart — change the step and the slope follows, where before a leader could be moved onto a different step and keep the old angle. Trigonometric functions have been Baseline since March 2023 and sqrt() since December 2023; both literals stay in place as the fallback, because an angle is not a place to find out a browser is old.
Left is a mirror, not a second angle. The leader carries scaleX(±1) ahead of its rotation, so --nw is --ne reflected rather than a separately stated −153.435°. Four directions, one angle, and no arithmetic anywhere that could put the left pair on a slope the right pair is not on.

How it is constructed

Nothing here is a new shape. The anchor is the lattice cell, the leader is a lattice step, the shoulder is the label rule the section header and the prose note already use, and the light is the light layer doing the job the manual gives it.

The shoulder is the label's own rule, and that is what keeps this inside where a line may go. Every line in this system is an edge, a division or a label rule. A leader is the third: a mono label with the hairline running out of it, so the line and the word are one mark. Drafting practice arrives at the same drawing from the other end — it asks for a level elbow at the note end so the text is not read at an angle — and the label's own underline is that elbow. What the component must never become is the bar beside a block, which is the decoration that rule bans by name: a leader always has an object at one end and a word at the other.
The label is placed by its bottom edge. Not by its top, and not by its centre. A leader arriving from below has to end at the shoulder rather than at the cap line, or the line stops in the middle of nothing and the two marks come apart. One rule — bottom: u × my × −sy — puts the underline at the end of the leader in all four directions, which is why the four directions need no separate label rules between them.
The anchor is a cell, drawn as a border. It carries --iso-transform, so the mark at 8 px is the same 2:1 rhombus the ground is tiled with at 120 — not a dot, and not a 45° diamond, which is what a square turned 45° would give and what the isometry is not. It is drawn out of border rather than a fill for the reason the radio's mark is: forced-colours mode discards background-color and maps border colours into its own palette. In forced colours the lit rung loses its ramp and every annotation is drawn identically, which is correct — the lit rung is emphasis, and emphasis is exactly what that mode is allowed to drop. That mode also gets the finished annotation rather than a frame of one: it exists to guarantee legibility, and an opacity ramp is the one thing it cannot guarantee.
The layer is measured against the drawing, never against the screen. --annot-u reads cqi off the figure, so the leader is a proportion of the object it points at. A 640-unit drawing in a 400 px column and the same drawing full-bleed get leaders that look the same length relative to what they are labelling, which a viewport unit cannot do.

Two rungs: contour, and the one you are on

This is the found state one scale up. There it is a word: every match carries the ground line, the current one carries light behind it. Here it is a part of an object: every annotation is drawn in contour, and the one the figure is about carries the light in its anchor cell.

That settles the lime budget without an exception, the same way the found state does. One lime moment per screen is a rule about composition, and a figure with six annotations composes one lit anchor and five contoured ones. It also settles what the lit rung may mean: it is the subject, never a category. Two lit anchors is a legend carried by a colour, in a component that has no legend.

A figure that has no subject gets no lit annotation at all. The 404 page is the shipped case: its empty socket is already the one lit element in the drawing, so the annotation that names it is drawn in contour. The light is spent on the object, and the note points at the light rather than competing with it.

What makes it readable

RuleWhy
The notes are a list, and the drawing is aria-hidden Each annotation is real text in a real <li>, so the figure reaches the accessibility tree as a list of the parts it names. There is no second copy of that text to drift out of step with the picture — the same posture as the plot.
Below 28 rem of figure the layer becomes a legend A callout needs clear ground to point into and a 320 px drawing has none. Rather than overlap two notes, the set flows under the figure as a row of marks and words. The label rule goes with the leader: an underline with no line running into it is not a label rule, it is decoration — and at that size it would be mistaken for a link.
Nothing is carried by the lit rung alone The lit anchor marks the subject the caption is already about in words. Never use lit and unlit to mean two kinds of thing.
Contrast is carried by the contour Labels are --text-primary (11.9:1 on the wash at its darkest end) and the leader and anchor are --border-strong, black — well past the 3:1 a UI contour owes. The lime in a lit anchor is a fill inside a black contour, so it carries none of that figure.

The leader draws itself

As the figure settles, each leader grows out of its anchor and its note fades up with it. One registered number, --annot-draw, is animated on a view timeline and read by both, so the line and the word cannot fall out of step.

The range opens at 45 % of the figure's cover — after .cf-iso has arrived (5–30 %) and after its own construction nodes have faded up (35–50 %). The drawing is finished before it is labelled, which is the order the two things happen in on paper. It is scrubbed from scroll position rather than played on a timer, so scrolling back up un-draws the leaders, and every path that cannot run it — no @property, no view timeline, reduced motion, print — lands on the finished annotation.

Do and don't

DoDon't
Point at a feature the drawing actually draws — a vertex, an edge, a face. Point at empty space, or at a part the object does not distinguish. A leader that terminates on nothing is a line that is neither an edge, a division nor a label rule.
Keep it to two or three notes on one object. Label every vertex. An annotated drawing that needs eight notes is a diagram that has not been simplified yet.
Send the leader into clear ground. Run a note across the object it is labelling, or across another leader. The component places what it is told to place; where there is room is a drawing decision.
Set the note in one or two words. Write a sentence. The label is the mono face at 11 px uppercase; prose belongs in the <figcaption>.
Light the anchor the figure is about, if the drawing has not already spent its light. Light two, or light one on a drawing that already carries a lit element.

Still open