
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
The waitlist of a calendar app, with the queue drawn: 2,480 thin grey marks on a canvas, one for every person waiting. Joining, your green mark drops into the end of the line, its neighbours feel the landing one after the other and a fisheye lens opens over your place, with the number rolling digit by digit. Every friend who joins with your link moves you up ten places: the marks ahead step back and yours slides forward.
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">
<title>The waitlist with the queue</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the waitlist of a calendar app: every person waiting is a thin mark in the queue. Joining, your mark drops
in at the end and a lens opens over it; every friend who joins with your link moves you up. Joining is
pretended: see post() in the script -->
<div class="wait" data-wait data-autoclic>
<h2 class="wait__title" id="wait-title">Halden is almost here</h2>
<p class="wait__sub">A calmer calendar. The first invites go out in November.</p>
<div class="queue" data-queue>
<canvas class="queue__canvas" aria-hidden="true" data-canvas></canvas>
<span class="queue__you" aria-hidden="true" data-you><span>You</span></span>
</div>
<p class="wait__count" data-count><span data-count-text>2,480 people are waiting.</span></p>
<form class="wait__form" action="#" novalidate aria-labelledby="wait-title" data-form>
<div class="wait__row">
<div class="wait__field" data-field>
<label class="sr" for="wait-email">Your email</label>
<input class="wait__input" id="wait-email" name="email" type="text" inputmode="email" autocomplete="email" autocapitalize="off" autocorrect="off" spellcheck="false" enterkeyhint="send" maxlength="254" placeholder="you@example.com" aria-describedby="wait-status" aria-invalid="false" data-input>
<span class="wait__caret" aria-hidden="true" data-caret></span>
</div>
<button class="join" type="submit" data-join>
<span class="join__bg" aria-hidden="true"></span>
<span class="join__label" data-join-label>Join the waitlist</span>
</button>
</div>
<p class="wait__status" id="wait-status" data-status><span class="status__line">One email when your invite is ready. Nothing else.</span></p>
</form>
<p class="sr" role="status" aria-live="polite" data-live></p>
</div>
</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.
22 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 waitlist with the queue” from Animorio and fit it into my siteEvery person is an object with a place in the line (a number that can sit between two places while it moves), a jump and an alpha. The place becomes a cell of a grid of ROWS rows, left to right and top to bottom, with a margin above and below so the lens is never cut. All the marks are drawn on a canvas at the screen’s density, one fillRect per mark; the drawing runs on the GSAP ticker only for the seconds a change asks for, then stops.
Within REACH pixels of your place, a point at distance r is pushed out to (d + 1) r / (d r / REACH + 1): in the middle everything is d + 1 times larger and at the edge the lens meets the flat line with no jump. The magnification of each mark also makes it wider, longer and darker. GSAP takes d from 0 to LENS and moves the lens’s centre together with your place.
Your mark drops from 44 pixels with power2.in and, as it lands, the marks of the same row within seven places get a jump that comes back with elastic.out, staggered by distance: the nearest feel the blow first. The You label is an HTML element the drawing puts over the mark at every frame.
When a friend joins (friendJoined(), pretended in the demo after you copy the link) a new mark lights up at the end, the BOOST marks ahead of yours slide back one place, staggered, and yours slides forward BOOST places with the lens following it; the number of your place rolls only in the digits that change, each in its own fixed-width window.
The email field is real, with a label, aria-invalid and aria-describedby to the line under it, which says what is missing in plain words. Joining is pretended (post(), WAIT seconds); the messages also reach screen readers through an aria-live region. Use another email puts the line back as it was: the marks that had made room for you step forward again.
| Name | File | Default | What it changes |
|---|---|---|---|
AHEAD | script.js | 2480 | How many people are already in line. |
ROWS | script.js | 16 | How many rows the line is drawn in. |
LENS | script.js | 3.2 | How much the lens magnifies: the middle is 1 + LENS times larger. |
REACH | script.js | 64 | The radius of the lens, in pixels. |
BOOST | script.js | 10 | How many places a friend who joins moves you up. |
WAIT | script.js | 0.7 | How many seconds the pretended joining takes. |
FRIEND | script.js | 1.8 | In the demo, the seconds between copying the link and the friend joining. |
On the launch page of an app or a product that is not out yet, where the waitlist is the only thing to do: the drawn line says how many people are waiting better than a number, and the lens makes whoever joins feel like one person among the others. The invite link that moves you up is the engine of word of mouth.
The block takes the width of the screen; the line narrows (the marks get denser, the same 2,480) and the button goes under the field, as wide as it. The field opens the email keyboard and the Enter key says Send; Copy your link and Use another email are tapped as buttons.
The line appears whole, without filling in; the green mark does not drop and its neighbours do not jump: it fades in with the lens already open. Moving up, the mark and the lens are at once in their new place and the number changes without rolling.
GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 9.6 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.