Three.js Scroll Orbit Showcase — GSAP Camera Orbit on Scroll

Three.js Scroll Orbit Showcase · Scroll · Plain HTML, CSS & JS · Live preview

What's included

Features

Camera orbits a fixed object via spherical coordinates, so lighting stays put and every side is revealed
One scrubbed tween advances azimuth a full 2π while dipping polar angle and pulling radius in together
Spiral-in reveal rather than a flat turntable — the orbit descends and tightens as it circles
Standard spherical-to-Cartesian conversion each frame with lookAt keeping the subject centered
Ground ring and fixed key/rim lighting anchor the motion so the camera clearly moves, not the object
Idle spin on the hero keeps the frame alive when scrolling pauses mid-orbit
Live 0–360° angle read-out from ScrollTrigger onUpdate self.progress
Pinned, smoothed scrub (0.6), and fully reversible — the orbit unwinds exactly on scroll-up

About this UI Snippet

How to Build a Scroll-Driven 360° Camera Orbit With Three.js and GSAP

Screenshot of the Three.js Scroll Orbit Showcase snippet rendered live

The Three.js Scroll Orbit Showcase snippet holds a hero object still at the center of the scene and swings the camera a full 360° around it as the visitor scrolls, so every face is examined in turn — the scrollbar drives the camera's orbital angle directly, not a timer — using core Three.js and GSAP's ScrollTrigger plugin, both loaded from a CDN.

Spherical coordinates, not a rotating object

The naive way to "show all sides" is to spin the object, but that makes lighting rotate with it and never reveals a true back view. This snippet does the opposite: the object stays fixed while the camera orbits, so highlights stay put and the visitor genuinely walks around the subject. The camera's position is expressed in three spherical values — az (azimuth, the angle around), polar (how high or low it sits), and radius (distance) — which are far more natural to animate than raw X/Y/Z.

One scrubbed tween moves all three angles at once

Scroll advances azimuth a full 2π for one complete revolution, while at the same time the polar angle dips from a high three-quarter view down toward eye level and the radius pulls in from 6.5 to 4.6. Tweening all three together means the orbit isn't a flat turntable — it spirals downward and inward as it circles, a far more cinematic reveal than a level 360° spin. Every frame converts the spherical values to a Cartesian position and calls lookAt(0,0,0) so the camera always faces the subject.

The conversion is the whole trick

The line that turns (az, polar, radius) into a camera position is standard spherical-to-Cartesian math: sin(polar) scales the horizontal circle while cos(polar) sets the height. Understanding this one conversion is what lets you drive a camera around anything — swap the torus knot for a product model and the exact same orbit rig applies unchanged.

A ground ring anchors the motion

A thin ring on the ground plane and the fixed key/rim lighting give the orbit a clear sense of place. Without a ground reference, a camera circling a symmetrical object can look like the object is spinning instead; the static ring makes it unmistakable that the *camera* is the thing moving.

Idle spin so it never freezes

A very slow constant Y rotation is layered onto the hero object so it still breathes when the visitor stops scrolling mid-orbit. The scroll-driven camera provides the structured 360° reveal; the idle spin keeps the frame alive between scroll movements — the same division of labor as the scroll camera path flythrough.

scrub: 0.6, a live angle read-out, fully reversible

A numeric scrub smooths the orbit against noisy wheel and trackpad input, and ScrollTrigger's onUpdate maps self.progress to a 0–360° read-out. Because the camera position is derived entirely from the three scrubbed values, scrolling back up unwinds the orbit precisely. Pair this examine-in-the-round showcase with a product stages tour or a horizontal gallery of variants.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not need to remember the spherical-to-Cartesian formula to orbit a camera. Paste this snippet's HTML, CSS, and JS into an AI assistant like Claude and ask it to explain why the camera orbits while the object stays fixed, and how the three spherical values convert into a camera position each frame. The same assistant can help you extend it — ask it to load a real GLTF model in place of the torus knot, add two full revolutions instead of one for a longer reveal, or fade in a caption at specific azimuth angles to annotate features as the camera passes them. It can also add gentle damping so the orbit eases at the start and end rather than running perfectly linearly. Treat the code as a starting point for a conversation, not a finished artifact.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "scroll-driven 360-degree camera orbit" in plain HTML, CSS, and JavaScript using Three.js, GSAP, and GSAP's ScrollTrigger plugin, all loaded from a CDN (no bundler, no build step).

Requirements:
- A pinned section containing a full-size canvas with a WebGLRenderer, PerspectiveCamera, and ambient + key + rim lighting, sized and updated on window resize including aspect ratio.
- Place one hero object (e.g. a torus knot) at the origin, and a thin ground ring below it for spatial reference. Keep the object essentially fixed.
- Keep the camera position in three spherical values: azimuth, polar angle, and radius.
- Register a GSAP tween on a ScrollTrigger targeting the pinned section, with pin: true, start at top top, a numeric scrub (~0.6), and an end several hundred percent tall, animating azimuth from 0 to 2*PI (one full turn) while also dipping the polar angle toward eye level and shrinking the radius, so the orbit spirals down and in. Use onUpdate to show a 0-360 degree read-out from self.progress.
- Every animation frame (requestAnimationFrame), convert the spherical values to a Cartesian camera position (sin(polar) scales the horizontal circle, cos(polar) sets the height) and call camera.lookAt(0,0,0). Add a slow idle spin to the object so it lives when scrolling pauses.
- Confirm scrolling back up unwinds the orbit exactly, since the camera derives entirely from the scrubbed spherical values rather than a timer.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<section class="orb-top"><p>Scroll ↓ to orbit the object</p></section>
<section class="orb-stage" id="orbStage">
  <canvas id="orbCanvas"></canvas>
  <div class="orb-angle"><span id="orbDeg">0</span>°</div>
</section>
<section class="orb-bottom"><p>A full turn, examined.</p></section>

Step by step

How to Use

  1. 1
    Load all three CDN scriptsAdd three.min.js, gsap.min.js, and ScrollTrigger.min.js from the CDN panel, in that order.
  2. 2
    Paste HTML, CSS, and JSA metallic torus-knot hero appears on a ground ring in a pinned 3D stage with an angle read-out.
  3. 3
    Scroll downThe camera orbits a full 360° around the object while spiraling downward and inward, tied to scroll.
  4. 4
    Scroll back upThe orbit unwinds exactly, since the camera derives entirely from scrubbed spherical values.
  5. 5
    Swap in your objectReplace the torus-knot geometry with your own model; the orbit rig applies unchanged.
  6. 6
    Reshape the orbitEdit the polar and radius targets for a level turntable, a steep top-down sweep, or a tighter close-up.

Real-world uses

Common Use Cases

SHOP
Product 360° views
Let shoppers examine a product from every angle by scrolling instead of dragging a turntable widget.
Sculpture and 3D art
Present a 3D model as a guided orbit that reveals its form as the visitor scrolls down the page.
Teaching spherical camera rigs
A minimal example of animating azimuth, polar, and radius and converting them to a camera position.
Hardware showcases
Reveal every face of a device, then transition into a product stages exploded view.
Hero centerpieces
Anchor a landing page around one striking object the visitor orbits as they read the copy.
Character and asset reveals
Show a game character or collectible in the round as a scroll-controlled camera sweep.

Got questions?

Frequently Asked Questions

Spinning the object rotates its lighting with it and never shows a true back view because the light follows the surface. Orbiting the camera around a fixed object keeps highlights anchored and lets the visitor genuinely walk around the subject, seeing every face lit consistently — the correct way to present an object in the round.

Azimuth (az) is the angle around the object, polar controls how high or low the camera sits, and radius is the distance from the center. These map to how humans think about "walk around, look down, step closer," which makes them far easier to animate than raw X/Y/Z camera coordinates.

Scroll advances azimuth a full 2π for one revolution while simultaneously dipping the polar angle from a high view toward eye level and shrinking the radius. Because all three tween together, the orbit descends and tightens as it circles rather than staying a flat turntable, producing a more cinematic reveal.

A camera circling a symmetrical object can read as the object spinning instead. The static ring on the ground plane, plus fixed key and rim lights, give a clear frame of reference so it is unmistakable that the camera is the thing moving around a stationary subject.

Yes. Click JSX for a React component, Vue for a Vue 3 SFC, Angular for a standalone component, or Tailwind for a React + Tailwind version. Build the object and GSAP timeline inside a mount effect against a canvas ref, keep the spherical values in a ref you read each frame, and on cleanup kill the ScrollTrigger and call renderer.dispose() so the pin and WebGL context are released on unmount.