Article / Scroll Animation

Scroll-Driven 3D: Directing a Camera the Visitor Holds

Scroll is the only rich interaction every visitor already knows. How scroll-driven 3D storytelling works, the GSAP, Lenis, and Theatre.js toolkit behind it, and the craft rules that separate cinematic from carsick.

Every fancy interaction pattern comes with a hidden tax: the visitor has to learn it. Drag to rotate, hold to explore, press keys to move. Each one filters out the people who did not read the instructions. Scroll is the exception. Every person who has ever used the internet arrives already fluent, and that is why the best 3D storytelling on the web is scroll-driven: it is cinema where the audience holds the camera dolly.

Why scroll works on the brain

Scroll gives the visitor control over time. A video plays at its own pace and asks for patience. A scroll-driven sequence moves exactly as fast as curiosity does, backward as easily as forward, and that control changes how people engage. They lean in instead of waiting. The story becomes something they are doing rather than something happening at them.

It also lets you borrow a century of film grammar. Dolly in for intimacy, pull wide for scale, cut on motion, hold on stillness. I used exactly this in Void Atlas, where camera choreography walks the viewer through deep-space distances that raw numbers cannot communicate. The scroll bar became the timeline of a documentary. How motion timing carries meaning is its own subject, and I wrote about it in The Semiotics of Digital Space.

The architecture underneath

Strip away the tools and every scroll-driven scene is the same machine: scroll position becomes a normalized progress value between zero and one, and that value drives everything. Camera position along a path, material opacity, text reveals, particle states. The scene is a function of progress. Nothing animates on its own clock, everything reads from the same timeline.

// the whole genre in six lines
const progress = clamp(scrollY / (docHeight - viewportHeight), 0, 1);

camera.position.copy(cameraPath.getPointAt(progress));
camera.lookAt(target.getPointAt(progress));
material.opacity = smoothstep(0.3, 0.45, progress);
titleReveal.set(smoothstep(0.5, 0.6, progress));

Everything else is elaboration on those six lines. Sections map to progress ranges, easing curves shape how fast meaning arrives inside each range, and the smoothing layer decides how the raw scroll value becomes the calm interpolated one the scene actually reads.

The important decision is keeping that machine honest: read the scroll once per frame, drive the scene inside the render loop, and never let animation work trigger browser layout. Transforms and shader uniforms are cheap. Anything that makes the browser recalculate the page mid-scroll turns a sixty-frames-per-second story into a slideshow, especially on the phones I wrote about in the performance post.

The toolkit

  • GSAP ScrollTrigger is the industry standard for a reason. The scrub option maps timelines to scroll position with one line, pinning and snapping included. If you use one tool from this list, use this one.
  • Lenis replaces native scrolling with a smoothed, interpolated version, which is what makes 3D scenes feel attached to the page instead of jittering behind it. Most award-level scroll sites you have admired are running it.
  • Theatre.js gives you a real animation editor in the browser: keyframe the camera, scrub the sequence, hand the timeline to scroll. For long cinematic sequences it beats hand-typed keyframes by a full order of magnitude.
  • For flat sections between 3D moments, plain CSS scroll-driven animations now cover more than most people think, at zero JavaScript cost.

The craft rules

Tools make scroll-driven work possible. Restraint makes it good. The failure mode of this genre is the site that fights its visitor: hijacked scroll speed, sections that trap the wheel, motion that keeps going long after the finger stopped. The visitor holds the camera. The moment the site wrestles them for it, trust is gone and so are they.

  • Respect momentum. Smooth the scroll, never redirect it. If the visitor flicks, the page goes where they sent it.
  • Give length cues. People tolerate long sequences when they can feel their position in them. A quiet progress indication beats a surprise every time.
  • Keep text still while it is being read. Motion behind text is cinematic. Motion of text is hostile.
  • Honor prefers-reduced-motion with a real alternative, not an empty page. Some visitors need the story without the ride.
  • Test on touch. Mobile scroll has its own physics, plus the address bar resize that has broken more scroll scenes than any browser bug.

Structure the story before the scene

The most common mistake in this genre is not technical. It is writing the choreography before the story. Decide first what the visitor should understand at each stage of the page, in plain sentences. Then assign each sentence a progress range, and only then decide what the camera does to serve it. Scenes built the other way around, motion first and meaning retrofitted, always read as demos, and visitors can smell a demo in the first two hundred pixels of scrolling.

Where to start

Start smaller than you think. One scene, one camera move, one idea revealed on the way down. A single dolly-in that lands exactly when the headline arrives will outperform six minutes of choreography that exhausts its audience by the second act. Film editors learned this a hundred years ago: the cut you notice is the cut that failed.

Then build the machine properly: progress value, one timeline, scene as a function of scroll. Add Lenis when the native scroll feels detached, ScrollTrigger when the choreography grows, Theatre.js when hand-tuned keyframes stop scaling. And keep the visitor in charge of the camera the whole way through. You are not animating a page. You are directing a shot that someone else gets to hold, and that someone decides how your story ends.