How the flame was lit.
WICK is a dark room you read by candlelight. A single canvas holds the dark; a real guttering flame rides your cursor, and everything you can read, you read by the pool of light you carry. This is what is behind it.
The concept
A page in the fourth wave, Second Person — inert until you drive it. The room has no light of its own; the visitor is the light source. Its single job: make you feel the flame as something fragile that you are carrying, so you slow down to keep it. Move gently and it steadies, brightens and drips wax. Rush, and it flattens and the room drops to black.
Palette
Every colour is a candle in a dark room. Per the collection's ink/line rule, the two bright flame tokens drive light and marks only; all text sits on a warm parchment ink ladder so nothing small is left at low contrast.
Type
A candlelit, high-contrast garalde. Its thin strokes and generous italic feel like reading by a small, unsteady light — exactly the mood — and it holds up huge in the hero and quiet in the passages.
A clean geometric sans for eyebrows, section numbers, nav and the hint. Its even, quiet forms keep the instrument chrome from competing with the serif's warmth.
Techniques
One fixed full-screen canvas sits above the prose. Each frame it fills with a near-opaque veil of the room colour, then switches to destination-out and punches a soft radial hole — the pool of candlelight — whose radius and clearing strength track the flame's health. It switches to lighter for a warm additive glow, then draws the flame from two stacked quadratic teardrops (orange body, near-white core) sheared by its lean.
The physics is the point. Health is a 0–1 value driven by real pointer speed (smoothed px/s): wind pressure = clamp((speed − 150) / 1250), and health chases 1 − wind — blowing out fast (rate 3.6) and recovering slow (0.85), the way a real candle does. Pool radius, veil opacity, flame height and glow all read off health, so moving fast literally drops the room toward black and holding still brightens it. Hold steady long enough and wax beads at the lip and falls; hold longer and it blooms once, as a reward.
Crucially, the prose lives in the DOM underneath the canvas. If WebGL had been used it would need a fallback; here, if the canvas or JavaScript ever fails, nothing is hidden — the reading is simply printed on the dark. Canvas discipline follows the house rules: DPR capped at 2, sized to the viewport on resize, the rAF loop paused on document.hidden, and one frame painted immediately so there is never a blank flash.
Iteration log
Lifted --ink-mute from #7E6F5B to #8C7C64 so nav and section labels clear ~4.5:1 on the near-black room. Caught the hint's decorative sub-label set in --smoke — effectively invisible at ~1.3:1 — and re-tiered the whole hint onto the parchment ink ladder, carrying hierarchy by size and tracking rather than by vanishing. Confirmed all body prose runs on ink, never the flame accent.
Added a cup-to-steady micro-interaction — hold the button (or finger) down and a cupped hand shelters the flame: wind is halved and recovery quickens, so you can carry it through a fast move without losing the room. Gave the flame idle life — a slow value-noise sway on the tip and a 2% height breathe, so it is never perfectly static. Added the patience bloom: hold it steady about four seconds and it opens once with a soft pulse and a released drip, then must be earned again — a detail you only meet on the second visit.
Chanel rule: removed the rising ember sparks — guttering, wax drips and the blow-out smoke wisp already carry the flame, and the sparks read as a separate effect. Verified 375px (scrollWidth 375, nothing spills), reduced-motion (the flame locks lit and calm — flicker, sway and breathing off — but still follows your hand), :focus-visible on every link, and the visibility-paused loop. Final copy read; made the hint device-agnostic — the light follows your hand.
Driven headless-Chrome checks (slow vs fast mousemove, state read live from window.__wick):
slow → health 0.95 · pool 261px · flame 58px · fast → health ~0.00 · pool 34px · flame 10px
recovery when steady again → 0.00 → 0.94 · cupped through a fast flick → 0.57 · reduced-motion holds 1.00 · zero console errors.