Two months into a Three.js prototype, the transition we wanted still wasn’t there. We could see it in our heads and not on the screen.
That was the moment we started over from scratch.
Labs uses real-time shaders, physics-style interactions and transitions that happen at the GPU level. That behavior took roughly 6,000 lines of hand-written WebGL 2 and four months of iteration. We needed direct control over every draw call and every animation frame. Existing libraries would have saved time upfront and cost us flexibility every week after.
Straight to the GPU
There’s no Three.js, no Pixi, no framework sitting between our code and the GPU. A single setup module compiles vertex and fragment shaders, builds a shared quad and manages four shader programmes. Every draw call goes through it.
Shaders manipulating geometry in real time
Feeding it real data
From there, modules handle different responsibilities: the canvas and render loop, the orbs with its GLSL transforms (bulge, twist, rotate, scale) layered through custom blend modes, full-screen post-processing for bloom and grain, a raycaster for hover detection, texture management, input handling, performance monitoring. Shared helpers cover noise functions, color math and UV manipulation.
The data layer pulls project boards and assets from the Air API, then caches them through Netlify Blobs with a distributed lock mechanism. The lock prevents stampedes when the cache expires: only one request refreshes the data while others serve the stale version.
We rebuilt that integration in October 2025 after the original approach (fetching on every request) started hitting rate limits. The lock-and-cache layer landed in February 2026 alongside SpeedyClip for asset delivery.
The UI around the canvas
A set of Astro components handles everything outside the WebGL viewport: search, filters, tabs, scroll controls, hover labels. They talk to the canvas through a bridge layer that translates DOM events into render-loop updates. The result is that filtering a project list triggers a shader transition, not a page reload.
Timeline
October 2025: Air API integration rewrite.
January 2026: Soft launch of Labs.
February 2026: Netlify Blobs caching with distributed locks and SpeedyClip rollout.
The UI and the canvas talk through a bridge layer for filtering.
What 6,000 lines bought us
Labs is often the first thing a potential client sees when they explore our work. The way it moves and responds tells them something about how we think before they’ve read a word.
Writing your own renderer is a terrible idea for most projects. The visual behavior we wanted doesn’t fit anyone else’s scene graph. The cost is 6,000 lines we maintain forever — and the page makes that worth it.