ZODIAC is one of 25 sites designed and built by Formwork to demonstrate web design, motion, and restraint. Here is exactly how the star map was made — and how you can build the same.
The brief was "read the sky." Instead of a photograph of stars, the hero is a generative, interactive star map: a few hundred twinkling stars and twelve stylised constellations laid out on the ecliptic — the sun's yearly road — arranged as a slowly turning wheel. Everything else (an elegant serif, gold on midnight, wide small-caps labels) exists to let that sky breathe.
<canvas> — no library, no WebGL, ~13 KB of JavaScript.requestAnimationFrame loop; CSS transitions handle reveals and the intro.main branch.Everything lives in a small world coordinate system centred on the screen. Each constellation is a set of node offsets around an anchor placed on an ellipse; the twelve anchors sit at 30° intervals, Aries at twelve o'clock. Every point is rotated by one shared angle that creeps forward each frame, so the whole sky drifts as the real one does — one turn every seventeen minutes.
// world -> screen: rotate, scale, then add camera + depth parallax
const rx = u * cos - v * sin, ry = u * sin + v * cos;
const sx = cx + rx * S + cam.x + par.x * depth;
const sy = cy + ry * S + cam.y + par.y * depth;
Stars carry a depth, so they parallax by different amounts as the cursor moves —
near stars swim, far stars barely stir. Hovering near a constellation (or choosing a sign)
eases its glow toward 1: the lines brighten, the nodes swell, a name fades in, and
the camera nudges a little toward it. Shooting stars spawn on a small per-frame probability and
streak along a fading gradient tail.
position:fixed backdrop, so hovering a house in the grid lights its figure behind the whole page.prefers-reduced-motion the loop never starts: one static frame renders, no drift, no shooting stars; hover still re-draws once to highlight.devicePixelRatio is capped at 1.5; the 2D context is feature-detected, with a CSS-gradient starfield fallback if it is missing.Every site here is static, so hosting is three commands:
git init -b main && git add -A && git commit -m "ship"
gh repo create formwork-zodiac --public --source=. --push
gh api --method POST /repos/OWNER/formwork-zodiac/pages \
-f 'source[branch]=main' -f 'source[path]=/'
Use relative paths (./main.js, not /main.js) because project
Pages live under /repo-name/. Add an empty .nojekyll file so every asset serves verbatim.
That is the whole recipe: one canvas, a rotating coordinate system, a little easing, strong type, and static hosting. The other 24 sites each swap the central technique — shaders, particles, isometric 3D, audio-reactive gradients — but the discipline is the same.