Interactive Newton's Cradle
Five canvas balls hung from a bar by 120 px strings respond to angular physics: momentum transfers from ball to ball on collision. Click and drag a ball to raise it, then release to launch it. Sharp on Retina, loop paused off-screen, static balls under reduced motion.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →
3 usage examples



How it works
Interactive Newton's Cradle — distinct from Newton's Cradle Loop (fx-0384, automatic animation): here the user drags the balls directly and triggers collisions. The .fx-0389-root wrapper contains a .fx-0389-canvas that is 100 % wide by 300 px tall. The script reads devicePixelRatio at init, sizes the bitmap accordingly and draws in CSS pixels via ctx.scale(dpr, dpr). The five balls are spaced 40 px apart around the horizontal centre; the first starts at −0.5 radians to begin the oscillation.
Each frame, the angular acceleration of each free ball is −0.0015 × sin(angle) (simple pendulum), with 0.9995 damping per frame. Collisions are detected when the horizontal distance between consecutive balls is less than the sum of their radii: momentum is exchanged and angles adjusted to separate them. Scaling by dt / 16.67 (capped at 50 ms) keeps the simulation stable after a background tab.
A mousedown (or touchstart) finds the ball under the cursor by comparing the distance to its radius; mousemove (or touchmove) updates the held ball's angle from the cursor's horizontal position, clamped to ±0.8 radians. An IntersectionObserver watches the root to pause the loop off-screen.
Accessibility
- Reduced motion: under
prefers-reduced-motion: reduce, the loop does not start and the balls are drawn at their initial position without oscillation. The effect is visible and readable. - Keyboard: the interaction requires a mouse or finger (click-drag on a ball). There is no natural keyboard equivalent for a click-drag on a canvas. Keyboard users cannot interact with the effect — this should be stated honestly if the effect is used as a functional component.
- Touch:
touch-action: noneon the canvas prevents page scrolling when a finger slides over it. The effect responds to touch on mobile. - Decorative role: the canvas carries no text content. If the balls represent named entities, expose those names as text beside the canvas.
Browser compatibility
Canvas 2D (devicePixelRatio, IntersectionObserver, matchMedia), no dependency. IntersectionObserver available since Chrome 51, Firefox 55 and Safari 12.1. Not measured in Firefox and WebKit.
Without JavaScript, the canvas stays empty. Without IntersectionObserver, the simulation runs off-screen too. Without matchMedia, the balls animate even under reduced motion.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0389-root"><div class="physics-container"><canvas class="fx-0389-canvas"></canvas><span class="info-label">Help text</span></div></div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
String length (JS — var STR = 120) |
120 px | 80 px for a faster, more compact pendulum; 160 px for a slower, wider swing. |
Initial angle (JS — angle: i === 0 ? -0.5 : 0) |
−0.5 radians for the first ball | −0.8 for a stronger start (maximum impulse: 0.8 radians); 0 to start in balance (wait for a click). |
Damping (JS — Math.pow(0.9995, scale)) |
0.9995 per frame | 0.999 stops the swing in a few seconds; 0.9999 keeps it going almost indefinitely. |
Ball colours (JS — gradient in createRadialGradient) |
#8b5cf6, #6366f1, #4338ca |
Replace with your brand's primary colour. The three gradient stops create the 3D effect. |
Number of balls (JS — for (var i = 0; i < 5; i++)) |
5 balls | 3 or 7 balls work; adjust the spacing (40 * i) and offset (−80) accordingly. |
FAQ
dragIdx) is maintained. To drag two balls simultaneously, you would need to track two touch identifiers (Touch.identifier) and two drag indices.H = 300 and the CSS rule .fx-0389-canvas { height: 300px }. The hanging bar redraws automatically at y = 30; strings descend STR pixels below it.