Running now, not on video.
Ten plates. Every one of them computes in your tab while you look at it: real WGSL compute kernels, a PDE solver over real Norwegian terrain, elevation tiles streamed for whatever coordinate you type, airborne LiDAR pulled out of a compressed LAZ file by range request, a million points in a single draw call. The readout beside each plate is measured live, on your machine.
This is craft evidence. The commercial work, proving an old calculation core and its replacement equal to the krone, is on the Norwegian main page.
Each plate runs on its own page, so only one live GPU scene is ever resident.
A year of sunlight over a real hillside, computed in your tab
Annual sun hours for every one of 455k terrain cells at 63.44° N. One WGSL pass marches 32 azimuths per cell to build a horizon map — the terrain's own skyline, packed to a byte per direction — and a second pass sums the daylight that clears it, for ~1 300 sun positions across the year. After that, shadowing is a lookup, not a ray: the sun sweeping the slope below runs the same horizon test per vertex at 60 fps. The result is read back once and 48 cells are recomputed in TypeScript from the same sun geometry; the CPU-check row is that comparison, printed live. Click any slope to read that cell's own skyline out of the map — the whole horizon in every direction, with no search radius and no ray cast, because the answer was already computed. The query time printed under the plot is measured, not quoted.
Plate 01 · horizon map + sun-hour integral · WGSL compute Open plate 01 →
A million grid assets, one draw call
A live MapLibre + deck.gl scene rendering 1,000,000 synthetic grid-asset points over Norway. All geometry is uploaded once as binary GPU buffers, so pan, zoom and animation cost no CPU re-tessellation. The hard part is keeping the buffer identity stable across frames so deck.gl never re-uploads.
Plate 02 · deck.gl + MapLibre · WebGL2 Open plate 02 →
Power flow, entirely GPU-resident
Hundreds of thousands of particles advected through an analytic flow field on a WGSL compute shader that models transfer from northern hydro generation to southern load centres. Trails accumulate in a ping-pong texture. The CPU writes one uniform per frame; everything else stays on the GPU.
Plate 03 · WebGPU Open plate 03 →
A risk surface repriced every frame
A 73k-triangle grid displaced entirely in a custom GLSL vertex shader by an animated exposure field of asset clusters that reprice per frame. The fragment shader ramps colour by exposure and shades with a screen-space normal. Zero CPU geometry work; drag to orbit.
Plate 04 · custom GLSL vertex shader · WebGL2 Open plate 04 →
Travel time over real terrain, solved on click
A real-time isochrone over Estenstadmarka / Jonsvatnet outside Trondheim. A WebGPU compute shader solves the anisotropic eikonal equation on a 455k-cell DEM, giving hiking time from any point, with cost from Tobler's hiking function. The full relaxation converges in a single GPU submit per click, so the isochrone snaps in instantly. Real Kartverket-derived elevation; the backend is static files.
Plate 05 · eikonal solver · WGSL compute Open plate 05 →
Urban wind, turbulence included
An unsteady 3D solver over a city (Stam stable-fluids plus a Smagorinsky LES eddy viscosity). Each frame: semi-Lagrangian advection → turbulent diffusion νt = (Cs·Δ)²|S| → pressure projection ∇²φ = ∇·u by red-black SOR, no-flow on buildings. Momentum advection produces real wakes, recirculation and vortex shedding behind the towers. It has to run live, because turbulence is unsteady. 70k tracers, coloured by speed.
Plate 06 · unsteady 3D Navier–Stokes · WGSL Open plate 06 →
An energy-system globe that costs nothing to load
A 3D globe of the Norwegian energy system: offshore platforms, onshore substations and transmission lines over the real coastline. Runs token-free on bundled public-domain imagery: no Ion account, no external calls. The engine is loaded on demand, so it contributes nothing to first paint.
Plate 07 · CesiumJS, lazy-loaded Open plate 07 →
Where an avalanche released up there would stop
The same 455k-cell terrain, read as a hazard map. One WGSL pass takes the slope of every cell; a second gives every cell in the release band — 30–50°, the band NVE's aktsomhetskart is built on — its own thread, which marches a steepest-descent path downhill and stops it where the α line from the release point catches the terrain again. That is the classic α–β runout model: released at h₀, an avalanche runs about h₀ / tan α in the horizontal. Thousands of independent paths, one dispatch, each stamping the cells it crosses — so the amber field is not a buffer around the steep ground, it is how many release zones can actually reach that cell. Click any slope to re-run one path in TypeScript from the same rules and read its long profile with the α line drawn over it; the CPU-check row is the GPU's runout length for 24 release cells against that same march, in metres.
Plate 08 · slope + α–β runout · WGSL compute Open plate 08 →
Any coordinate on earth, streamed while you look at it
Every other terrain plate on this page runs against one DEM baked into the build. This one has no baked data at all: it walks a quadtree over the live Terrarium pyramid, fetches only the 256×256 tiles the camera can see, and displaces a shared mesh against them in the vertex shader. Zoom in and watch the counters — tiles split, stream, and get evicted. A tile that has not landed yet is drawn from its nearest loaded ancestor with a scaled uv window, so the surface never flashes a hole; it only gets sharper. Below the source resolution a slope-weighted fBm adds roughness, with its amplitude pinned to the source texel size so it can sharpen a ridge but never invent one.
Plate 09 · quadtree LOD + live tile streaming · WebGL2 Open plate 09 →
10.6 million LiDAR points, and none of them were downloaded
The source is an 81 MB COPC — a LAZ file whose chunks are laid out as an octree with the index stored inside the file. The plate never fetches the file. It reads the header, reads the hierarchy page, and from there issues HTTP range requests for the octree nodes the camera can see, at the depth the screen can actually resolve. Every point on the canvas came out of the LASzip arithmetic decoder (laz-perf, WASM) in this tab, and the 36-byte LAS records go straight into one interleaved buffer, so RGB, ASPRS class and elevation are three uniforms rather than three uploads. Zoom into the stadium roof and watch Spacing fall: the walk descends only where the pixels pay for it.
Plate 10 · COPC octree streaming · LASzip in WASM · WebGL2 Open plate 10 →
Happy to walk through any of it.
Also built: embedded systems, moving-map engines, production Rust against Norwegian national geodata, and a live product of my own at solrapport.no.
bjreppen@gmail.com