three-scroll-sync-camera
Installation
SKILL.md
Three.js Scroll-Synced Camera
What this builds
A precision binding layer between page scroll position and a Three.js camera's transform (position, quaternion, lookAt target) that eliminates the three failure modes every naive implementation hits: accumulated floating-point drift over long scroll distances, visible judder when the camera lerps behind the scroll position, and desync between the DOM overlay positions and the 3D scene after a resize or ScrollTrigger refresh. The system reads scroll progress as a single 0-to-1 value and maps it to camera state through a pre-computed path, with no per-frame accumulation.
- Scroll progress drives camera position along a CatmullRomCurve3 or array of keyframes.
- Camera look-at target follows a separate path or uses directional derivatives for auto-aiming.
- Zero drift: camera state is always computed from absolute progress, never accumulated from deltas.
- Smooth scroll integration (Lenis) with a unified scroll-value source that works identically with or without smooth scroll.
- Sub-frame interpolation: the system samples camera state at the exact scroll position, not the last-known RAF position.
- Resize-safe: paths are resampled and ScrollTrigger positions recalculated on container resize.
When to use / when not to
- Use this whenever a Three.js camera must move in direct response to the user scrolling the page (scroll-driven product tours, architectural walkthroughs, landing page fly-throughs).
- Use this as the camera layer inside
scroll-3d-camera-path-journey, which handles the full journey experience (waypoints, overlays, act transitions) on top of this binding. That toolkit is the "what to show"; this toolkit is "how to move the camera without drift." - Do NOT use this for orbit controls, fly controls, or any camera driven by pointer/gamepad input. Those are user-interactive, not scroll-driven.
- Do NOT use this for a camera that animates on a timeline independent of scroll (e.g., an intro animation that plays once on load). Use
gsap-core-timelinesfor that. - Do NOT use this for 2D parallax scroll effects. See
parallax-depth-systemsfor CSS/transform-based parallax.