Yuhang

Colophon

How this is made

Recorded because design decisions that are not written down get re-litigated every six months.

Type2 families

Two typefaces, two jobs. The reading voice isNewsreader — a variable serif with a real optical-size axis, which is why display and body can be the same family without the headings looking like inflated text. Browser optical sizing is left on, so a 96px title automatically gets the high-contrast cut and a 17px paragraph gets the sturdy one. The field-label layer — navigation, metadata, counts, legends — isIBM Plex Mono, always uppercase and tracked out, which is what gives the whole thing its surveyor's-notebook register.

Both are self-hosted via Fontsource with unicode-range subsetting, so a Latin-only page downloads only the Latin files. No Inter, no system stack.

DisplayReading terrain
BodyThe compression ratio of a contour map is absurd, and it works anyway.
LabelSnow science · 14 notes
Mono1 234 567 890 · f/8 · 1/250s

Colour3 chromatic slots

Warm paper, one accent, and hue used sparingly. Depth comes from paper tone and line weight — there are no shadows and no corner radii anywhere on the site.

The graph's domain colours were not chosen by eye. A force-directed graph is an all-pairs colour problem: any two nodes can end up adjacent, so every pair has to be separable, not just neighbouring ones in a legend. Under that constraint a validated categorical palette only clears the colour-vision-deficiency gates at three chromatic slots — so three domains carry hue and everything else is neutral. Both modes were stepped and checked separately against their own surface, because an inverted light palette is not a dark palette.

RoleLightDark
Outdoor#357f3a#38833f
Technical#2a5f9e#5a94d8
Business#d08a0c#c2871e
Everything else#8a8275#7d7668

Measured results, light surface #faf8f3, all pairs: worst colour-deficient separation ΔE 10.1, worst normal-vision ΔE 20.5. The amber slot sits at 2.7:1 against paper, which is below the 3:1 bar — so it ships with relief rather than on its own: every topic node is permanently labelled, the legend is always visible, hovering gives a text readout, andthe graph page carries a full table of the same data. On the dark surface #15140f every slot clears 3:1, but green and amber land at ΔE 7.5 — inside the warn band, which the same labelling makes legitimate. The dark lightness band and an amber slot cannot both hold while clearing 8; that is a measurement, not an omission.

Buildstatic

  • Astro, static output. No server, no database.
  • Markdown via remark/rehype. Astro 7 ships Sätteri as its default processor; this site opts back into unified because the markdown pipeline is the product here and needs real plugins.
  • Two wikilink passes. remark turns [[slug]] into links; rehype resolves the display text to the target's title and marks dangling ones visibly.
  • d3-force on a 2D canvas for the graph, with the layout built from a single compile-time pass over the note bodies.
  • Pagefind for full-text search, indexed after the build.
  • Sharp, via Astro's image pipeline, for every photograph.
  • Cloudflare Pages for hosting.

Behaviourthe boring guarantees

  • Every interactive thing degrades. The graph's data exists as a table; search only appears if its index actually shipped; the note index filters a list that is fully rendered server-side.
  • prefers-reduced-motion is honoured literally, not cosmetically: the graph solves its layout silently and paints once, and the lab sketches render a single still frame instead of animating.
  • Canvas sketches pause when scrolled out of view.
  • The theme toggle has three states — auto, light, dark — so following the system stays reachable after a manual override, and it beats the OS setting in both directions without a flash on load.
  • The ornament is one deterministic contour generator, seeded, drawn as static SVG at build time. Zero JavaScript.