Letters of water: building the WebGL tunnel on vorluno.dev without a 3D library
WebGLCraftWebsitePerformance

The second screen of vorluno.dev is a sentence you travel through. The letters ripple under your cursor. There is no 3D library behind it — one shader, one quad, and a rule that nothing draws when nothing moves.
We wanted the statement of the studio to be read the way you walk into a building: one line at a time, each one closer than the last, the whole thing settling when the last line arrives. Not a slideshow. A tunnel. And we wanted the text to feel like it had a surface — water, not glass — so the cursor would leave rings on it.
Why the text is a texture
The water effect is a displacement of pixels around the cursor: rings that are born where it passes and fade as they spread, and a lens right under it. In the DOM you can only fake that with SVG filters recalculated on every frame, on the CPU, everywhere on the page. A shader does it for free, but a shader needs pixels — so each line of the statement is rasterised once into a texture, at the exact size it will be drawn, and the tunnel draws textures.
The real text is still in the page. Screen readers read it, Google indexes it, and if WebGL2 is not there the same lines fall back to plain DOM nodes with the same geometry, without the water. Nobody gets a blank screen because their graphics driver is old.
A camera on one axis
The tunnel is a straight line. Each plane sits at a fixed depth; the scroll moves the camera forward along z, and the projection is the simplest one there is: scale by one over the distance. Because the camera position is a pure function of scroll progress, scrolling back up undoes the journey exactly — no drift, no accumulated error, no «where am I».
What makes it feel heavy rather than mechanical is that the camera lags the scroll by a small lerp and the scroll itself is smoothed. Your wheel asks for a position; the camera gets there a beat later. That beat is the difference between a page and a place.
Nothing draws when nothing moves
The rule we hold every animated surface on this site to: at rest, zero writes. The tunnel keeps a counter of frames it actually drew, and the test suite scrolls to a plane, moves the cursor away, waits — and asserts the counter did not move. Rings fade, the camera settles, and the GPU goes quiet. Battery is a feature.
We measure it because we would not believe it otherwise. Sixty frames a second on a real GPU with the water running is the number that lets us keep the effect; the day it drops, the effect goes, not the number.
// Experience itScroll the tunnel on vorluno.dev