webdevpuneet.com

Three.js Scroll Prism — Spectrum Dispersion Fan

Three.js Scroll Prism Light Split · Scroll · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<section class="prm-stage" id="prmStage">
  <div class="prm-intro"><p>Scroll ↓ to split the light</p></div>
  <canvas id="prmCanvas"></canvas>
  <div class="prm-hud">DISPERSION <span id="prmPct">0</span>%</div>
</section>
<section class="prm-bottom"><p>White light was the whole story all along.</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

Prism from CylinderGeometry with 3 radial segments — a zero-cost extruded equilateral triangle
Budget glass: MeshPhysicalMaterial at 22% opacity, near-zero roughness, plus an EdgesGeometry outline
Beams as stretched boxes via a layBeam(midpoint, length, atan2) helper — WebGL line-width limits bypassed
Physically ordered dispersion: per-ray bend factors from −3 to +3, violet deflecting most
White beam thins as the fan opens — energy visibly transferring into the spectrum
Two-phase scrub: beam arrival (30%), smoothstepped fan opening (70%)
Camera swings edge-on to frontal, reframing the subject from beam to spectrum
300 additive dust motes giving the light something to illuminate, plus independent per-ray shimmer

About this UI Snippet

How to Build a Scroll-Driven Prism Light Split With Three.js and GSAP

Screenshot of the Three.js Scroll Prism Light Split snippet rendered live

The Three.js Scroll Prism Light Split snippet stages the most famous experiment in optics: a white beam extends across a dark room into a glass prism, and as the user keeps scrolling, seven spectral rays fan out of the far face — red bending least, violet most — while the camera swings from an edge-on beam view to the full *Dark Side of the Moon* silhouette. GSAP's ScrollTrigger scrubs one dispersion value; the beams are boxes laid between computed points.

A prism from a three-sided cylinder

Three.js has no prism primitive, but CylinderGeometry(6, 6, 7, 3) — three radial segments — is exactly an extruded equilateral triangle. Rotated so its axis lies horizontal, it presents a triangular cross-section to the camera at zero modeling cost. The glass recipe repeats this series' budget formula (see the hourglass bulbs): MeshPhysicalMaterial at 22% opacity with near-zero roughness, depthWrite off, plus an EdgesGeometry wireframe overlay so the silhouette stays crisp even where the glass is nearly invisible.

Beams are boxes, not lines

WebGL line width is capped at 1px on most platforms, so glowing light rays can't be Line objects. Every beam here is a 1-unit BoxGeometry stretched between two points by a layBeam() helper: scale.x becomes the length, position the midpoint, rotation.z the atan2 of the direction. Additive blending makes overlapping beams brighten each other, and each ray's cross-section shimmers independently on clock time so the fan reads as *light*, not painted stripes. The white beam thins as dispersion grows — its energy visibly transferring into the spectrum.

Dispersion as a per-ray bend factor

Each of the seven rays stores a bend factor from −3 (red) to +3 (violet), and its exit angle is −0.12 − bend × 0.085 × dispersion — so at zero dispersion all rays overlap the white beam's line, and as the scrub advances the fan opens with violet deflecting most, the correct physics ordering. Ray length also grows with dispersion (4 to 50 units), shooting color to the frame edges at full split. Because angle and length are pure functions of the scrubbed value, scrolling back retracts the spectrum into the prism and restores the undivided white beam.

Two phases, one camera thesis

The scrub splits at 30%: first the white beam *reaches* — extending from off-screen to the entry face, an arrival that gives the split a cause — then the fan opens through a smoothstepped 70%. Meanwhile the camera swings 1.1 radians from nearly edge-on (where the beam is a bright line and the prism a dark triangle) to frontal (where the fan is widest). The camera move is doing argumentative work: it starts where the *beam* is the subject and ends where the *spectrum* is, the same choreography-as-explanation idea as the pendulum wave's profile-to-front slide.

Dust makes light visible

Beams in empty space are invisible in reality and unconvincing in 3D. Three hundred additive dust motes drift through the scene, giving the beams something to appear to illuminate — the same trick film sets use with haze machines. The prism itself rotates half a radian as dispersion grows, suggesting the split is *caused* by the geometry change, and idles with a gentle wobble so the scene never freezes. For the full-scene color treatment of this idea, see the scroll color morph; for beams at architectural scale, the lightning orb.

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 glass prism floats in a dark, dust-hazed room, viewed nearly edge-on — DISPERSION 0% in the HUD.
  3. 3
    Scroll to send the beamAcross the first 30% a white beam extends from off-screen and lands on the prism's entry face.
  4. 4
    Keep scrolling to split itSeven rays fan from the exit face — violet bending furthest — while the white beam visibly thins and the camera swings to the frontal view.
  5. 5
    Scroll backThe spectrum retracts into the prism and the beam withdraws — every angle and length is a pure function of the scrub.
  6. 6
    Restyle the spectrumEdit the SPECTRUM hex array (fewer, more, or brand colors) — bend factors derive from array position automatically.

Real-world uses

Common Use Cases

Creative-tool and brand-palette pages
Design tools whose product is color get their origin story: white in, spectrum out — swap SPECTRUM for your brand ramp.
Analytics and "one input, many insights" pitches
The prism is the diagram every BI deck draws — here it renders live, with rays as report categories annotated via scroll pin steps.
Physics and optics teaching pages
Correct dispersion ordering plus a scrub students can reverse — pair with the pendulum wave for a classroom set.
Music and album visuals
The Dark Side silhouette is a permanent cultural reference — land the full fan on a tracklist or tour date reveal.
Portfolio hero for colorists and photographers
Light-as-subject framing suits color graders; the dust-haze room sets a cinematic mood beyond a flat aurora background.
Puzzle games with light mechanics
Beam-routing puzzles can demo their core verb — split, bend, recombine — before a single screenshot.

Got questions?

Frequently Asked Questions

CylinderGeometry's radialSegments parameter controls the cross-section polygon: 32 gives a circle, 3 gives an equilateral triangle — which extruded along the axis is exactly a prism. Rotated 90° so the axis is horizontal, the triangle faces the camera. It ships in every Three.js build, needs no ExtrudeGeometry shape path, and its EdgesGeometry gives clean silhouette lines for the glass outline.

The WebGL spec only guarantees 1-pixel line width, and most platforms enforce it, so glowing beams cannot be drawn as lines. A unit BoxGeometry stretched by scale.x between two points — midpoint position, atan2 rotation — renders at any thickness, supports additive blending for overlap glow, and its cross-section can animate (the shimmer and the white beam's thinning) via scale.y/z.

The ordering is: violet carries the largest bend factor and deflects most, red least — matching real glass, where refractive index rises toward shorter wavelengths. The angles themselves are art-directed rather than Snell's-law-derived (a real 60° prism at this geometry would fan only a few degrees), a standard theatrical exaggeration so the split reads at page scale.

In reality a light beam crossing clean air is invisible — you see light only where it scatters off something. The 300 additive-blended motes drifting through the scene give the beams an atmosphere to visually illuminate, the same reason film sets use haze machines. Without them the boxes read as solid neon tubes; with them, as light through a dusty room.

Yes. Export via the JSX, Vue, Angular, or Tailwind buttons. Build the prism, beams, and ScrollTrigger inside a mount effect against a canvas ref; the layBeam helper and scratch vectors live in effect scope. On cleanup kill the ScrollTrigger, dispose the prism geometry, edges, every beam box's geometry/material, the mote system, and call renderer.dispose().