Three.js Scroll Domino Run — Edge-Pivot Chain Topple

Three.js Scroll Domino Run · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Edge-pivot topple via geometry.translate — rotation.x alone tips each tile about its resting edge
CatmullRomCurve3 layout: 64 tiles placed by getPointAt with yaw from the curve tangent, re-routable via five points
Topple front keyed to path parameter, so the chain reaction moves at constant speed along the curve
Overlapping 0.055 windows — the previous tile is still falling as the next one starts
easeOutQuad per tile: gravity-fast initial tip decelerating into rest
Rest angle π/2 × 0.82 so tiles lean on neighbors at ~74° instead of pancaking flat
Chase camera sampling the same spline twice (look-at at the front, anchor 0.12 behind)
Honest DOWN counter — counts completed windows, not raw scroll percentage

About this UI Snippet

How to Build a Scroll-Driven Domino Run With Three.js and GSAP

Screenshot of the Three.js Scroll Domino Run snippet rendered live

The Three.js Scroll Domino Run snippet lines 64 dominoes along a snaking S-curve and lets scroll drive the topple front down the chain — each tile tipping about its bottom edge with a gravity-fast ease, settling into a lean against its neighbor, while a low tabletop camera chases the falling front along the spline. GSAP's ScrollTrigger scrubs the front's position; everything else is derived per frame.

The pivot is a geometry translation

A domino must rotate about its bottom-front edge — the edge it tips over in reality. Like the spine hinge in the book pages snippet, this is solved with a one-time geometry translation: geometry.translate(0, H/2, D/2) moves the box so that edge sits at the local origin, and from then on plain rotation.x *is* the topple. No pivot groups, no matrix composition — the same trick that handles doors, levers, and lids handles a falling tile.

A spline placement that snakes

The run follows a CatmullRomCurve3 through five control points, sampled at 64 even parameters with getPointAt. Each domino's yaw comes from the curve tangent via atan2(tangent.x, tangent.z), so tiles always face along the path — through both S-bends — without any manual angle bookkeeping. Re-routing the entire run means editing five control points; count, spacing, and facing all recompute. A hue ramp across the chain (magenta fading toward orange) makes the front's progress legible even in wide shots.

A topple front with per-domino windows

The scrubbed value positions an invisible *front* traveling the chain from u = 0 to u = 1. Each domino compares the front against its own path parameter: once passed, it animates through a short window (WIN = 0.055) from upright to its rest angle. The window overlap means the previous tile is still falling as the next one starts — the visual signature of a chain reaction — using the same derived-stagger arithmetic as the voxel build, but keyed to path parameter rather than index, so the front moves at constant *speed along the curve* even where control points crowd.

Two constants encode the physics feel

easeOutQuad on each tile's window mimics gravity taking over — the tip starts fast and decelerates into rest, the inverse of a thrown object. And the rest angle is π/2 × 0.82, not a full quarter turn: real toppled dominoes never lie flat, they lean on the next tile at roughly 74°. That 0.82 factor is the difference between a chain of tiles that reads as *resting on each other* and one that reads as pancaked. Tiles never intersect because neighbors farther down the chain are always at an equal or lesser angle.

A chase camera on the same spline

The camera samples the curve twice — once at the front for its look-at, once 0.12 behind for its own anchor — then offsets low and wide like a tabletop tracking shot. Because both samples derive from the same scrubbed front, the camera decelerates through bends exactly as the front does, and reversing the scroll rewinds the chase shot along with the un-toppling tiles. The DOWN counter counts tiles whose window has completed, honest-count style like the portal gate sequence. For the launch-scale version of a chain of staged events, compare the rocket launch phase table.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not need to work out edge pivots and front propagation yourself. Paste this snippet's HTML, CSS, and JS into an AI assistant like Claude and ask it to explain the geometry-translation pivot, the parameter-keyed topple front, or why the rest angle is 82% of a quarter turn. The same assistant can escalate the run — branching chains that split at a Y junction (two splines sharing a control point), a tile that flips a lever or rings a bell mid-chain using the same window math, camera cuts between wide and chase framing at set front positions, or your logo spelled in dominoes by generating control points from text coordinates. It can also convert the tiles to an InstancedMesh with per-instance rotation matrices if you want a thousand-tile run. 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-driven domino run" 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 + directional light, a large dark table BoxGeometry, and Fog matched to the background.
- A THREE.CatmullRomCurve3 through five control points forming an S-curve on the table plane.
- 64 domino tiles (BoxGeometry ~2.1 × 4.2 × 0.6) placed at even curve parameters with getPointAt; each tile's yaw = atan2(tangent.x, tangent.z) from getTangentAt so it faces along the path. HSL hue ramp across the chain.
- Edge pivot: apply geometry.translate(0, H/2, D/2) ONCE per tile so the bottom-front edge is the local origin — rotation.x alone must perform the topple.
- One GSAP tween (ease "none") scrubbing p 0→1 on a ScrollTrigger with pin: true, scrub ~0.4, end ~+=450%.
- Topple front: front = p × (1 + WIN) with WIN = 0.055; each tile's local progress = clamp((front − u) / WIN); rotation.x = easeOutQuad(local) × (π/2 × 0.82) so tiles tip fast and settle into a ~74° lean, never lying flat. Windows must overlap so the previous tile is still falling as the next starts.
- A chase camera that samples the SAME spline twice — lookAt point at the front (clamped to [0.015, 0.985]), camera anchor 0.12 behind — offset low and to the side like a tabletop tracking shot, with a small clock-driven sway.
- A HUD "n / 64 DOWN" counting tiles whose window completed, and an intro overlay fading at p > 0.02.
- Confirm reverse scrolling stands tiles back up in exact reverse order while the chase shot rewinds.

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 JSSixty-four hue-ramped dominoes stand along an S-curve on a dark table, HUD reading 0 / 64 DOWN.
  3. 3
    Scroll to toppleThe front travels the chain — each tile tips fast and settles into a 74° lean on its neighbor while the camera chases low along the spline.
  4. 4
    Ride the bendsTangent-derived yaw keeps every tile facing along the path through both S-bends; the hue ramp shows progress at a glance.
  5. 5
    Scroll backTiles stand back up in exact reverse order and the chase shot rewinds — the front is a pure function of the scrub.
  6. 6
    Re-route the runEdit the five CatmullRom control points (or add more) — placement, facing, and camera path all recompute automatically.

Real-world uses

Common Use Cases

Cause-and-effect product stories
Automation and workflow tools get their pitch literally: one trigger, a visible chain of consequences — annotate stages with scroll pin steps.
Agency and campaign intros
The chain reaction is a classic momentum metaphor; land the last tile's fall on your headline like a scroll hero exit beat.
Teaching pivot and spline techniques
Two transferable patterns in one scene: edge-pivot geometry translation and parameter-keyed stagger along a CatmullRom curve.
Physics-toy and puzzle game promos
Rube-Goldberg games can demo their core loop scrubbed; pair with the physics 2D burst for interaction contrast.
Process and pipeline visualizations
Sixty-four stages of anything — CI steps, supply chain hops — falling in sequence, with hue encoding the pipeline segment.
Cascade and dependency storytelling
Risk, contagion, and dependency-graph narratives get a visceral cascade; the DOWN counter doubles as an impact metric.

Got questions?

Frequently Asked Questions

geometry.translate(0, H/2, D/2) is applied once at build time, shifting the box's vertices so the bottom-front edge lies at the local origin. Rotation always occurs about the local origin, so rotation.x now tips the tile about exactly the edge a real domino pivots on. One translation replaces a pivot Group per domino — 64 fewer scene-graph nodes.

Index-keyed stagger would make the front race through regions where dominoes happen to be closer together and crawl where they spread out. Keying to the CatmullRom parameter u (each tile compares the front against its own u) makes the reaction travel at constant speed along the curve, which matches how a real chain propagates — spacing determines timing, not array position.

Real toppled dominoes rest ON the next tile, propped at roughly 70–80° of rotation depending on spacing. The REST constant of π/2 × 0.82 reproduces that lean. A full 90° would make tiles interpenetrate the table and each other, and would read instantly as fake — the 0.82 factor is the cheapest realism in the scene.

The window arithmetic guarantees a monotonic angle gradient down the chain: a tile can never be more rotated than the one before it, because its window starts later on the same front. Combined with the sub-90° rest angle and the spacing implied by 64 samples over the spline, each tile's swept volume stays clear of its neighbor's — collision-free by construction rather than by physics testing.

Yes. Export via the JSX, Vue, Angular, or Tailwind buttons. Build the spline, dominoes, and ScrollTrigger inside a mount effect against a canvas ref; the HUD counter should update through a ref. On cleanup kill the ScrollTrigger, dispose all 64 geometries and materials plus the table, and call renderer.dispose(). The curve object itself is plain math and needs no disposal.