How this site was built

The concept: LOW ORBIT is a two-night electronic festival on a decommissioned Danish airfield, and the page's one job is lineup + tickets delivered with overwhelming energy. The art direction is sunset-acid — hot coral, ultraviolet, jet black and signal yellow on a black field — with diagonal energy everywhere: tilted orbit rings, a rotated marquee, a photo knocked off its axis.

The hero is the thesis: a live synth loop you can actually start, feeding a canvas visual that listens. Everything else stays disciplined so that one element carries the boldness.

Palette

#0B0A10 jet black
#FF4B33 hot coral
#7B2BFF ultraviolet
#EFFF3B signal yellow
#F4F2EB warm ink
#9A93A8 violet gray

Four loud colors need rules to stay legible: coral marks headliners and structure labels, yellow marks data and interaction (times, hovers, the waveform), ultraviolet is atmosphere (orbit rings, shadows, the marquee band), and everything else is warm ink on black. No gradients between them — they meet at hard edges, like stage lighting.

Type pairing

Archivo — wdth 62, wght 900

Display: compressed variable Archivo. One family covers the whole compressed-to-extended grotesk brief through its width axis (62–125), which also makes the lineup hover possible.

Archivo — wdth 125

Extended cut of the same family for eyebrows and small caps labels — the stretch reads like runway signage.

Space Mono — schedule, coordinates, boarding-pass fields

Everything that is data — times, stage codes, coordinates — is set in mono, so structure is visually separable from voice.

The kinetic hover on lineup names animates the variable width axis itself — the letterforms physically stretch from compressed to wide, a typographic analogue of a filter opening:

.act__name {
  font-variation-settings: "wdth" 62, "wght" 900;
  transition: font-variation-settings .4s cubic-bezier(.3,1,.4,1);
}
.act:hover .act__name {
  font-variation-settings: "wdth" 110, "wght" 900;
  color: var(--yellow);
}

The signature: a hero that listens

The hero canvas draws five tilted elliptical orbit rings with ~190 particles riding them, plus a waveform across the horizon. Pressing Start the signal builds a 128 BPM acid loop from scratch with the Web Audio API — no audio files: a sine-drop kick, filtered-noise hats, and a sawtooth bassline through a resonant lowpass (Q=15) whose cutoff envelope is the classic TB-303 move:

function acid(t, note, accent) {
  const o = ac.createOscillator(), f = ac.createBiquadFilter(), g = ac.createGain();
  o.type = "sawtooth"; o.frequency.value = mtof(note);
  f.type = "lowpass";  f.Q.value = 15;
  f.frequency.setValueAtTime(accent ? 2600 : 900, t);
  f.frequency.exponentialRampToValueAtTime(160, t + 0.22);   // the acid squelch
  g.gain.setValueAtTime(0.26, t);
  g.gain.exponentialRampToValueAtTime(0.001, t + 0.24);
  o.connect(f).connect(g).connect(master);
  o.start(t); o.stop(t + 0.26);
}

A 16-step scheduler with ~140 ms lookahead keeps timing sample-accurate. The master bus runs through an AnalyserNode; each frame the visual reads three bands and maps them to physics — bass blooms the ring radii, mids spin the particles, treble brightens them — while getByteTimeDomainData draws the real waveform:

analyser.getByteFrequencyData(freqData);
bass   → ring radius  (rx *= 1 + bass * 0.5)
mid    → particle speed (a += sp * (0.5 + mid * 3.4))
treble → particle size + color flips to signal yellow

Before you press play, the same renderer idles on slow sine curves, so the hero is alive but calm. With prefers-reduced-motion the canvas renders a single static frame and every animation, marquee and reveal is switched off — the loop still plays if you ask for it.

Photos: the two field shots (night stage, golden-hour crowd) were generated with Nano Banana Pro and art-directed to match the palette — the lasers and the sunset carry the same coral/ultraviolet pair as the CSS.

Structure is information

Three structural devices encode real content: lineup type size = set time (bigger plays closer to sunrise, outlined names close their stage), stages carry aviation codes (RWY / HGR, like the airfield's own charts), and tickets are boarding passes — perforation, stub, barcode, PASSENGER: YOU / FROM: DUSK / TO: DAWN.

Three passes

  1. Pass 1 — correctness + compositionThe rotated marquee band was widening the page — wrapped it in a clipping frame; content hidden behind scroll reveals got a safety net so nothing can stay invisible; the fixed nav gained a blur backdrop after it drowned in the stage photo's lasers.
  2. Pass 2 — elevateStaggered the lineup wall's left edge row by row for the diagonal poster energy, added an ultraviolet echo behind the yellow waveform, gave schedule rows a hover wash, softened the kinetic hover (width 62→100) and let long names wrap so Acid Widow b2b Dial Tone can't break the grid.
  3. Pass 3 — tasteChanel rule: cut the coordinates from the hero eyebrow (the footer already carries them, and they crowded 390 px); verified reduced motion renders a single calm frame, the loop starts and stops cleanly, and both pages screenshot with zero console errors.

Do this yourself

  1. Pin the subject before pixels. Give Claude one concrete world (a dead airfield, not "a festival") — vernacular like RWY codes and boarding passes falls out of the subject for free.
  2. Commission an art direction, not a look. Name 4–6 hex values and give each color a job; ban gradients between them if you want the stage-light feel.
  3. Pick one variable font with a real axis (Archivo's width, 62–125) instead of two static families — you get a pairing and a signature interaction from the same file.
  4. Spend all the boldness in one element. Ask for a hero that does something (synthesize sound, react to it) and keep every other section quiet and gridded.
  5. Make structure carry meaning. Decide what size, order and labels encode before styling them — then say it on the page ("bigger plays closer to sunrise").
  6. Iterate with screenshots, three times. Have Claude screenshot desktop and mobile, critique what it actually sees, and fix — correctness first, then elevation, then removal.
  7. Test the unhappy paths: reduced motion, keyboard focus, 375 px, and the state before the user presses play — the idle state is the one most people see.

Built as one of 25 sites showcasing Claude Fable 5 · photos by Nano Banana Pro · everything else is hand-written HTML/CSS/JS