VOOZH about

URL: https://dev.to/prodiamadmin/how-we-built-a-diamonds-3-billion-year-journey-in-webgl-threejs-gsap-2014

⇱ How we built a diamond's 3-billion-year journey in WebGL (Three.js + GSAP) - DEV Community


We open-sourced a scroll-driven WebGL piece that traces a single natural diamond from its birth about 150 km down in the mantle, across three billion years, up to a finished ring. As you scroll, the stone is cut in front of you, from a rough octahedral crystal into a round brilliant.

Live: https://www.prodiam.co.za/oldest/
Source (MIT): https://github.com/prodiamadmin/deep-time-diamond

Here is how it is built.

Stack

  • Three.js r184 for the diamond and all 3D
  • GSAP + ScrollTrigger so every animation is driven by scroll position
  • Lenis for inertial smooth-scroll that the timeline reads from
  • HTML5 audio for the voiceover and ambient bed

The diamond is procedural, not a model

There is no .glb. The brilliant is generated from rings of vertices: a table, a table ring, girdle top and bottom, and one culet point at the bottom, stitched into facets. Flat shading means each facet catches light on its own, like a real cut stone:

function makeBrilliant(N) {
 const rg = 1.0, rt = 0.56, ht = 0.36, gd = 0.05, pd = 0.92;
 const v = [0, ht, 0]; // table center
 for (let k = 0; k < N; k++) { // table ring
 const a = k / N * Math.PI * 2;
 v.push(Math.cos(a) * rt, ht, Math.sin(a) * rt);
 }
 // ...girdle top, girdle bottom...
 v.push(0, -(gd + pd), 0); // culet
 // index facets, computeVertexNormals(), flatShading: true
}

The cut is a single morph target

The rough raw crystal is a second set of vertex positions on the same geometry, an irregular octahedron (apex, a jittered wide equator, apex). It starts at full influence, so the very first thing you see is a raw stone:

geo.morphAttributes.position = [new THREE.Float32BufferAttribute(roughPos, 3)];
diamond.morphTargetInfluences = [1]; // 1 = fully rough

During the cutting-bench scene, one GSAP tween drives that influence to 0 and turns the optics on at the same instant. That single tween is the entire rough-to-brilliant reveal:

tl.to(diamond.morphTargetInfluences, { 0: 0, duration: w, ease: 'power2.inOut' }, benchStart)
 .to(material, {
 roughness: 0, transmission: 1, dispersion: 1.25,
 clearcoat: 1, thickness: 2, envMapIntensity: 2.2,
 duration: w, ease: 'power2.inOut'
 }, benchStart);

Fire, without a path tracer

The material is a MeshPhysicalMaterial with ior: 2.42, the real refractive index of diamond, plus transmission and dispersion for the rainbow fire. Reflections come from a PMREM-prefiltered RoomEnvironment, and the canvas is transparent (alpha: true) so the 3D floats over DOM era-art and film. Tone mapping is ACES Filmic. It holds 60fps on a phone and still reads as a diamond.

Scroll is the timeline

One GSAP master timeline owns everything: camera dolly, rotation, era cross-fades, copy, and the cut. ScrollTrigger scrubs it, and Lenis feeds scroll into the GSAP ticker so the scrub stays smooth:

const lenis = new Lenis({ lerp: 0.08, smoothWheel: !reduced });
lenis.on('scroll', ScrollTrigger.update);
gsap.ticker.add((t) => lenis.raf(t * 1000));

Each act gets a weight, not a fixed height. The deep-time montage (older than the pyramids, older than the first flower) gets about three times the scroll room of any other beat so it actually lands:

const WEIGHTS = [1.1, 3.6, 1.4, 1.4, 1.3, 1.7, 1.5];
scrollEl.style.height = WEIGHTS.reduce((a, b) => a + b, 0) * 100 + 'vh';

Performance and accessibility

  • Only the active scene's <video> plays; the rest are paused as you scroll past.
  • devicePixelRatio is capped at 2.
  • prefers-reduced-motion drops the smooth-scroll and the scrub, degrading to plain page scroll.
  • A ?static flag exposes window.__shot(progress) to render any single frame on demand, which made deterministic QA screenshots trivial.

Why

ProDiam is a natural-diamond cutting house in Bedfordview, South Africa (https://www.prodiam.co.za). They buy rough, cut it in-house, and sell the finished stone, so we wanted to show the part nobody usually sees: the three billion years before the ring.

It is MIT-licensed. Fork it, tear out the diamond, and point the same scroll engine at your own story. Feedback welcome, especially on the dispersion look and the scroll performance.