Three.js Scroll Pendulum Wave — GSAP Physics Scrub

Three.js Scroll Pendulum Wave · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

True pendulum-wave physics: pendulum i completes 26 + i oscillations per 30 s cycle, realigning exactly at cycle end
Scroll scrubs simulated time — play, pause mid-swing, and run entropy backwards, impossible with the real apparatus
Closed-form angles (A·sin(ωT)) mean zero accumulated state: time can jump anywhere without integration error
Pivot-group rotation swings wire and bob together through the scene graph, no per-frame trigonometry for bob arcs
Emissive intensity tied to |angle|/A makes bobs glow at their turning points, sweeping a secondary glow wave along the line
HSL hue ramp across pendulums keeps each identifiable through camera moves
Camera slides from side profile to front view — the two angles that reveal amplitude versus phase pattern
Live simulated-time HUD driven by the same scrubbed value

About this UI Snippet

How to Build a Scroll-Scrubbed Pendulum Wave With Three.js and GSAP

Screenshot of the Three.js Scroll Pendulum Wave snippet rendered live

The Three.js Scroll Pendulum Wave snippet recreates the famous physics demonstration — fifteen pendulums of graduated frequency swinging from one beam, drifting from a perfect traveling wave into apparent chaos and snapping back into unison — with one twist: scroll position *is* time. GSAP's ScrollTrigger scrubs a simulated-time value from 0 to 30 seconds, so users can play the demonstration forward, pause at any instant, and run physics backwards, which no video of the real apparatus can do.

The pendulum wave equation

The classic apparatus works because pendulum i completes exactly 26 + i oscillations in one shared cycle. This snippet encodes that directly: each pendulum's angular frequency is (26 + i) / 30 × 2π rad/s, and its swing angle at any instant is A × sin(ω × T). At T = 0 all fifteen are in phase; small frequency differences accumulate into traveling snakes, then two interleaved groups swinging opposite ways, then apparent randomness — and at exactly T = 30 every phase difference is a whole multiple of 2π and the line snaps back together. None of this is choreographed; it falls out of fifteen sine evaluations per frame.

Scrubbing time instead of animating it

Because the swing angle is a closed-form function of T (no integration, no accumulated state), simulated time can jump anywhere without error: scroll fast and the wave fast-forwards, stop mid-scroll and it freezes at a physically exact configuration, scroll up and entropy visibly runs backwards into order. This is the deepest version of the derive-from-one-value pattern in this series — where the gear train scrubs an angle, this scrubs the independent variable of a physics equation. Any simulation expressible in closed form gets scrub-reversibility for free.

Rotation about the pivot, not bob positioning

Each pendulum is a Group positioned at the beam with the wire and bob as children hanging below the group origin. Setting group.rotation.x swings the entire assembly about the pivot — the wire tilts and the bob traces its arc automatically through the transform hierarchy, the same scene-graph leverage used by the chips in the exploded view. Computing bob arc positions by hand would need trigonometry per frame and would leave the wire pointing the wrong way.

Emissive glow at the turning points

Real pendulum bobs seem to hang at their extremes, where velocity crosses zero. To emphasize this, each bob's emissiveIntensity scales with |angle| / A — bobs glow brightest exactly where they pause. Since neighboring pendulums reach extremes at different instants, the glow sweeps along the line as its own secondary wave, making phase relationships readable even from the front view. Bob hues sweep a blue-to-magenta HSL range so each pendulum is identifiable across camera moves.

A camera move that changes what you understand

The pendulum wave looks completely different from different angles: side-on you see the swing amplitude; front-on you see the phase pattern — the snakes and interleaving groups. The camera slides 1.2 radians from profile toward front view across the cycle, so the scroll journey doubles as a lesson in why this demonstration is filmed from the end of the beam. A small clock-driven bob keeps the shot alive during scroll pauses, consistent with the idle-motion convention across this series, like the drifting clouds of the planet approach.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not need to rediscover why 26, 27, 28... oscillations per cycle produce snakes and realignment. Paste this snippet's HTML, CSS, and JS into an AI assistant like Claude and ask it to explain the phase mathematics, why closed-form angles make time scrubbing exact, or what happens if you change BASE_OSC. The same assistant can extend the demonstration — adding motion-blur trails by rendering bob positions at several recent T values with fading opacity, a slider that decouples from scroll for touch-free replay, damping that makes amplitude decay with T for realism, or labels that appear at notable instants (half-cycle interleave, third-cycle triplets). It can also retheme bob hues to a brand ramp. Treat the code as a starting point to interrogate and reshape, 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 pendulum wave" in plain HTML, CSS, and JavaScript using Three.js and GSAP's ScrollTrigger plugin, all loaded from a CDN (no bundler, no build step).

Requirements:
- A pinned full-viewport section with a canvas, WebGLRenderer, PerspectiveCamera (resized with aspect on window resize), ambient plus directional light, and a metallic support beam (BoxGeometry) at the top.
- 15 pendulums hanging from the beam. Each is a THREE.Group with its origin AT the pivot: a thin CylinderGeometry wire child and a SphereGeometry bob child at the wire's end. Bob materials use an HSL hue ramp (blue → magenta) with an emissive component.
- Pendulum wave frequencies: pendulum i has angular frequency (26 + i) / 30 × 2π rad/s, so the line realigns exactly at T = 30. Slightly longer wires for slower pendulums.
- One GSAP tween (ease "none") scrubbing a SIMULATED TIME value from 0 to 30 on a ScrollTrigger with pin: true, scrub ~0.4, end ~+=500%.
- Each frame set group.rotation.x = 0.55 × sin(freq × T) per pendulum — closed form, no integration — and set emissiveIntensity = 0.4 + 1.1 × |angle| / 0.55 so bobs glow at their turning points.
- A camera that slides ~1.2 radians from a side profile toward a front view across the cycle (lookAt beam center), with a small clock-driven bob so the shot idles alive.
- A HUD showing T to one decimal place, and an intro overlay fading once T passes ~0.15.
- Confirm: pausing scroll freezes an exact configuration, and scrolling backwards runs the wave in reverse until the pendulums realign at T = 0.

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.

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 JSFifteen pendulums hang motionless and aligned from a beam, viewed from the side, with a T = 0.0 S HUD.
  3. 3
    Scroll to start timeThe line swings as one, then a traveling snake forms as small frequency differences accumulate.
  4. 4
    Pause anywhereStop scrolling and the system freezes at an exact instant — inspect the two interleaved counter-swinging groups around mid-cycle.
  5. 5
    Scroll backwardsPhysics runs in reverse: chaos reassembles into the traveling wave and back to unison, frame-perfect.
  6. 6
    Retune the demonstrationChange N, CYCLE, or BASE_OSC — e.g. 20 pendulums over 40 s starting at 35 oscillations — and the wave patterns recompute automatically.

Real-world uses

Common Use Cases

Physics teaching and STEM outreach pages
The scrub turns a one-shot classroom demo into an explorable: students pause at the interleave point and reverse it, unlike any video.
Science museum and planetarium sites
A signature interactive for institutions whose real pendulum wave draws crowds — pair with a scroll year timeline of exhibits.
Order-from-chaos brand storytelling
The realignment moment is a ready-made metaphor for consultancies and data companies; land key copy exactly at T = 30.
Ambient hero sections
Even without the physics framing, fifteen glowing bobs tracing waves make a hypnotic backdrop, calmer than a lightning orb.
Kinetic and generative art portfolios
Present it as time-sculpture alongside pieces like the wave ribbon, with scroll as the exhibition control.
Explaining periodicity and aliasing
Analytics and signal-processing products can use the interleaved-groups moment to explain sampling and phase concretely.

Got questions?

Frequently Asked Questions

Each pendulum completes a whole number of oscillations in the shared 30-second cycle — 26 for the first, 27 for the next, and so on. At T = 30 every pendulum has finished its integer count, so every phase difference is a multiple of 2π and the line is exactly as it was at T = 0. The intermediate snakes and interleaved groups are just the fractional phase differences passing through simple ratios like 1/2 and 1/3.

Because the swing angle is closed-form — angle = A·sin(ω·T) — there is no integrator carrying state from frame to frame. Any T gives an exact configuration, so jumping time around (which is what fast or reversed scrolling does) cannot accumulate error. A force-integrated simulation would need fixed timesteps and could not run backwards for free.

Each pendulum is a Group whose origin sits at the pivot on the beam; the wire and bob are children positioned below it. Setting group.rotation.x rotates the whole assembly about the pivot, so the wire tilts and the bob follows its arc purely through the transform hierarchy — no per-frame trigonometry to place the bob, and the wire always points at it by construction.

Each bob's emissiveIntensity is 0.4 + 1.1 × |angle| / A, peaking at the swing extremes where the pendulum momentarily pauses. Neighboring pendulums hit their extremes at slightly different times, so the brightness peak travels along the line as its own wave — a secondary visualization of the same phase relationships that create the position snakes.

Yes. Export with the JSX, Vue, Angular, or Tailwind buttons. Create the pendulum groups and ScrollTrigger in a mount effect against a canvas ref; keep sim.t in a plain object (not state) since it updates every scrubbed frame. On cleanup kill the ScrollTrigger, dispose wire and bob geometries and materials, and call renderer.dispose() so the pin and WebGL context release cleanly.