I open-sourced a scroll-driven WebGL piece that scrolls you back three billion years, to the moment a diamond formed, then forward to a finished ring. As you scroll, the stone is cut in front of you, rough crystal to brilliant.
Live: https://www.prodiam.co.za/oldest/
Source (MIT): https://github.com/prodiamadmin/deep-time-diamond
My first post covered the diamond itself. This one is about the part that makes it feel like a film: scroll position IS the timeline.
One timeline, scrubbed by scroll
Everything (camera moves, the diamond rotating, era cross-fades, the copy, the cut) lives on a single GSAP timeline. ScrollTrigger scrubs it, and Lenis smooths the scroll that feeds it:
const lenis = new Lenis({ lerp: 0.08, smoothWheel: !reduced });
lenis.on('scroll', ScrollTrigger.update);
gsap.ticker.add((t) => lenis.raf(t * 1000));
const tl = gsap.timeline({
scrollTrigger: { trigger: scrollEl, start: 'top top', end: 'bottom bottom', scrub: 1.2 }
});
Because it is one scrubbed timeline, the whole story is reversible: scroll up and the diamond un-cuts itself. No scroll listeners firing callbacks, no state machine. Just a timeline you drag with the wheel.
Acts get weight, not pixels
Each act of the story needs a different amount of room. The deep-time montage (older than the pyramids, older than the first flower) has to breathe; the transitions can be quick. So each act gets a weight, and the page height is the sum:
const WEIGHTS = [1.1, 3.6, 1.4, 1.4, 1.3, 1.7, 1.5];
const total = WEIGHTS.reduce((a, b) => a + b, 0);
scrollEl.style.height = total * 100 + 'vh';
The deep-time act gets about three times the scroll distance of any other beat, so it lands instead of flashing by. Tuning the pacing becomes editing one array.
The cut is one tween
The diamond is a single procedural mesh with a rough-crystal morph target. The entire rough-to-brilliant reveal is one tween that drops the morph influence to zero and turns the optics on at the same instant:
tl.to(diamond.morphTargetInfluences, { 0: 0, duration: w, ease: 'power2.inOut' }, cut)
.to(material, {
roughness: 0, transmission: 1, dispersion: 1.25,
clearcoat: 1, thickness: 2, envMapIntensity: 2.2,
duration: w, ease: 'power2.inOut'
}, cut);
Reduced motion
If the visitor prefers reduced motion, I drop the Lenis smoothing and the scrub, so it degrades to a plain, honest page scroll:
const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches;
// new Lenis({ smoothWheel: !reduced }) and scrub: reduced ? false : 1.2
Why
It was built for ProDiam (https://www.prodiam.co.za), a natural-diamond cutting house in South Africa, to show the three billion years before the ring. The code is MIT, so the same scroll engine works for any deep-time or how-it-is-made story. Fork it and point it at your own story. Feedback welcome, especially on the scroll performance.
Top comments (0)