How to Build a Scroll-Driven 3D Scene with Three.js and WebGL
By Digital Strategy Force
A scroll-driven 3D scene connects the browser scroll position to a camera moving along a predefined spline path through a Three.js environment, transforming vertical page scrolling into a cinematic journey through 3D space.
Step 1: Set Up the Three.js Scene and Renderer
Every scroll-driven 3D experience begins with three foundational objects: a Scene, a Camera, and a WebGLRenderer. The scene is the container for all 3D objects. The camera defines the viewport through which users see the scene. The renderer converts the scene graph into pixels on a canvas element that sits behind your DOM content.
Set the renderer size to match the window, append the canvas with position fixed and z-index negative one. Add a resize listener for responsive behavior. Use PerspectiveCamera with FOV 65, near 0.1, far 20000. Create the animation loop with requestAnimationFrame calling renderer.render each frame.
Step 2: Define the Camera Spline Path
The camera spline is a THREE.CatmullRomCurve3 constructed from Vector3 control points. These points define the physical path through 3D space. Start simple with five points along the negative Z axis, spaced 2000 units apart. The tension parameter controls curve sharpness: 0.5 for gentle curves, 0.3 for tight turns that pass closer to control points.
Use getPointAt to sample the current position and a look-ahead position at t plus 0.001. Point the camera at the ahead position with lookAt. This creates natural forward-facing orientation as the camera travels along the curve.
Camera Spline Parameters
Step 3: Map Scroll Position to Camera Movement
Listen to window scroll events and compute normalized scroll percentage: scrollTop divided by total scrollable height. Map this to the spline parameter t. Use smoothed interpolation with a lerp damping factor of 0.05 to 0.1 rather than applying raw scroll directly. This creates buttery smooth camera movement that absorbs CSS scroll event jitter.
In your animation loop, call cameraSpline.getPointAt with the smoothed t value. The difference between raw and smoothed scroll is the difference between amateur and professional feel. Every production implementation at Digital Strategy Force uses scroll smoothing.
Step 4: Add Environmental Objects and Lighting
Add a starfield with 10000 randomized BufferGeometry points using PointsMaterial. Add ambient light at intensity 0.3 and directional light at 0.8 pointing along the camera forward direction. These create base visibility. For specific zones, add point lights and spot lights that activate based on camera position.
Every object must justify its GPU cost. If removing it would not diminish the experience, it should not be there. Lighting should serve the narrative: brighter zones feel active, darker zones feel mysterious.
"Every object in a scroll-driven scene must justify its existence. If removing it would not diminish the experience, it should not be there."
— Digital Strategy Force, WebGL Engineering DivisionStep 5: Implement Zone-Based Asset Management
Divide the spline into zones with intensity functions mapping camera t to visibility between 0 and 1. When intensity is 0, the zone group becomes invisible and its update returns early. This is the most important architectural pattern for maintaining 60fps in complex scenes with many objects.
Create three functions per zone: computeIntensity, init, and update. Use smoothstep transitions at zone boundaries for fade-in and fade-out. Deferred initialization spreads GPU upload cost across the scroll timeline rather than front-loading everything at startup.
Implementation Complexity by Feature
Step 6: Add Post-Processing Effects
Create an EffectComposer with RenderPass, UnrealBloomPass, and OutputPass. Bloom is the highest-impact post-processing effect. Configure with strength 1.0, radius 0.5, threshold 0.7. Adjust per zone for different atmospheres. On mobile, disable bloom or use half-resolution rendering.
Post-processing transforms competent 3D into cinematic experience. But every pass costs frame time. Budget carefully: bloom at half resolution costs 25 percent of full resolution with minimal visual loss on small screens.
Step 7: Optimize for Cross-Device Performance
Build a performance tier system: desktop full quality, mobile reduced geometry, degraded static fallback. Detect tier during initialization via WebGL extensions, GPU renderer string, and benchmark render. Profile with Chrome DevTools Performance tab. Watch for frames over 16.6ms.
The difference between a portfolio piece and production website is sustained performance under real conditions. Digital Strategy Force engineers every immersive build to hit 60fps on target devices.
