Lab

A camera lens, written by hand.

No 3D model, no Three.js. The barrel, the knurling, the nine iris blades and the coated glass are all maths in a single fragment shader, drawn fresh every frame.

Scroll the page and the iris opens, holds wide, then stops down again.

Move your mouse over it · scroll to drive the aperture

Library
None
Weight
~6 KB gzipped
Technique
SDF raymarch
API
WebGL2

How it works

Every pixel fires a ray into the scene and steps along it until it hits a surface. The surfaces are signed distance functions: a hollow cylinder for the barrel, a nine-sided polygon cut out of a thin plate for the iris, two intersected spheres for the rear element. Knurling is a sine wave subtracted from the barrel's distance.

Each iris blade is its own slightly tilted facet with a groove at the seam. Without that, the iris reads as one flat disc and catches the light like a lens cap.

Keeping it fast

Rays are tested against a bounding sphere before marching, so the large empty part of the screen costs almost nothing. Resolution is capped, the frame rate is held at 36, and the loop stops completely in a hidden tab. On a GTX 1060 a frame takes about 3 ms at 3.2 megapixels.

When it can't run

If the browser would render WebGL on the CPU — hardware acceleration switched off — it doesn't try. You get the same lens as a pre-rendered image, gently drifting, made from this exact shader. Reduced-motion settings are respected; the chip in the corner switches motion on or off at any time.

Back to the work

WhatsApp