BeigePill.
A studio site revealed through growing dots, rebuilt in WebGL.
The problem
The design needed full-screen images and video revealed through a growing grid of circles, tied to scroll. The first prototype used CSS clip-path: animating it repaints constantly, overlapping shapes behaved differently between browsers, and it stuttered on mobile.
What I did
I moved the whole composition into a React Three Fiber canvas. Each dot is a circle mesh that writes into the stencil buffer through drei's <Mask>, and the slide's image or video plane only draws where the stencil matches. GSAP ScrollTrigger scrubs a 0 → 1 progress value per slide, and that value sets the dots' radius.
How it works
Details
The mask lives in the stencil buffer
Each dot is a circle mesh inside drei's <Mask>, which writes an id into the stencil buffer instead of drawing colour. The slide's image or video plane uses the matching stencil test, so it only appears inside the dots.
Scroll drives it directly
A scrubbed GSAP ScrollTrigger maps each slide's trigger element to a progress value between 0 and 1, and the dot radius follows it linearly up to a maximum that depends on the screen size. Scrolling back reverses the reveal exactly.
Any image size fits its frame
A small fragment shader fits the texture to the full-screen plane like object-fit: cover. When an image is taller than the screen, a second scroll value pans it vertically.
The dot pattern is hand-authored
The dots come from a hand-written grid of 1s and 0s, and each slide starts reading it at a random column, so partial reveals look designed rather than noisy.
