Colophon
How this was made
Vitrea is a showcase built to one rule: the page is a single piece of glass. Here is how the refraction, the stack, and the accessible fallbacks fit together.
The concept
Vitrea makes optical instruments, so the site does not talk about glass. It is glass. The visitor looks through a real 3D lens that refracts the wordmark behind it and splits the spectrum at the rim. Every other section re-uses that one idea exactly once: the vision line read through a tilting slab, the instrument names that break into colour on hover, the dispersion fan on the bench, and a CTA button that refracts like a lens.
One signature, repeated everywhere, is the single trait that separates award-level work from a competent page. So there is exactly one flex, and colour is spent only inside the glass.
The glass shader
The hero runs a small three.js scene, bundled locally so no code is loaded from a CDN. A background plane carries a 2D canvas texture (the VITREA wordmark, an optical-bench line, a faint spectral band). In front of it sits a plano-convex lens: a sphere flattened on its depth axis, given a MeshPhysicalMaterial with transmission, an index of refraction of 1.52, and dispersion. Transmission refracts whatever is behind the lens; dispersion splits the refracted light into red, green and blue at the edges.
A single value, progress, is driven from the scroll position and eased in JavaScript. It maps to a slow rotation and a growing thickness, so the distortion evolves as you read. The material itself stays declarative; the JavaScript owns the curve.
const lens = new THREE.MeshPhysicalMaterial({
transmission: 1, // refracts the plane behind it
thickness: 1.5,
ior: 1.52,
roughness: 0.02,
dispersion: 5.2, // splits the spectrum at the rim
});
// one driving value of intent, eased in JS:
lens.rotation.y = progress * 0.9;
lens.thickness = 1.5 + progress * 1.4;The stack
Astro builds the page to static HTML with all styles inlined and hashed into a strict Content-Security-Policy: no inline event handlers, no inline style attributes, no external hosts. three.js is a local bundle, so the policy stays at self. Tailwind 4 carries layout; the design tokens (paper, prussian ink, one accent, the spectral channels) live in one file. Type is Space Grotesk for display and Space Mono for every measurement, both self-hosted.
Accessibility
The WebGL is only a rendition. The real headline is ordinary DOM text, so screen readers and search engines read the page whether or not the shader runs. There is one h1, a logical heading order, a working skip link, and AA-or-better contrast on every line of running text. Focus states are visible.
Reduced motion is a designed second experience, not a switch that removes content: the glass renders one sharp, centred frame with the headline fully legible, the loader shows no blur, and the count-up numbers jump straight to their final value.
Performance
Before anything renders, the site measures the device: CPU cores, memory, pointer type and viewport. A strong desktop gets the full live transmission loop with the pixel ratio capped, paused whenever the hero scrolls out of view. A phone or weak GPU gets a single crisp static frame with a lighter material and no live loop. If WebGL cannot start at all, a 2D canvas still stands in. During the loader the shaders are compiled off-screen once, so the first interaction never stutters.