Design guide · Fable Websites 09

Apex Expeditions

How this showpiece was concepted, art-directed and built — one HTML file, one stylesheet, one script, three AI-generated photographs, zero build step.

Concept

The brief: an elite alpine guiding company. Mood — thin air, cold light, quiet danger. National Geographic reportage discipline crossed with the restraint of a Norwegian design studio: enormous imagery, a strict grid, copy that states facts and stops.

The organizing metaphor is altitude. The page itself is an ascent: a fixed rail on the right converts scroll progress into metres (0 m at the top of the page, 8,091 m — Annapurna I — at the footer). Every big numeral on the site is an altitude, a ratio, or a count of people who came home.

Glacier#F4F6F8
Granite#2B3038
Ice#A8C6DA
Signal#FF5C1F
Deep slate#171B21

Signal orange is used the way it is used on a mountain: sparingly, and only for things that matter — CTAs, the route line, the number zero.

Archivo · 72% width · 900
6,419 m
Display: Archivo variable (width axis 62–125) condensed for headlines and numerals · Body: Inter

One variable font family (Archivo) covers the whole display range — font-stretch at 70–82% gives the condensed, expedition-stencil voice without loading a second display face. Inter carries body copy. Numerals are always tabular-nums so tickers don't wobble.

Assets — GPT Image 2

Three photographs, generated with gpt-image-2 at 1536×1024, quality high, then recompressed to WebP q80 (2.1 MB → 265 KB for the hero). Each was visually inspected before acceptance; all three passed on the first generation. The actual prompts:

Generated hero image: golden-hour alpine face with tiny climbers

hero-face.webp — the wall

gpt-image-2 · 1536×1024 · high

A cinematic large-format film photograph of a monumental alpine north face at golden hour, a colossal wall of granite and blue glacial ice towering into thin cold air, its upper ramparts catching low amber sunlight while the lower couloirs stay in deep blue shadow. Two tiny roped climbers, almost invisible specks in signal-orange shells, ascend a snow arête at the lower third, giving staggering scale. Spindrift streams off the summit ridge against a deep cobalt sky. Shot on a telephoto lens compressing the face, crisp detail in rock texture and ice, subtle 35mm grain, restrained Nordic color grade of glacier white, granite grey, ice blue and one note of orange. Vast, silent, quietly dangerous mood. No text, no watermark.
Generated image: rope team crossing a corniced ridge in storm light

ridge-storm.webp — the traverse

gpt-image-2 · 1536×1024 · high

A cinematic film photograph of a knife-edge ridge-line traverse in storm light: a single rope team of three alpinists in muted shells crossing a corniced snow ridge that falls away thousands of meters on both sides, low torn clouds racing across the face below them, a shaft of cold silver light breaking through heavy slate-grey storm sky and striking the ridge crest. Wind-blown snow ripping horizontally off the cornice. Telephoto compression, high shutter freezing the spindrift, muted palette of graphite, steel blue and bone white with faint warm light on the snow, fine film grain, National Geographic expedition reportage style. Severe, elemental, disciplined mood. No text, no watermark.
Generated image: base camp tents glowing at blue hour, headlamps on the glacier

basecamp-blue.webp — the camp

gpt-image-2 · 1536×1024 · high

A cinematic film photograph of a high-altitude base camp at blue hour, a scatter of small geodesic expedition tents glowing warm amber from within on a moraine bench beneath an immense dark mountain wall, two thin headlamp beams tracing a switchback line up the lower glacier in the distance, the sky a deep luminous indigo fading to pale ice blue over the ridgeline, stars just appearing. Long exposure stillness, faint mist over the ice, tones of deep slate, indigo, glacier blue and warm tent-orange, subtle 35mm grain, quiet documentary composition with the tents small in the vast frame. Hushed, cold, expectant mood. No text, no watermark.

Techniques

ALayered hero — Ken Burns + ridge parallax

The hero photo runs a 34-second alternating Ken Burns zoom in pure CSS. Two hand-drawn SVG ridge silhouettes sit over it; GSAP ScrollTrigger scrubs them upward at different rates (−26% and −60% yPercent) while the photo drifts down (+14%), so the foreground ridge slides over the image and the wall appears to recede as you leave the valley.

gsap.to("#ridgeNear", { yPercent:-60, ease:"none",
  scrollTrigger:{ trigger:"#hero", start:"top top",
                  end:"bottom top", scrub:true } });

BAltitude rail — scroll as ascent

A fixed vertical track maps document scroll progress to 0–8,091 m. The readout uses tabular-nums, the fill is signal orange, and it fades in only after you leave the hero — chrome earns its place.

CSelf-drawing route profile

The elevation cross-section is a single SVG polyline. Its getTotalLength() feeds stroke-dasharray/-offset, and a scrubbed ScrollTrigger tween draws it as the section crosses the viewport. Each camp marker carries a data-at fraction; when the draw progress passes it, the marker pops in with a radiating pulse.

function setProgress(p){
  profLine.style.strokeDashoffset = L * (1 - p);
  camps.forEach(c => c.classList.toggle("on",
    p >= parseFloat(c.dataset.at)));
}

DTopographic contours

Section backgrounds carry sparse SVG contour paths that draw in on first intersection (3.2 s dash transition) and then drift ±30 px on a slow alternating loop — the map is never quite still.

EAltitude tickers

Expedition cards reveal a slate stats panel on hover; the altitude counts up with a cubic ease-out on every fresh hover (re-armed on leave). On touch layouts the panel is always visible and ticks when scrolled into view. Stat-strip and guide numerals use the same ticker via IntersectionObserver.

Everything degrades: prefers-reduced-motion zeroes the animations and prints final values; if the GSAP CDN fails, reveals and the profile draw fall back to IntersectionObserver.

Process — three passes

  1. Pass 1 — structure & truth to the grid

    Desktop + 375 px screenshots, console audit, snapshot review. The outlined "EXPEDITIONS" clipped at 375 px (clamp floor too high) — retuned the type scale. Redrew both hero ridge silhouettes: the first drafts repeated uniform triangles and read as clip-art. Closed the route-profile area fill at the summit instead of the SVG edge (it had a false vertical cliff). Killed a lone-"M" wrap in guide stats, scaled camp labels up inside the SVG for mobile, deepened the hero top gradient for nav contrast, and rewrote a lede that said "hover" to be input-agnostic. Added difficulty pips (I–V, skewed orange squares) to the stat panels.

  2. Pass 2 — motion & texture

    The application section had a dead right column — filled it with a "What happens next" ladder and a live-availability line. Shortened the ridge stack at 375 px (34 vh read spiky). Added the altimeter-sweep hover line over card imagery, a diagonal sheen on solid buttons, and the footer sign-off that closes the altitude metaphor: "You are at 8,091 m. Descend safely." Verified the stats panel opens for keyboard users via focus-within.

  3. Pass 3 — polish & edge cases

    Anchor targets got scroll-margin-top so the fixed header never overlaps section heads. Card imagery now settles from 1.1× to 1× on first reveal. Added a <noscript> escape hatch so reveals, contours and the route line are fully visible without JavaScript. Final audit: zero console errors on desktop and 375 px, no horizontal scroll, semantic tree verified (banner/main/articles/dl), images ≈ 0.47 MB total.

Ship it

The site is fully static — deploy the directory as-is:

npx wrangler pages deploy . --project-name apex-expeditions

No build step, no dependencies beyond two pinned CDN scripts (GSAP 3.12.5 + ScrollTrigger) and Google Fonts.