← Back to BUFFON
Colophon · The making of

BUFFON, counted out.

A live Monte-Carlo estimator of π, built in canvas 2D — where a physical constant condenses out of nothing but scattered needles and two integers.


The idea

BUFFON is a fictional single-page instrument for one of the oldest surprises in probability. Drop slim needles onto a floor of evenly spaced boards; count the ones that come to rest across a seam. When a needle is as long as a board is wide, the crossing probability is exactly 2 ⁄ π — so the ratio of throws to crossings estimates π, and the error shrinks like 1 ⁄ √N. The page's single job: make a viewer see a constant assemble itself from pure chance, with the resting floor already mid-convergence so the first glance reads π ≈ 3.14.

Palette

Argued from the subject: a dark oiled floor, iron needles catching lamplight, the few that cross a seam glowing warmer.

Board oak
#1C1712
The oiled floor — near-black with a brown undertone so needles read as metal, not neon.
Needle
#D9A441
Line/mark accent — brass lamplight on the needles that fall between the seams. Marks only.
Crossing ember
#B5502E
The needles that pay — the ones counted toward π glow a hotter iron.
Parchment ink
#EDE2CC
Body ink, derived light for 4.5:1+ on the oak. Copy is never set in the mark accents.

The bright #D9A441 and #B5502E stay on the needles and the trace line. Type runs in parchment #EDE2CC and its dimmer sibling #C4B99E, keeping the ink/line split the collection insists on.

Type

Spectral
Display & prose — a lecture-hall serif, 18th-century composure for an 18th-century puzzle.
3.14159   2N ⁄ C
JetBrains Mono — the π readout, counts and formula. Tabular figures so the estimate ticks without reflow.

The typographic bravery lives in the readout: the estimate paints only the digits of π you have genuinely earned in ember, and dims the rest — so the type itself tells you how much of the constant the chance has yet to buy.

Technique

Canvas 2D · accumulation buffer

The floor is an offscreen accumulation buffer. Every settled needle is stamped into it exactly once and never redrawn, so thousands of them cost nothing per frame; the visible canvas each frame is just that buffer plus the handful of bright needles currently falling, their crossing rings, and a soft glow. Each needle is a centre, an angle, and one crossing test — floor((cx−h)/t) ≠ floor((cx+h)/t), where h is its half-width projected onto the axis across the boards — and the estimate is only ever 2N ⁄ C.

The resting frame

A blank floor would read as "waiting". So the rest state is a genuine ~1,300-needle experiment, chosen from a few hundred seeded runs of a Mulberry32 generator and replayed deterministically — an honest sample that happens to land cleanly near 3.14, without inflating the count until the floor turns to mush. Alongside, the error trace plots |estimate − π| against needles thrown, hugging a dashed 1 ⁄ √N envelope: the visible promise that the last digits are ruinously expensive.

Iteration log

Pass 1 — Craft

The first resting floor was a mistake you could see in one screenshot: ~4,400 overlapping needles at high opacity formed an illegible mat and buried the ruled floorboards completely — the concept's whole identity was gone. I rebuilt the rest state as a deterministic best-of-K seeded experiment at a far lower count, dropped the stamp opacity, and separated the crossing and non-crossing tones so the ember count reads. Re-checked the P(cross) label against the true 2 ⁄ π target.

Pass 2 — Depth

Brought the wooden floor forward — stronger alternating plank shading and each seam cut as a shadow-plus-highlight groove, so the boards read beneath the needles (the second read: it is an actual floor, not a void). Added the ember pulse ring that blooms where a crossing lands, the live earned-digit highlight, and eased the rain to a slow 760 ms cubic fall so it reads as deliberate scatter rather than a stutter.

Pass 3 — Hardening

Verified 375 px with nav and wordmark inside the viewport box and a clean scrollWidth; fixed the mobile eyebrow wrap and lifted the hint with a scrim shadow. Confirmed the prefers-reduced-motion path renders a settled static frame near 3.141 and starts no animation loop. DPR capped at 2, re-seed on debounced resize, rAF paused on document.hidden. Chanel rule: removed the wood-grain streaks — invisible beneath the needle field, pure cost.