← Back to the plate

Build note · Plate 84

How the plate was made

LODESTONE is a dead scatter of iron filings on grey paper that wakes only under your hand. Your cursor is a north pole; each tap pins a fixed pole. The single job of the page: to let you feel, for a moment, that you are the magnet — and to prove it with a field that is computed, not drawn.

The palette

Argued from the subject — a physics demonstration plate

Grey paper and grey iron, with two poles of colour: the warm/cool pair every compass and every classroom magnet has worn since the nineteenth century. Bright red and blue are held back for the poles and their field lines only; all type sits on a dedicated dark ink so nothing important rides a low-contrast accent.

Paper
#E7E3D8
Warm grey card — the dead plate. Neutral enough that grey iron reads, warm enough to feel like paper, not a screen.
Filings-grey
#3A3D42
Iron at rest. Deepens toward charcoal #191B1F as a filing aligns, so the field lines darken into being.
Pole-red
#C0392B
North. Rides your cursor and marks pinned north poles; also tints their field-line streamlines.
Pole-blue
#2C5AA0
South. The pole you drop by default, so a first tap and a sweep draw a true dipole.

Two ink tokens keep text safe over the paper: red-ink #8E2A20 and blue-ink #1F4276 for the rare coloured label, and cool #26282C for body — all above 7:1 on paper, well clear of the 4.5:1 floor.

The type

Archivo + IBM Plex Mono

ArchivoDisplay · variable width
A grotesque built on a rectangular grid — the right voice for an instrument plate. The headline runs at its widest cut (width 125, weight 900) so “the magnet.” fills the plate like a caption stamped on iron: one moment of typographic width used as pressure.
IBM Plex MonoReadings · labels
Every measurement — |B| in gauss, pole count, the field equation, the spec strip — is set monospaced, so the page reads like a bench instrument logging what your hand does.

The signature

A real magnetic field, not a decorative one

The plate is a single canvas 2D layer holding a few thousand iron filings — short needles on a jittered grid, each lying at a random rest angle. They are inert until a pole comes near.

Every pole (the one on your cursor, and each pinned one) is treated as a point of magnetic charge — Gilbert’s 1600 model of a lodestone. The field H at any point is the vector sum of an inverse-square, radial contribution from each pole:

H(p) = Σ qi (p − ri) / |p − ri
// q = ±1 · soft-core in the denominator to tame the singularity

Each frame, for every filing, the code samples H at its position and turns it toward that field’s axis — a filing has no north end of its own, so θ and θ+π are the same to it, and the target is always taken on the nearest half-turn to avoid flips. Rotation speed scales with field strength (a snap up close, a drift far off), and where the field dies to nothing the filing eases back to its rest angle — which is the re-scatter wake you leave behind as you move. Alignment also sets each filing’s darkness, length and weight, so strong field lines emerge as darker, longer iron.

Pair a north with a south and the sum bends into the classic dipole loops. Beneath the filings, a handful of true streamlines are integrated by stepping along the field from each pinned pole until they reach an opposite pole or the plate’s edge — the faint red and blue arcs the needles are snapping onto. Rendering is bucketed into six intensity levels so a few thousand needles cost only six canvas strokes a frame.

Techniques: canvas 2D · magnetic-charge field summation · field-axis alignment with easing · integrated field-line streamlines · bucketed path batching · DPR-capped, resize-rebuilt, IntersectionObserver-gated rAF. No libraries.

Three passes

What each fine-tooth-comb pass found and changed

Pass 1Craft
  • Rendered the plate and drove it in headless Chrome: the two on-screen poles were both north, so they repelled into radial bursts instead of the dipole loops the concept promises. Cause: I had tied the cursor’s polarity to the drop-polarity toggle.
  • Fix: the cursor is now always north; the toggle sets only the pole you drop, defaulting to south — so a first tap and a sweep draw a true dipole immediately.
  • Shortened the eyebrow so it no longer ran out of the scrim and into the live filings; cleaned the mobile instrument panel that was overlapping the hero copy.
Pass 2Depth
  • Added a pin/lift ripple — a coloured ring that snaps out when you drop a pole and contracts when you lift one, giving the compose gesture a tactile magnetic click.
  • Added an iron sheen: a hairline light glint over the most strongly-aligned filings, so field lines read as metal catching the light rather than flat dashes.
  • Brought the integrated field-line streamlines up in presence (second-read detail) so the arcs the filings snap onto are visible on a closer look.
Pass 3Hardening
  • Re-tested 375px (no overflow; wordmark and nav inside the box) and the reduced-motion path: the cursor is disabled, a static demo dipole is settled once, and tapping still composes poles — verified the cursor now moves filings by Δ 0.000 under reduced motion.
  • Gated the render loop behind an IntersectionObserver so it stops when the plate scrolls off screen, on top of the existing tab-hidden pause and DPR-capped resize rebuild.
  • Chanel rule — cut the “sweep px/s” readout, the one metric that didn’t correspond to the physics, leaving three honest field readings.