
The send button
Buttons, Transitions, SVG
NewFree
A card payment in an online shop, with its progress engraved like the security pattern of a banknote: the fine interlaced lines a guilloché engine cuts. A pale ghost of the whole pattern waits on the plate; each step of the payment is one turn of the graver, a hairline that sweeps round from the top and leaves the lines inked behind it: the woven band outside while the card is authorized, the rosette while the bank checks it, the star in the middle while the payment is confirmed. The freshest stretch is darker, like wet ink. If the bank does not answer the graver stops, shakes and the last cut turns red until Retry carries on; once paid, a sheen crosses the plate like light on foil, and Cancel or Done wind the engraving back.
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 guilloché payment</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/schibsted-grotesk@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the guilloché payment: a card payment whose progress is engraved like the security pattern of a banknote. Each
step of the payment is one turn of the graver: the woven band outside while the card is authorized, the
rosette while the bank checks it, the star in the middle while the payment is confirmed. The pattern is
drawn by script.js -->
<section class="gp" aria-labelledby="gp-title" data-pay>
<div class="gp__head">
<div class="gp__words">
<h2 class="gp__title" id="gp-title"><span class="gp__swap" data-title>Studio Ferro</span></h2>
<p class="gp__meta"><span class="gp__swap" data-meta>Visa ending 4242</span></p>
</div>
<p class="gp__amount" data-amount>€186.00</p>
</div>
<div class="gp__plate" role="progressbar" aria-labelledby="gp-title" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-valuetext="Not started" data-bar>
<canvas class="gp__canvas" aria-hidden="true" data-plate></canvas>
</div>
<div class="gp__foot">
<p class="gp__status">
<svg class="gp__tick" viewBox="0 0 16 16" aria-hidden="true" data-tick><path d="M3.2 8.4l3 3 6.6-7" pathLength="1"/></svg>
<span class="gp__swap" data-status>Secured by your bank</span>
</p>
<button class="pill" type="button" data-btn data-autoclic>
<span class="pill__fill" aria-hidden="true"></span>
<span class="pill__label" data-label>Pay €186.00</span>
</button>
</div>
<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.
37 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 guilloché payment” from Animorio and fit it into my siteEvery line is a polar curve r(θ) sampled at 720 points, and every layer is a family of identical lines shifted in phase: the band is r = 102 + d·sin(20θ + 2πk/12), twelve wavy rings that, out of phase, cross into a braid; the rosette is a nine-petalled rose, 36 + D·w·(0.8 + 0.2·cos 18θ), with w = ½ + ½·sin(9θ + 2πk/20); the star is 7 + D·w² with six points. It is what the guilloché engine did on watch cases and banknotes.
The whole pattern is drawn once, in the palest grey, on a separate canvas: it is the ghost waiting on the plate, copied under everything else every frame. The progress from 0 to 1 becomes three turns, one per layer, and every layer draws its lines from point 0 to point q·720, the last piece interpolated, so the graver turns smoothly. The graver itself is a radial hairline from the inner to the outer edge of the layer.
The last FRESH degrees of every line behind the graver are gone over again in the graver’s colour at half opacity: the freshest engraving is darker and lightens into the layer’s colour as the graver moves on. When the bank does not answer that stretch turns red and the graver shakes for a few twentieths of a second with a GSAP yoyo.
Once paid, a pale linear gradient crosses the plate on the diagonal, drawn source-atop so it only falls on the engraved lines and the ghost, like light on holographic foil, while the tick draws itself with stroke-dashoffset and makes room beside Paid by widening from nothing.
Cancel during the payment and Done at the end bring the progress back to nought with a GSAP tween, longer when more has been engraved: the three layers wind back in reverse order, from the star to the band. The loop only draws when something changes and leaves the ticker when the plate is still.
| Name | File | Default | What it changes |
|---|---|---|---|
AMOUNT | script.js | '€186.00' | What is being paid (at the top, in the pill and at the end). |
SECONDS | script.js | 6 | How many seconds the payment takes in the demo. |
BAND | script.js | { lines: 12, waves: 20, depth: 10 } | The woven band: how many rings, how many waves round, how deep. |
ROSETTE | script.js | { lines: 20, petals: 9, depth: 44 } | The rosette: how many lines, how many petals, how deep. |
STAR | script.js | { lines: 12, points: 6, depth: 26 } | The star in the middle: how many lines, how many points, how long. |
LINE | script.js | 0.7 | The width of an engraved line, in pixels. |
FRESH | script.js | 22 | How many degrees behind the graver the ink is still wet. |
FAIL_EVERY | script.js | 2 | One payment in how many waits for a bank that does not answer (0 never). |
FAIL | script.js | 0.55 | Where the bank stops answering, from 0 to 1. |
PREVIEW | script.js | 1.35 | In the preview’s round: how many times faster. |
LABELS | script.js | ['Pay', 'Cancel', 'Retry', 'Done'] | The words of the pill, state by state (Pay is followed by the amount). |
--band | style.css | #0b6e57 | The colour of the woven band. |
--rosette | style.css | #c0612b | The colour of the rosette. |
--star | style.css | #1b2440 | The colour of the star in the middle. |
For a card payment in an online shop, for confirming a booking with a deposit, for a transfer or a payment in a banking app, for buying a gift card, for any wait where it matters that things feel safe and precious.
The panel takes the whole width less the margins and the plate shrinks with it, because the pattern is drawn in units of its box; the lines stay fine. The pill answers a touch as it does the mouse.
The engraving moves on all the same, because it is the progress, but the graver does not shake, the final sheen does not pass, the amount does not jump and the words change without moving; the ghost is simply there, without rising.
GSAP 3.15.0, Fraunces (font variabile, assi opsz, SOFT, WONK e wght) 5.3.0, Schibsted Grotesk (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 8.4 KB; the libraries: GSAP 28 KB.
Tested on 19 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.