Build notes · site 03 of 25
How this room
was lit
Atelier Lumen is a fictional installation studio, but the page behaves like one of its rooms. The portfolio is mostly darkness. The visitor supplies the lamp. Content is not hidden as a gimmick; it is metered, rationed and warmed by proximity, so reading becomes a physical act.
The Technique
The torch lives in main.js. A single animation loop eases the current point toward the pointer with torch.x += (torch.tx - torch.x) * k, then writes --tx and --ty to the root. Those variables feed .torch-veil, a fixed radial-gradient darkness layer with a transparent hole, and .torch-glow, two amber gradients in mix-blend-mode: screen. The .strike layer gives the first load a brief ignition flash before the room settles.
Reveals
Elements marked data-track receive local --mx/--my coordinates from frame(). The hero is rendered twice: a dim readable base, then an aria-hidden lit layer clipped by mask-image. The whisper lines and guide aperture use the same coordinates. Headings with .warm get --w, a distance score mixed in CSS from cold white to candle amber.
Atmosphere
The #motes canvas draws capped particles that brighten only near the torch. Cards are glass: blurred charcoal, a radial edge glint at --gx/--gy, and a masked one-pixel border. Touch devices and idle desktops call wanderTarget(), a slow Lissajous path, so the site never becomes a blank dark wall. document.hidden stops the loop; prefers-reduced-motion removes continuous animation and updates only on pointer movement.
Generated Media
Pass 3 added one first-class image workflow. /assets/gen/lumen/installation.jpg was generated with GPT Image 2 through Higgsfield, then animated into the five-second /assets/gen/lumen/haze.mp4 loop with Kling 3.0. In index.html, .hero-installation mounts the still as an eager <img> and the loop as a muted .ambient-video with the still as its poster. CSS scrims and the same torch coordinates grade it back into the charcoal/amber palette. updateAmbientVideos() pauses the loop when offscreen, hidden, or reduced-motion is requested. The remaining visuals — diagrams, score, motes, grain, glints and masks — stay code-generated.
Reproduce This
Prompt an AI agent: “Build a dark portfolio where the cursor is a torch. Use self-hosted Italiana and Manrope. Store a lerped pointer in root CSS variables. Add a local generated installation still and haze loop as a torch-reactive hero aperture. Create a fixed radial darkness veil, screen-blended amber glow, canvas dust, masked duplicate headline text, glass cards with pointer-following glints, a touch auto-wander path, reduced-motion fallbacks, and a guide naming the actual functions and CSS classes.” Ask for measured fictional content: lux values, colour temperatures, site names, commissioning windows.