How it was made
I designed the site from my own mockups and rebuilt it in two days by directing Claude Code, which wrote the fragment shader, the glass renderer, the carousel physics and the card-open sequence. My part was the brief, the taste calls and the checks: twenty-four screenshots per change at two widths, an offline harness to tune the shader without a rebuild, and a spec updated the day a decision is made, including what was rejected. Since October the site has been kept by a small team of AI agents run through V: an AI art department audited the look, an AI writer rewrote the copy, an AI engineer built the motion films on these pages with Remotion. Each change waits for my sign-off before it ships.
The light
One fragment shader, about 8 KB, draws an infinite glossy floor, exponential height fog, one volumetric shaft of light and a Fresnel-weighted floor reflection that marches a second, roughened ray. ACES tone mapping, vignette and grain applied after gamma. It runs on a fixed pixel budget of 0.42 megapixels on desktop and 0.24 on phones regardless of display density, capped at 30 fps, and pauses when the tab is hidden. Step counts are solved so the march reaches the same distance with fewer steps on phones. Each page gets its own light placement.
The glass
Each card is a signed-distance rounded rectangle with a superellipse bevel and a gentle dome for its height field. Light refracts through it in five spectral taps, leaving a faint spectral edge; reflection comes from a synthetic gray studio environment weighted by Schlick Fresnel. It is rendered once per card into a static canvas from one shared offscreen context, so at runtime a card costs the same as an image. Three dead ends taught the material: a crease on the diagonals when the bevel exceeded the corner radius, blur that killed the rim wall, and grain added before gamma.
The motion
The carousel is CSS 3D with a spring-mass model, stiffness 110 and damping 15, deliberately under-damped so a throw overshoots and settles with weight. Drag sets position and estimates velocity; release throws and snaps; the ends rubber-band. Opening a card is a 1.7-second sequence of web animations: anticipation, a flight to the center, a swap to a frosted pane, the pane extending to the viewport with light runners on its edges, a fog, then a feathered circular reveal once the next page is in the DOM. Only opacity and transform ever animate.
The method
Every visual change goes through a build and a screenshot pass at 1440 and 390 pixels wide, twenty-four images looked at one by one before anything is called done. Shader tuning happens in an offline harness that renders the GLSL with given uniforms in seconds, so the site is never rebuilt to try a value. The spec is the single source of truth and is updated the day a decision is made, with a log of what was rejected: warm gold, indigo fantasy, corridor galleries, sci-fi HUDs.
Why it is here
A portfolio is expected to be a portfolio. This one is meant to be read as a work sample: taste and restraint in the design, graphics engineering underneath it, a performance budget kept, and a process that lets one person ship the thing by directing AI. Static export, two font families, no UI framework, deployed on Cloudflare Pages.