
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
A card payment being processed, made as a Newton’s cradle of polished steel on a walnut base: every step of the payment lifts one more ball. One ball swings while the card is authorized, two while the bank verifies it, three while the payment is confirmed, and as many fly out on the other side of the row. The collisions are real physics. At the end the balls slow down and stop, a light runs over them and a tick is drawn; if the bank declines the card the balls go dead at once and Retry appears.
A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>The Newton's cradle loader</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the Newton's cradle loader: a card payment being processed, shown as a Newton's cradle of polished steel on a
walnut base. Every step of the payment lifts one more ball: one ball swings while the card is authorized, two
while the bank verifies it, three while the payment is confirmed. The balls really collide and pass the blow
along the row. At the end they slow down and stop and a tick is drawn. The cradle is drawn by script.js -->
<section class="pay" aria-labelledby="pay-title" data-pay>
<canvas class="pay__cradle" aria-hidden="true" data-cradle></canvas>
<div class="pay__head">
<div class="pay__words">
<h2 class="pay__title" id="pay-title"><span class="pay__swap" data-title>Ready to pay</span></h2>
<p class="pay__meta"><span class="pay__swap" data-meta>$1,249.00 · Card ending 4242</span></p>
</div>
<p class="pay__figure" aria-hidden="true">
<span class="pay__pct" data-pct></span>
<svg class="pay__tick" viewBox="0 0 28 28" data-tick><path d="M6.5 14.8l5 5 10-11.4" pathLength="1"/></svg>
</p>
</div>
<div class="pay__steps" role="progressbar" aria-labelledby="pay-title" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-valuetext="Not started" data-bar>
<div class="step" data-step><span class="step__word">Authorizing</span><span class="step__track"><span class="step__fill"></span></span></div>
<div class="step" data-step><span class="step__word">Verifying</span><span class="step__track"><span class="step__fill"></span></span></div>
<div class="step" data-step><span class="step__word">Confirming</span><span class="step__track"><span class="step__fill"></span></span></div>
</div>
<button class="pill" type="button" data-go data-autoclic><span class="pill__label" data-label>Pay $1,249.00</span></button>
<p class="sr" role="status" aria-live="polite" data-live></p>
</section>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.
40 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The Newton's cradle loader” from Animorio and fit it into my siteEvery ball is a pendulum with its own angle θ and angular speed ω: θ'' = −(2π ÷ PERIOD)² · sin θ − DRAG · θ'. It is integrated with semi-implicit Euler (the speed first, then the angle) in 14 steps a frame, and a frame’s time never goes past 1/30 of a second, so a tab coming back to the front does not make the balls jump. The real sine is used, not the angle: at large swings the oscillations are a little slower, as in real life. The two threads of every ball start from the two rails, one higher than the other because the cradle is seen from a little above, and meet at the eyelet.
When two neighbours touch (their centres are less than two radii apart) they exchange an impulse along the line between the centres. For two constrained pendulums, how far a turn of each moves its ball along that line is a = L · (cos θ · nx − sin θ · ny); the impulse is λ = −(1 + e) · v ÷ (a₁²/I + a₂²/I), with v the speed at which they close in and e = BOUNCE. Then the overlap is shared between the two. The balls at rest hang a quarter of a unit apart, so a blow really travels from ball to ball; the contacts are solved three times a step, both ways. No special rule for «two in, two out»: it comes by itself.
The payment is a GSAP timeline: every step has its share of SECONDS and its percentage (34, 72, 100), slow at the start and at the end like a bank’s answer. When the step changes, the script waits for the lifted balls to reach the top of their swing (θ < 0 and ω going from negative to positive), then holds them, takes one more and brings them all to the step’s angle with a tween; meanwhile the others are braked to rest. After a moment at the top it lets them go. If the balls do not reach the top within 1.6 seconds it takes them anyway.
On a canvas: the base and the back of the frame are painted once into a picture of their own, the front of the frame into another. Every frame the shadows (a soft ellipse that widens and fades as the ball rises), the threads and the balls are painted. Every ball is a dark steel ground, a cap of bright sky, the wood below bent into a bowl whose edge is the curved horizon, the reflection of the base’s light edge, the darker rim, a cool light on the right and the window of light that slides with the ball’s place. When a neighbour comes close, its reflection appears on the side, squashed.
At 95% the last balls let go make one more swing, then the drag rises and when they hardly move any more the last sway is eased to zero with a tween: only then is the tick drawn and a band of light runs over the row (lighter). On a decline the bounce drops to 0.15 and the drag rises: the balls clump together and stop. When nothing moves the loop does not paint. The steps are a role=progressbar with aria-valuenow and aria-valuetext («51 percent, Verifying») at most every 0.6 seconds, aria-busy while it works and an aria-live line for every step, the end and the decline. Clicks from a script (the library preview’s) never bring it back to rest: once it is done, after 2.4 seconds, they pay again.
| Name | File | Default | What it changes |
|---|---|---|---|
SECONDS | script.js | 9 | How long the demo’s payment takes, in seconds (a real one follows the bank’s answer). |
SWING | script.js | 28 | How many degrees the first ball is lifted; with two and three balls the angle is a little smaller. |
PERIOD | script.js | 1.15 | How long a whole swing takes, in seconds: the higher it is, the slower the balls go. |
BOUNCE | script.js | 0.985 | How much the balls bounce off each other: 1 they lose nothing, 0.8 they stop soon and move together. |
DRAG | script.js | 0.08 | The air’s drag on the balls. |
FAIL_EVERY | script.js | 2 | In the demo, one payment in how many is declined by the bank; 0 never. |
FAIL_AT | script.js | 0.52 | How far through the payment the decline comes, from 0 to 1. |
LABELS | script.js | { busy: 'Processing', done: 'Done', retry: 'Retry' } | The button’s words while it works, at the end and after a decline; the one at rest, Pay $1,249.00, is changed in index.html. |
WORDS | script.js | { busy: 'Processing payment', done: 'Payment complete', declined: 'Card declined' } | The title while it works, at the end and after a decline; the one at rest, Ready to pay, is changed in index.html. |
NOTES | script.js | ['Authorizing your card', 'Verifying with your bank', …] | The line under the title during the three steps, at the end and after a decline; the one at rest and the steps’ names are changed in index.html. |
For a wait of a few seconds where trust matters: a card payment, an instant transfer, an account being verified, a subscription being switched on. The cradle says something is working precisely and without hurry, and the growing number of balls says which step it is at even without reading. It suits a shop for design objects, a finance or office app, where the steel and the walnut go well with the product. For a very short wait, or a loader that comes back often, it is too much.
The component is at most 380 pixels wide: at 390 it fits in 358, the canvas shrinks with it and paints at the screen’s real density, up to twice, and the balls have the same physics at any size (everything is in drawing units). The words stay on one line. The button is 48 tall and under a finger it squashes and springs back; the ball moving aside on the way past is there only with the mouse and the keyboard. The balls can be pulled with a finger too, sideways: the canvas lets the page’s vertical scroll through.
The balls stay still in the row: no swinging, no ball moving aside, no pulling, no light at the end and no shake of the title. The payment is read in the words, the percentage and the steps’ tracks, which fill; the words change with a fade, the tracks turn green with no delay and the tick appears without drawing itself.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 14 KB; the libraries: GSAP 28 KB.
Tested on 8 October 2026
Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.