CONTOUR ← Back to site
Build guide · Sheet 16 of 25

A trail atlas that redraws itself.

CONTOUR is one of 25 sites designed and built by Formwork to show web design, motion, and restraint. The hero is a living topographic map — real iso-contours computed live from a drifting noise field. Here is exactly how it was made.

The idea

The brief was cartographic: an expedition brand whose homepage feels like reading a map before a walk. Rather than a photo of a mountain, the mountain is generated and contoured on the fly — nested elevation rings that drift, breathe, and label their own altitude. Everything else — condensed Oswald headings, a Spectral serif for route names, mono for coordinates — is set on warm paper to frame that one moving surface.

The stack

The signature technique: marching squares

Each frame samples a scalar field onto a grid. For every cell — a square of four grid points — the four corners are tested against an iso-value. That gives a 4-bit case (0–15), and each case says which cell edges the contour crosses. Linearly interpolating the crossing point along each edge yields the line segment. Do that for ~17 iso-values and you have a topographic map; make every fourth one thicker and it reads as index contours.

// four corners → 4-bit case → interpolated crossings
let idx = 0;
if (tl > L) idx |= 8; if (tr > L) idx |= 4;
if (br > L) idx |= 2; if (bl > L) idx |= 1;
const ax = x0 + sx*(L-tl)/(tr-tl);   // top edge X
const dy = y0 + sy*(L-tl)/(bl-tl);   // left edge Y
switch (idx) {
  case 7: case 8: seg(ax, ay, dx, dy); break;  // one corner cut
  case 3: case 12: seg(dx, dy, bx, by); break; // left→right
  // …14 cases, two saddles
}

The field itself is 3D value noise: sampling a slowly advancing z makes the terrain morph smoothly instead of teleporting, while a few Gaussian "peaks" with drifting centres guarantee the iconic nested rings. A tiny sine offset on every iso-value makes the whole map breathe. Labels are placed greedily along index contours and drawn with a paper-coloured halo — which is exactly how a paper map leaves a gap in the line for its numbers.

Details that matter

Ship it on GitHub Pages

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-contour --public --source=. --push
gh api --method POST /repos/OWNER/formwork-contour/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's the whole recipe: one contour engine, a little motion, strong type, and static hosting. The other 24 sites each swap the central technique — shaders, particles, kinetic type — but the discipline is the same.