This site is a prototype too.

One typeface family, one colour tone per project, one signature: the contour lines on the home page. This page explains how it is built. The numbers are measured on every build.

The contour lines

What they are
The contours of a soft noise field, like the lines on a hiking map, drawn by a shader on a canvas behind the whole page. On the first screen the same lines trace the labyrinth below: its depth is read as terrain, and scrolling melts it into the landscape.
How they move
They drift slowly and scroll at a third of the page’s speed, so they sit behind the content. Under your pointer the field rises and the lines give way like a wave.

The map

What it is
A small, playable version of Klangraum, my map of music. It uses the app’s data for 19 genres and the app’s blend rule: every place belongs to the nearest genre, and close to a border the neighbour mixes in, until both stand at 50% on the line itself.
What it leaves out
Subgenres, zoom and the music. In the app, Google’s Lyria model generates the blend live; here the readout names what you would hear. Two simplifications: a border considers every genre instead of direct neighbours only, and the coast is a radius around each genre.
Three ways to draw it
Before the script runs, and without it, CSS prints the map: a tone map of 138 × 148 values, one per dot, is multiplied with a dot pattern and sharpened by contrast. With WebGL2 a fragment shader takes over and adds the listening circle and the wave. Without WebGL2, the script moves the CSS print instead.
Input
Drag with momentum, tap a genre to glide there, or focus the map and use the arrow keys. On a touch screen a vertical swipe still scrolls the page; a sideways drag moves the map. The portrait on the About page is printed the same way.

The labyrinth

The figure behind the headline on the home page, here on its own: a flight through a Menger sponge, a cube that keeps splitting into smaller tunnels, drawn as fine lines through a kaleidoscope. Drag to spin it, click or tap to choose the next way, or focus it and use the arrow keys.

Motion

cubic-bezier(0.16, 1, 0.3, 1)
ElementBehaviourTiming
HeadlineLines rise out of a mask, once per page1 s, 80 ms apart
Contour linesDrift slowly, rise under the pointer, pull together when you scroll fastcontinuous, 30 frames a second
Project rowThe cover grows out of the rule and runs along it with the pointer0.2 s, then a spring
Chapter titlesOne-word titles widen as they scroll into viewtied to the scroll position
SenzuDrag turns to the next view, letting go snaps to ita spring, with the speed of the hand
MapA wave from the needle, then one glide into the next genre1.7 s and 2.6 s, then it rests
ImagesOpen from the bottom edge when they scroll into view1 s
Page changeTitle and cover of the project you clicked travel into its page0.6 s
ControlsLinks, buttons and labels answer; pressing gives way0.2 s and 0.14 s

One curve and three durations (0.2 s, 0.6 s, 1 s), shared by the stylesheet and the scripts, plus 0.14 s for the press of a control. Things that follow the hand or get thrown (project row, Senzu, the table, the map) run on springs instead, so they can be interrupted at any point. Keyboard actions do not animate. With “reduce motion” switched on in your system there is no smooth scrolling, no entrance, no page morph and no momentum; videos wait for a click.

Measured

  • 55.2KBJavaScript on the home page, gzipped
  • 210KBHome page, first load
  • 13Requests on first load
  • 0Cookies and trackers

Measured automatically on every build (last: 2026-10-02). Videos load only when they scroll into view and are not counted.

Accessibility

  • WCAG 2.2 AA is the target. On the dark ground the text colour reaches 12 : 1 and the accent 7 : 1 in every project tone, so both also work as small text.
  • Everything is readable without JavaScript, including the map. If the script fails, hidden content appears after 1.2 seconds anyway.
  • The map works with the keyboard: focus it, then use the arrow keys. A screen reader hears the blend once the map has come to rest.
  • Every looping video has a pause button. Headlines are split into lines for the entrance only; assistive technology gets the whole sentence.

Your browser

  • Page-to-page view transitionsin useplain page change
  • Scroll-driven animations for the header line and reading progressin usestatic
  • WebGL2 for the labyrinth and the mapin useCSS print
  • Balanced and pretty text wrappingin usedefault wrapping

Each of these is an enhancement. Where a feature is missing the site falls back quietly. Press G on any page to see the twelve-column grid.

Built with

Framework
Astro 7 with MDX, static output, 8 pages
Motion
GSAP (core, SplitText, InertiaPlugin), Lenis for smooth scrolling with a mouse, WebGL2, cross-document View Transitions, CSS scroll-driven animations
Loading
Speculation Rules for instant navigation, build-time image sizes, lazy media, no web fonts from third parties
Type
Mona Sans and Mona Sans Mono by GitHub, under the SIL Open Font License, reduced to three small files with only the axes and characters this site uses
Process
Designed by me. Much of the code was written with an AI coding agent: I set direction and made the design calls, the agent implemented, and I checked every step in the browser. The same way I built Klangraum.

Keys

1
Klangraum
2
BMW · CES 2025
3
orca
4
Senzu
G
Show the layout grid
?
Open this list
←→↑↓
Move the map, the turn view or a picture once it has focus