webdevpuneet.com

Three.js Scroll Planet Approach — GSAP Orbit Arrival

Three.js Scroll Planet Approach · Scroll · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<section class="pla-stage" id="plaStage">
  <div class="pla-intro"><p>Scroll ↓ to approach the planet</p></div>
  <canvas id="plaCanvas"></canvas>
  <div class="pla-hud">DISTANCE <span id="plaDist">98,000</span> KM</div>
</section>
<section class="pla-bottom"><p>Orbit established.</p></section>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Procedural vertex-colored planet — continents, oceans, and polar ice from trig noise, zero texture downloads
Budget fresnel atmosphere: oversized BackSide sphere whose opacity scales with scroll progress
Additive-blended cloud shell rotating faster than the surface for continuous secondary motion
Braking-burn distance easing via 1 − (1 − p)^2.2 so arrival flattens instead of stopping abruptly
Corkscrew approach vector swings 2.1 radians around the planet so the terminator sweeps into view
Inclined moon orbit advanced by both clock time and scroll progress for constant parallax
Live distance HUD in kilometers derived from the same scrubbed camera distance
Fully reversible — every visual state is a pure function of one ScrollTrigger-scrubbed value

About this UI Snippet

How to Build a Scroll-Driven Planet Approach With Three.js and GSAP

Screenshot of the Three.js Scroll Planet Approach snippet rendered live

The Three.js Scroll Planet Approach snippet flies the camera from deep space into a close orbit around a procedurally colored planet, with GSAP's ScrollTrigger scrubbing a single 0–1 progress value that every other quantity — camera distance, swing angle, atmosphere glow, and a live distance HUD — is derived from each frame. It is the "arrival" counterpart to the starfield warp: instead of racing past stars forever, the scroll ends in a stable orbit around a destination.

A textureless planet painted per-vertex

The planet needs continents, oceans, and polar ice, but downloading an equirectangular texture would make the snippet depend on an external image. Instead, the sphere's vertices are colored directly: each vertex normal is fed into a cheap trigonometric noise expression (sin/cos products at different frequencies), and the result thresholds into land green or ocean blue, with anything above 0.86 on the Y axis painted ice white. Because MeshLambertMaterial supports vertexColors, the GPU interpolates smoothly between vertices and the 96-segment sphere reads as soft-edged continents with zero network requests.

Atmosphere and clouds without shaders

The atmosphere rim is the classic budget fresnel trick: a second sphere 7% larger than the planet rendered with side: THREE.BackSide, so only its far hemisphere's inside faces draw, producing a halo that hugs the limb. Its opacity is tied to scroll progress — barely visible from deep space, glowing at 0.38 opacity once you arrive — which sells the sensation of entering the atmosphere's optical thickness. Clouds are a third shell using the same vertex-color trick but with AdditiveBlending and depthWrite: false, rotating slightly faster than the surface so the planet feels alive even when the user stops scrolling.

Distance easing shaped for a braking burn

Mapping scroll linearly to distance would make the final moments feel abrupt — most of the planet's apparent growth happens in the last few units of approach. The snippet instead applies 1 - Math.pow(1 - p, 2.2) to the scrubbed progress, so distance closes quickly while the planet is small and flattens out near arrival, mimicking a deceleration burn. This is the same derive-from-one-value philosophy used in the portal gate sequence: ScrollTrigger scrubs one number, and the frame loop shapes it.

A swinging approach vector, not a straight line

Flying straight at a sphere is visually static — the silhouette just grows. The camera's position is computed on a circle whose angle advances 2.1 radians across the scroll, so the approach corkscrews a third of the way around the planet and the day/night terminator sweeps across the visible face during descent. Combined with an inclined moon whose orbital angle also advances with progress, there is always parallax between foreground and background to communicate motion.

Scroll-scrubbed but never frozen

Only the approach itself is scroll-driven. Planet rotation, cloud drift, the moon's base orbit, and a subtle sinusoidal camera bob all run off THREE.Clock elapsed time, so the scene keeps breathing when scrolling stops — the same split between scrubbed primary motion and clock-driven secondary motion used in the scroll camera path snippet. Scrolling back up reverses the entire arrival exactly, because nothing is fired one-shot; every visual state is a pure function of the current progress value and the clock.

Step by step

How to Use

  1. 1
    Load the three CDN scriptsAdd three.min.js, gsap.min.js, and ScrollTrigger.min.js in that order before the snippet JS.
  2. 2
    Paste HTML, CSS, and JSA pinned deep-space view appears with the planet as a small disc, a drifting moon, and a live DISTANCE HUD in the corner.
  3. 3
    Scroll downThe camera closes in along a corkscrew path — the planet grows, the terminator sweeps across its face, and the atmosphere rim brightens.
  4. 4
    Watch the final approachThe power-curve easing flattens the last stretch so arrival into orbit feels like a braking burn rather than a sudden stop.
  5. 5
    Scroll back upThe whole approach reverses exactly — distance, glow, and HUD all derive from one scrubbed value, so nothing is one-shot.
  6. 6
    Recolor the planetChange the ocean, land, and ice THREE.Color values or the noise threshold (0.35) to redraw the continents instantly — no texture needed.

Real-world uses

Common Use Cases

Space and aerospace landing pages
Open a satellite, launch-provider, or space-data product page with an arrival sequence that ends exactly where your content begins.
Sci-fi game and metaverse promos
Use the approach as a "destination reveal" before showing gameplay, pairing naturally with a starfield warp intro above it.
Story-driven scrollytelling
Anchor chapter one of a scroll narrative on arrival at a world, then hand off to a scroll camera path for the surface tour.
Teaching procedural vertex coloring
A compact demonstration of painting geometry with BufferAttribute colors instead of textures, plus the BackSide atmosphere trick.
Portfolio hero with a destination metaphor
Frame your work as "arriving somewhere" — the orbit-established endpoint makes a natural transition into a project grid.
Ambient generative-art pages
Let the clock-driven rotation and cloud drift carry the scene between scrolls, similar to the idle motion in galaxy formation.

Got questions?

Frequently Asked Questions

Each vertex of the SphereGeometry is colored directly through a color BufferAttribute. The vertex normal is fed into a sum of sin/cos products at different frequencies, and the result is thresholded: above 0.35 paints land green, below paints ocean blue, and any vertex with |y| > 0.86 becomes polar ice. MeshLambertMaterial with vertexColors: true interpolates between vertices, so the 96-segment sphere reads as soft continents with zero network requests.

A second sphere 7% larger than the planet is rendered with side: THREE.BackSide, so only the inside of its far hemisphere draws — visually a rim halo hugging the planet's limb. Its opacity is tied to the scrubbed progress value (0.08 in deep space up to ~0.38 in orbit), which imitates entering the atmosphere's optical thickness without writing GLSL.

The tween stays ease: "none" so one linear 0–1 value is shared by every derived quantity. Applying 1 − (1 − p)^2.2 only to the distance lets the camera brake late while the swing angle and moon advance stay linear — different easings per property from a single scrub, which one eased tween could not provide.

A straight-line approach at a sphere only changes silhouette size, which reads as a zoom rather than travel. Advancing the camera's orbital angle 2.1 radians during the approach sweeps the day/night terminator across the visible face and generates parallax against the moon and starfield, so the motion reads as flight through space.

Yes. Click JSX, Vue, Angular, or Tailwind to export a component. Build the scene inside a mount effect (useEffect / onMounted / ngAfterViewInit) against a canvas ref, and in the cleanup kill the ScrollTrigger instance, dispose the sphere geometries and materials, and call renderer.dispose() so the WebGL context and scroll pin are released on unmount.