wgpu · webgpu · wgsl
This is not
a website.
It is a single breath of scroll. Everything below is text, one color, and a shader accent — nothing more. No buttons. No menus. No cards. Nothing to click.
wgpu is a specification, not a renderer.
It defines a contract between a host language and a GPU backend — Vulkan, Metal, D3D12, or a software fallback. WebGPU is its browser implementation. WGSL is the language it speaks. Everything else — three.js, curtains, points, slug — is a layer on top.
Three names, one pipeline. The confusion is historical: wgpu existed in Rust before WebGPU existed in browsers. WGSL was designed after. They were never the same thing.
04 / three names
The same abstraction, described three times.
wgpu
Rust. The reference implementation of the WebGPU specification. Compiles to native, compiles to wasm. Used by Firefox for WebGPU. Not a browser API.
WebGPU
JavaScript. The W3C standard. Shipped in Chrome 113, Safari 17, Firefox 141. Exposes command encoders, pipelines, buffers, and queues to script.
WGSL
The shading language. Text-based, typed, no preprocessor. Written in files that end in .wgsl. Compiles to SPIR-V, MSL, or HLSL at runtime.
06 / the stack
Eleven libraries. One job each.
On the GPU, text is not an image. It is a set of quadratic Bézier curves — one per glyph — evaluated per fragment. No texture atlas. No bitmap resolution. No memory cost that scales with font size.
The Slug algorithm, published by Eric Lengyel in 2017, is the reference. It reconstructs a curve inside the fragment shader from a compact band-based lookup, then evaluates winding order to decide coverage. It is the reason vector text can be rendered at any scale without blur.
08 / frame budget
Within those sixteen milliseconds: Lenis reads the input, GSAP ticks, ScrollTrigger recalculates, the shader uniforms update, the command encoder records, the queue submits, the compositor presents. Miss the window and the frame drops. Drop enough and the illusion of smoothness dies.
09 / synchronization
Two worlds, one frame.
DOM
The source of truth for layout. Where text lives. Where the browser decides line breaks, kerning, and accessibility. Read via getBoundingClientRect once per frame — never per scroll event.
WebGPU
The source of truth for color. Where the shader runs, once per pixel, in parallel. Written via uniform buffer — a small typed array uploaded to the GPU each frame with scroll, time, and viewport.
The seam between them is a single requestAnimationFrame callback. Lenis feeds its RAF into gsap.ticker, ScrollTrigger reads the position, the shader reads the scroll value. One loop, one frame, two truths.
10 / velocity
Scroll faster. The shader responds.
Lenis exposes its scroll delta. We pass it to the shader as an unsigned float. Higher velocity means more displacement in the fragment field — the noise stretches along the direction of motion. Stop scrolling, and the field settles into a slow drift.
A frame is not a moment. It is a breath — sixteen milliseconds in, sixteen out, and the space between them is where everything happens.
— on the nature of the render loop
12 / end
One breath.
The page ends where it began — a black field, one color, a shader drifting behind the text. Nothing to subscribe to. Nothing to click. Just text, and the space it moves through.