Five by Erik — night photography design study

2026

A one-page site for a fictional night-photography studio, with a 3D photo wall in three.js, custom shaders and GSAP animation. All images are AI-generated.

On load, the photos fly spinning through space and settle into a masonry grid in about a second and a half, after which the word Five rises into view. Five is a design study with an invented brand: a night-photography studio that does not exist. The 24 photos are AI-generated (gpt-image-2), and the titles and captions are fiction too. The subject is the page itself: motion, depth and what a photo does when you point at it.

The grid tilts, without a cut, into a 3D wall built with three.js and custom shaders. The switch from HTML to WebGL is invisible because the wall's first frame copies the grid exactly: each photo is a plane in the same place and at the same size, and at rest the shader returns the texture unchanged. Only then does the wall bend into a concave cylinder, with its edges coming towards you and every photo turning to face the cylinder's axis. Dragging turns the camera around the wall, with inertia. Point at a photo and it bulges forward in the vertex shader, its red and blue channels shift apart a fraction, its hue shifts and its edge picks up a cyan glow.

Pick another series (Neon, Long Exposure or Quiet Nights, or all 24 together) and the wall bursts into a star cloud of its own pixels. Each photo has a grid of 28 × 28 points for this, which take their colour from the photo and fly off in a random direction, slightly towards you. Then the new series rebuilds, with a wave running through the planes. On stronger hardware a bloom pass adds a glow. It starts at zero, so even with bloom the first frame matches the grid.

A click opens a lightbox that grows from the spot where the photo sat on screen, even when it hung in the 3D wall. A small function projects the plane's four corners through the camera to a rectangle on screen, and GSAP animates from that rectangle to the large image. Below it, a scroll story with photos in parallax layers and words that light up (Lenis and GSAP ScrollTrigger).

three.js sits in a separate chunk of JavaScript that is only fetched when the intro starts. The wall uses textures 960 px wide; the 1600 px version only loads in the lightbox. On touchscreens, screens narrower than 768 px and processors with four cores or fewer, the pixel ratio is capped at 1.5 and there is no bloom. The render loop pauses off-screen, in a hidden tab and while the lightbox is open. With reduced motion or without WebGL2 you get a plain grid, and the lightbox and series still work. The canvas is hidden from screen readers; an invisible list of buttons, one per photo, opens the lightbox from the keyboard. Built with SvelteKit and Svelte 5 in TypeScript. Lighthouse mobile: 94 performance, 100 accessibility.

Technologies

SvelteKit three.js WebGL GSAP Lenis TypeScript

More of my work

Browse the full portfolio or read the blog.

More work