Three.js Scroll Particle Assembly — GSAP Effect

Three.js Scroll Particle Assembly · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Two pre-computed positions per particle (scattered + target) blended by a single scrubbed 0–1 value
Fibonacci-sphere target distribution via the golden angle for an even, un-clumped assembled shape
Smooth-step easing (p*p*(3-2p)) so particles settle into place instead of crossing at a constant rate
Single Float32Array BufferAttribute rewritten in place — one geometry upload per frame at any count
Additive blending with depthWrite off for a glowing, artifact-free transparent point cloud
Per-particle color set once from height, never recomputed, keeping per-frame work to position math
Live status caption driven by ScrollTrigger onUpdate self.progress
Fully reversible and pinned — scrolling back up dissolves the sphere with no extra code

About this UI Snippet

How to Build a Scroll-Driven Particle Assembly Effect With Three.js and GSAP

Screenshot of the Three.js Scroll Particle Assembly snippet rendered live

The Three.js Scroll Particle Assembly snippet starts with a cloud of 2,600 scattered points and pulls each one into an ordered sphere as the visitor scrolls — the scrollbar drives the assembly progress directly, not a timer — using a Three.js Points cloud and GSAP's ScrollTrigger plugin, both loaded from a CDN.

Two positions per particle, blended by one number

The core idea is that every particle carries two pre-computed 3D coordinates: a random "scattered" position in a loose box of noise, and an ordered "target" position on the surface of a sphere. Neither is ever recomputed. Scroll only moves a single value p from 0 to 1, and each frame the live position is a straight linear interpolation between the two stored coordinates. This is dramatically cheaper than physics or per-particle easing, because the expensive random layout is done once at startup and every frame is just addition and multiplication.

A Fibonacci sphere for an even assembled shape

If the target positions were random points on a sphere, the assembled form would look clumpy and uneven. Instead the targets use the golden-angle spiral (a Fibonacci sphere): each particle's Y is stepped evenly from top to bottom and its angle advances by the golden angle of about 2.39963 radians. This spreads the points across the surface with almost no clustering, so the moment of full assembly reads as a clean, deliberate sphere rather than a noisy blob.

Smooth-step so the assembly eases

The raw scrubbed progress is passed through the classic smooth-step curve p * p * (3 - 2p) before it drives the interpolation. This means the particles accelerate out of the scattered state and decelerate into the assembled state, rather than crossing at a constant, mechanical rate. The visitor feels the shape "settling" into place at the end of the scroll, which a linear blend never achieves.

One BufferAttribute updated in place

All 2,600 positions live in a single Float32Array backing a BufferAttribute. Each frame the loop rewrites that array in place and sets needsUpdate = true, so there is exactly one geometry upload per frame regardless of particle count. Colors are set once at startup from each particle's height and never touched again, keeping the per-frame work to position math only.

Additive blending for a glowing cloud

The PointsMaterial uses additive blending with depthWrite disabled, so where particles overlap their colors add toward white and the cloud glows from within. Disabling depth writes prevents the sorting artifacts that otherwise plague large transparent point clouds, and the slight constant Y rotation keeps the shape alive even when the visitor pauses mid-scroll.

scrub: 0.5 and a live status label

A small numeric scrub smooths the assembly against noisy input, and ScrollTrigger's onUpdate callback reads self.progress to swap a caption between "Scattered", "Assembling…", and "Assembled". This same scatter-to-target pattern powers the scroll text grid snippet, which targets a flat grid instead of a sphere. Contrast it with the physically-simulated magnetic particles or pair it with a starfield warp intro.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not have to work out how thousands of particles move together without lag. Paste this snippet's HTML, CSS, and JS into an AI assistant like Claude and ask it to explain why each particle stores two positions and why the target uses a golden-angle spiral instead of random spherical points. The same assistant can help you change the destination shape — ask it to assemble the particles into a cube, a torus, or the outline of a word by generating a new target array — or to add a subtle per-particle delay so the sphere assembles in a wave rather than all at once. It can also optimize the loop, for instance moving the interpolation into a GLSL shader so the CPU stops rewriting the buffer every frame. 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-scrubbed particle assembly" 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 and PerspectiveCamera sized to it and updated on window resize including aspect ratio.
- Create about 2,600 particles as a THREE.Points cloud backed by a single BufferGeometry position attribute.
- For every particle, pre-compute two fixed positions once at startup: a random "scattered" coordinate in a loose noise box, and a "target" coordinate on the surface of a sphere using a Fibonacci / golden-angle spiral for an even distribution. Also set a per-particle color once from its height, using vertexColors.
- Use a PointsMaterial with additive blending and depthWrite disabled for a glowing cloud.
- Register a GSAP tween on a ScrollTrigger targeting the pinned section, with pin: true, start at top top, a small numeric scrub (~0.5), and an end a few hundred percent tall, animating a single plain value p from 0 to 1. Use the ScrollTrigger onUpdate callback to swap a caption between scattered / assembling / assembled based on self.progress.
- Every animation frame (requestAnimationFrame), pass p through a smooth-step curve, then rewrite the position buffer in place as a linear blend from each particle's scattered position to its target position, and set needsUpdate. Add a slow constant rotation so the cloud stays alive when scrolling pauses.
- Confirm scrolling back up dissolves the sphere back into the cloud, since p is fully scrubbed rather than a one-way timer.

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 scattered cloud of glowing particles appears in a pinned 3D stage with a status label.
  3. 3
    Scroll downThe particles migrate from their scattered positions into an ordered sphere, tied to scroll.
  4. 4
    Scroll back upThe sphere dissolves back into the cloud exactly, since the progress value is fully scrubbed.
  5. 5
    Change the target shapeReplace the Fibonacci-sphere math in the target loop to assemble a cube, ring, or text layout instead.
  6. 6
    Tune density and paceAdjust COUNT for more or fewer particles and the ScrollTrigger end value for a longer or shorter assembly.

Real-world uses

Common Use Cases

Hero reveals for tech brands
Let a scattered cloud resolve into a logo, planet, or product silhouette as the page loads and scrolls.
Data-story openers
Assemble thousands of points to imply a dataset coming into focus before a chart section begins.
Teaching buffer-geometry animation
A minimal, readable example of interpolating a BufferAttribute in place instead of per-particle tweens.
Loading and intro transitions
Use the assembly as a scroll-gated intro before revealing a horizontal gallery.
Science and space themes
The glowing sphere suits astronomy, biotech, and particle-physics landing pages.
Generative art sections
Swap the target for any parametric surface to assemble bespoke generative forms on scroll.

Got questions?

Frequently Asked Questions

Each particle keeps a fixed scattered coordinate and a fixed target coordinate, both computed once at startup. Scroll only moves one value p, and the live position is a linear blend between the two. This avoids per-particle easing objects or physics entirely, so even thousands of points cost only a little addition and multiplication per frame.

It distributes points on a sphere by stepping Y evenly and rotating each point by the golden angle (~2.39963 radians). Compared with random spherical points, it spreads particles almost uniformly with no visible clumping, so the assembled shape reads as a clean, deliberate sphere at the end of the scroll.

The raw scrubbed progress is linear. Running it through p*p*(3-2p) makes the particles accelerate away from the scattered state and decelerate into the assembled state, so the shape appears to settle into place. A linear blend, by contrast, moves every particle at a constant, mechanical rate the whole way.

All positions share one Float32Array behind a single BufferAttribute. The animation loop rewrites that array in place and flags needsUpdate once, producing exactly one geometry upload per frame no matter how many particles there are. Colors are written once at startup and never recomputed, so per-frame work is limited to position interpolation.

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. Allocate the typed arrays and build the Points cloud and GSAP timeline inside a mount effect against a canvas ref, and on cleanup kill the ScrollTrigger, call geometry.dispose() and renderer.dispose(), so buffers and the WebGL context are freed on unmount.