Zephyr

How this was made

ZEPHYR is a book of six weather poems — mistral, sirocco, chinook, harmattan, bora, zephyr — each spoken by the wind itself. The page has one job: make you feel the weather change when you turn the page. The background is not a picture of wind; it is a wind simulation you are standing in.

The signature element

The entire viewport is a canvas flow field: roughly two thousand particles ride a curl-noise velocity field. A scalar potential ψ is built from two octaves of simplex noise; the velocity at any point is the perpendicular of its gradient (∂ψ/∂y, −∂ψ/∂x), which makes the flow divergence-free — particles never bunch up or drain away, exactly like a 2-D incompressible fluid. On top of that curl each wind adds its own prevailing direction and speed.

Changing poems does not restart the field — it retunes it. Direction, speed, turbulence, noise scale, stroke width, trail persistence and all colours interpolate over ~1.9 s, so you watch the mistral's cold vertical rain bend and warm into the sirocco's languid loops. Trails come free: each frame repaints the sky gradient at low alpha, so strokes decay like breath on glass. The noise field itself is advected downstream at about half the wind speed, which is why the texture streams instead of boiling in place.

Readability over the field is handled twice: a radial scrim of the sky colour sits behind the text block, and every particle segment inside an invisible ellipse around the poem is drawn at reduced alpha — the wind literally thins out to let you read, then thickens again at the margins.

Six weathers, six palettes

mistral
EAF2F7 C9DCEA 5E87A8 3E607E 1D3247

Scoured ice-blue sky. Fast, near-straight strokes falling NNW→SSE with short trails — the wind that strips Provence to blue enamel.

sirocco
F5E8D2 E3BF93 B06F3B 8C4F26 46280F

Saharan dust over the Mediterranean. Turbulence dominates speed, so the field curls into slow feverish loops with the longest trails of the set.

chinook
F7E8E4 EBBFAC C0795A 8F4F30 3F231A

Warm rose light out of season. Fast west→east flow with big, low-frequency waves — long combed filaments, snow-eater warmth.

harmattan
F1EDE0 DBD1B6 A29467 7E7048 37301D

Desaturated khaki haze. The densest and faintest particles — wide strokes at low alpha, almost laminar, a gauze across the sun.

bora
E9EEF2 BFCBD6 54687A 39495A 16232E

Cold steel over Trieste. The fastest base speed of the six with hard, thin strokes — violence read as long gusts, not confetti.

zephyr
EEF4EA D1E2CC 6F9678 4F7358 1F3527

The gentle one, saved for last: pale olive-green, the slowest speed, the most persistent trails — fine drifting threads that barely crease the sea's skin. This page borrows its palette.

Type

EB Garamond italic carries the poems and the huge lowercase wind names. Wind belongs to old books — sailing directions, the Beaufort scale, myth — and Garamond's italic has the right lean; the display name is even rotated a fraction of a degree downstream of the current wind, the way Van Gogh's cypresses hold theirs. Outfit does everything instrumental — eyebrows, bearings, the anemometer — in small tracked capitals, the voice of a weather station log. The scale is deliberately extreme: 10.5 px instrument labels against a ~7.8 rem wind name, with nothing in between except the poem itself.

Techniques

No libraries — one canvas, vanilla JS. Simplex-noise curl field with finite-difference gradients; per-wind parameter objects interpolated with an eased 1.9 s transition (angles lerped along the shortest arc, colours in RGB); trail rendering by translucent gradient repaint; particle strokes batched into nine paths (three colours × three falloff levels) per frame. UI colours ride registered CSS @property custom properties so ink, accent, sky and scrim cross-fade in pure CSS. The cursor drags a gust through the field, and clicking the sky releases an expanding ring impulse. Wheel, arrow keys, digits 1–6, swipe and the wind list all turn the page; each wind deep-links by URL hash. Reduced motion swaps the animation for a one-shot static etching of the same field traced with short streamlines.

Iteration log

Pass 1 — Craft

  • First render read as scratch marks: trail persistence was too short everywhere. Halved the per-frame fade (mistral 0.10→0.05 and similar across the set) so strokes became filaments instead of dashes.
  • The three warm winds blurred together as "beige curls". Re-argued each: chinook got a rosier sky and long low-frequency waves (scale 0.0014→0.0011, turbulence 0.85→0.6), harmattan went desaturated khaki and near-laminar (turbulence 0.25), sirocco kept the loops as its signature.
  • Bora's violence rendered as confetti — small eddies at scale 0.0024. Rebuilt as long gusts: scale 0.0013, turbulence 0.45, speed 5.2.
  • Zephyr's drizzle-like dots became threads: fade 0.028→0.015, alpha down to 0.34.
  • Tightened mobile eyebrow tracking and footer size after a 375 px check showed loose wrapping.

Pass 2 — Depth

  • Second-read details: the wind name leans a fraction of a degree downstream of the active wind; the tab title becomes the wind's name; each wind is hash-addressable (#bora).
  • Micro-interactions: moving the cursor drags a decaying gust through the particles; clicking open sky releases a ring impulse; wind-list names nudge 2 px on hover.
  • The anemometer's km/h reading wobbles on the same simplex noise that drives the field — the instruments and the weather share one atmosphere.
  • Refined the change-of-wind choreography: text exits up on a 0.36 s ease while the field re-tunes over 1.9 s, then poem lines rise in a 95 ms stagger — the words settle just as the new weather establishes.

Pass 3 — Hardening

  • 375 px pass: wind list collapses to roman numerals, anemometer and hint retire, poem holds nine lines comfortably above the fold at 667 px height.
  • Reduced motion: verified the static-etching path renders each wind without the rAF loop, and live changes of the media query switch modes without reload.
  • rAF loop pauses on document.hidden (verified in a background tab); devicePixelRatio capped at 2; resize re-seeds only off-screen particles.
  • If the 2-D context fails, the CSS sky gradient and full text remain — the site degrades to a quiet, readable book of poems.
  • Chanel rule: removed the anemometer arrow's wobble — it now holds steady on the bearing while only the reading flickers. One fidget fewer.
  • Final copy read; killed a weak line break in the harmattan poem ("and then the near ones").