Build guide · Site 25 of 25 — the series closes at the top of the world

How the sky was drawn: building 69° NORTH

1 · Concept & art direction

69° NORTH is a polar expedition company running aurora voyages out of Tromsø; the page's one job is to sell the March sailing. The art direction treats the aurora as light, never as UI chrome — green and violet exist only in the sky (and one respectful glow), while the interface stays in polar-night blues, snow white, and a single expedition orange for everything you can act on.

There are deliberately no photographs. The hero sky is a live GLSL shader — the proof of skill is that you believe it anyway. Structure encodes truth: the voyage log is a real six-day sequence, coordinates are real places, and the "honest notes" section does actual expectation-setting a real expedition outfit would do.

2 · Palette & type

Polar night#050B17 · page ground
Deep water#0D1A2E · panels
Snow#DFEAF6 · text
Expedition orange#FF7B3D · the one warm accent
Aurora#57E6A4 → #8F7BFF · light only, never chrome
The night is the destination.

Fraunces (optical sizing on, weight ~340) — an old-style revival with the slightly wonky warmth of a 1900s expedition journal. Set light and large, it reads as engraved plates, not a blog serif.

VOYAGE LOG · TROMSØ → ALTA

Archivo stretched to width 118 for expedition-crate labels, plus IBM Plex Mono for coordinates, soundings and KP readings — instrumentation, used as ornament.

3 · Techniques — the signature sky

The hero is one fragment shader on a raw WebGL1 context — no three.js, no libraries. Curtains use the classic layered-plane raymarch (in the lineage of nimitz's "Auroras"), retuned and composed into a full scene: the ray marches through 30 stacked altitude planes, samples a rotating triangle-wave fbm at each, and accumulates colour along a green→violet spectral ramp:

for (float i = 0.; i < 30.; i++) {
  float pt = ((.85 + pow(i,1.4)*.002) - ro.y) / (rd.y*2. + .4);
  vec2 p  = (ro + pt*rd).zx + vec2(uTime*.018, 0.);
  float d = curtain(p, .055);            // triangle-noise fbm, rotated per octave
  vec3 c  = (sin(1. - vec3(2.15,-.5,1.2) - uScroll*.5 + i*.043)*.5+.5) * d;
  avg = mix(avg, vec4(c,d), .5);         // vertical smear = curtain rays
  col += avg * exp2(-i*.065 - 2.5);
}

Around it, in the same shader: hash-grid stars with per-star twinkle, two ridged-fbm mountain silhouettes (the far ridge picks up 5% of the aurora's colour, like lit snow), and a fjord reflection — the scene function re-sampled with a mirrored ray, noise-rippled x, darkened and depth-faded. Scroll feeds a uniform that deepens the curtains toward violet; the pointer leans the camera a few degrees. prefers-reduced-motion renders one calm frame and stops the loop.

The second device is the nautical chart: a hand-drawn SVG of the actual coast (Kvaløya, Lyngen, Kvænangen, Lopphavet) with graticule, soundings and a title block. The route is a single path whose stroke-dashoffset is driven by the log's scroll progress; a vessel glyph rides getPointAtLength() and rotates to the path tangent, and each day's marker ignites as the reader reaches it.

const L = route.getTotalLength();
route.style.strokeDashoffset = L * (1 - progress);   // never un-draws
const pt = route.getPointAtLength(L * progress);
vessel.setAttribute('transform',
  `translate(${pt.x},${pt.y}) rotate(${angleToTangent})`);

4 · Three iteration passes

5 · Do this yourself

  1. Give Claude a one-line brand and a one-line job. "A polar expedition company; make people book the March sailing." Everything else should be derivable from those two lines.
  2. Assign one signature element and protect it. Here: a live aurora shader. Say explicitly that everything else must stay disciplined so the signature reads.
  3. Ban the defaults. Name the clichés you don't want (starfield heroes, purple SaaS gradients, three-card grids) so the model can't fall back on them.
  4. Ask for structure that encodes truth. A six-day voyage is a real sequence, so day numbers earn their place; coordinates and soundings are real, so they can be ornament.
  5. Demand the shader be composed, not pasted — stars, ridgelines and a reflection in one scene function, with scroll and pointer as uniforms, and a reduced-motion still frame.
  6. Iterate with screenshots, three times. Correctness, then elevation, then taste — and actually remove something in the last pass.
  7. Write copy like a brand, not a template. The honest-notes section ("The aurora is weather") does more selling than any adjective.

BUILT BY CLAUDE FABLE 5 · SITE 25 OF 25 · THE SKY IS CODE — THE REAL ONE IS BETTER

← Back to 69° NORTH