The Lodestone

Artificial Noodles ·

Inspired by Lodestone on Wikipedia

Built with Canvas 2D · Dipole field math · Batched path rendering · Per-filing hysteresis state

Techniques Two-monopole field sum · Bidirectional angle collapse · Velocity-aligned magnet axis · Cumulative magnetization memory · Opacity-bucketed draw passes

Direction A hand moves over iron, and the iron remembers where it has been

Result A cream-paper field of 15,000 filings that pivot into the dipole curves around your cursor, fuse into darker chains wherever you linger, and keep that record long after the hand has moved on

The Story

A lodestone is a naturally magnetized lump of magnetite — iron-rich rock that was struck by lightning a long time ago and kept the memory. Ancient people noticed that these stones pointed. Suspend one on a string, and it turns until one end faces north. They had no theory of it, only the fact: some stones had a direction inside them, and they could teach that direction to other iron.

The word itself preserves the wonder. In Middle English, lode meant course or leading — a lodestone was a “course stone,” a stone that knew the way. It was the first compass, the first piece of navigational technology, and for a thousand years the only one. A sailor going to sea carried a lump of rock that remembered Earth’s magnetic field and shared it with a needle.

In 1831, Michael Faraday put a magnet near a piece of paper, sprinkled iron filings across the surface, and watched them draw the field. Not the poles — the lines. Curves that left the north pole, looped around through empty space, and returned to the south. He called them lines of force, and argued that the space between magnets was not empty at all. It was full of something invisible that iron could see.

This experience is that piece of paper. Plate I of a natural-philosophy textbook that hasn’t been printed yet.


The Take

You carry an invisible bar magnet on the tip of your cursor. As you move, fifteen thousand iron filings across the cream paper pivot to align with your field — not pointing at you, but through you, along the curves that connect your north pole to your south. Where the field is strong, filings rotate decisively into the dipole pattern. Where it’s weak, they drift in the ambient idle flow. The classic bar-magnet textbook diagram assembles itself under your hand in real time.

But iron doesn’t just pivot. It magnetizes. Linger in one place and the filings within reach start teaching each other — they accumulate magnetization, darken, thicken, and freeze in place. They stop following your cursor and become part of the field themselves. When you move on, the path you took remains behind as a chain of darker, committed filings. The paper keeps a record of your hand.

Marginalia fades in as you work. Plate I, like a 19th-century engraving, is annotated in Roman numerals: A stone that points. A needle that follows. / Where there should be nothing, curves appear. / Between the poles lies a line no needle can name. / Iron teaches iron — chains form where the hand lingers. / Faraday, 1831. He called them lines of force. / Everywhere you moved, the field remained.

The creative connection to the lodestone is the teaching. The stone teaches iron; the iron teaches other iron; and the record of that teaching is the shape of your gesture in the paper.


The Tech

Dipole Field, Two Monopoles

The cursor is a bar magnet. Internally this is modelled as two opposite point sources (monopoles) separated by POLE_SEPARATION pixels, oriented along a magnetAxis vector. The north pole is at pointer + axis × sep/2, the south at pointer − axis × sep/2.

For each filing, the field is computed as the vector sum of two inverse-square terms:

B = (r_N / |r_N|³) − (r_S / |r_S|³)

Where r_N and r_S are displacement vectors from the filing to each pole. Distances are normalized by POLE_SEPARATION before the math runs — this keeps the formula in clean unit-length terms and lets a single FIELD_STRENGTH constant scale everything consistently regardless of viewport size. A softening term of 0.15 is added to the squared distances to prevent the singularity right at the poles from blowing up to infinity.

The resulting (bx, by) is the local field vector. Its direction tells filings which way to face; its magnitude determines how hard they align.

Bidirectional Angle Collapse

A filing is a line, not an arrow. An iron sliver aligned at angle θ looks identical to the same sliver at θ + π — both trace the same short segment. So when a filing is asked to rotate toward a target field angle, the code picks the nearest of the two equivalent orientations:

let d = targetA - f.angle;
while (d > Math.PI) d -= Math.PI * 2;
while (d < -Math.PI) d += Math.PI * 2;
if (d > Math.PI * 0.5) d -= Math.PI;
else if (d < -Math.PI * 0.5) d += Math.PI;

Without this, filings would spin a full 180° when the field flipped past perpendicular, producing visible wobble. With it, the field lines flow smoothly through the dipole.

Velocity-Aligned Magnet Axis

A bar magnet has an orientation. Dragging it across a table, the magnet’s long axis naturally points along the direction of motion. The code tracks pointer velocity each frame and, when moving faster than a threshold, nudges a targetAxis toward the unit velocity vector. The actual magnetAxis then eases toward the target with an exponential spring, so quick direction changes don’t snap — they turn.

This one detail is what makes the field feel embodied rather than procedural. The dipole rotates as your hand rotates. Move in a circle and you can watch the pole axis chase your direction of travel, dragging the whole field pattern with it.

Hysteresis Memory — Chains That Form and Stay

Every filing carries a scalar mag value, initially 0, maximum 1. Each frame, filings within CHAIN_RADIUS of the cursor that are experiencing a strong enough field (fieldInfluence > 0.14) accumulate magnetization at a rate proportional to their proximity and the local field strength:

const prox = 1 - Math.sqrt(distP2) / CHAIN_RADIUS;
f.mag = Math.min(1, f.mag + dt * 0.95 * prox * fieldInfluence);

The consequence is twofold. First, magnetized filings respond more sluggishly to new field changes — their angular spring rate decays with (1 − f.mag × 0.88), so the more magnetized a filing is, the less it cares about where the cursor has moved to. It stays in its last committed orientation. Second, they’re drawn darker and thicker. This is what produces the chains: visible trails of locked-in filings marking the path your hand has taken.

Two-Pass Batched Rendering

Rendering fifteen thousand individual line segments per frame would be prohibitively expensive if each one called beginPath() and stroke() separately. Instead, the code uses two batched passes:

  1. Faint unmagnetized pass. All filings with mag < 0.10 are rendered in a single path at low opacity (rgba(38, 32, 22, 0.40)) and thin stroke (1.0 px). This is the pivoting field — thousands of filings flowing as a single gesture.

  2. Magnetized bucket passes. Filings with mag ≥ 0.10 are drawn across six opacity/width buckets, each in its own batched path. Bucket 0 is the freshly-teaching filings at low opacity; bucket 5 is the fully-committed chains at maximum darkness and line weight (up to rgba(26, 21, 14, 0.94) at 1.80 px). This gives the magnetized filings visual weight — they read as darker ink pressed harder into paper, standing out from the soft field around them.

Seven total ctx.stroke() calls per frame. Device-pixel-ratio-aware scaling. Sixty frames per second at full desktop resolution.

The Paper

Background is #f4ece0 cream with two radial-gradient paper tints in warm browns, plus a vignette that darkens the corners. The effect is a 19th-century scientific-plate page, slightly aged. The filings are drawn in a near-black warm ink (rgba(26, 21, 14, ...)) so they sit on the paper like actual iron rather than a computer display’s pure black.

Right-gutter marginalia uses EB Garamond in italic, with the plate label (Plate I. / The Lines of Force) in small caps above a pair of hairline rules, and narrative notes numbered in lower-roman. Notes fade in as milestones are reached, each over a 1.6-second transition, so the annotations gradually populate the page the way they would in a textbook being read for the first time.

Idle Demo and Mobile

If no cursor input arrives within four seconds, the pointer auto-animates along a gentle Lissajous curve around the viewport center. The field is alive immediately on load — you see what you can do before you know to do it.

Touch events map onto the same pointer state, with the caveat that touch taps don’t build up the smooth velocity history that a drag produces. On iPhone, filing density drops to ~9,000 (from ~18,000 on desktop) to keep the frame rate comfortable on mobile GPUs. The dipole math and hysteresis are identical.


Experience: The Lodestone


This blog post was AI generated with Claude Code. Authored by Artificial Noodles.