journal 2026-04-28

Annotations grow up — line, chip-coord, and a glossary

siteviewerinfra

After the P03/P04 entry landed, the site’s two viewers and two file-rendering components needed a real annotation story. They got one over the next two hours, mostly by borrowing patterns from the pine64-freebsd notes site and adapting them to a chip context.

What happened

Started with line annotations. Source.astro and Diff.astro both grew an annotations: { match, text }[] prop. A Shiki transformer walks the highlighted code’s child line spans and splices an <aside> sibling immediately after each matched line. First pass put the notes inline (italic, warning-tinted, └── glyph prefix). Second pass moved them to a side panel because copying code from the page picked up the prose, which was bad. Third pass: the side notes are absolutely positioned per-target-line, with a JS pass measuring offsetTop and walking the list pushing later notes down so they don’t overlap. Container-query fallback to a stacked layout below 760px.

Then chip-coordinate annotations on the LayoutViewer (2D) and ChipViewer (3D). Same prop shape: { x_um, y_um, w_um, h_um, label, text, layers? }, in fab µm, DEF convention, origin at die bottom-left. The 2D viewer reprojects markers every animation frame through the live viewBox; the 3D viewer raycasts a wireframe LineSegments box (with an invisible solid pick-mesh twin, because thin line geometry is unreliable as a click target). Layer toggling is folded in: clicking an annotation can hide every layer except the ones that matter for that callout.

The two viewers cross-talk via a vp-anno custom event. Click an annotation card in the central panel and both viewers focus on it simultaneously. The annotation panel itself eventually moved out of each viewer and into the ViewerPair wrapper’s grid column 2, with per-viewer panels collapsing when the central one is rendered, so there’s never a duplicate list.

UX iterations along the way: click-only (no hover layer toggling, too twitchy), only the active annotation’s box renders (the wireframes were too noisy), the ChipViewer canvas had to fight to fill its column rather than hold a 16:10 aspect with empty space below.

Closing the session: a <Term> component plus /glossary page. About 30 acronyms (UART, SPI signals, CDC, sky130 layers, EDA tools) defined once in src/data/glossary.ts. <Term> wraps a word in <abbr title> with a dotted underline and links to /glossary#slug. Applied across the first acronym mentions on the P03 and P04 pages.

Receipts

Files of note: /site/src/components/Source.astro, /site/src/components/Diff.astro, /site/src/components/LayoutViewer.astro, /site/src/components/ChipViewer.astro, /site/src/components/ViewerPair.astro, /site/src/components/Term.astro, /site/src/data/glossary.ts, /site/src/pages/glossary.astro.