
The send button
Buttons, Transitions, SVG
NewFree
A cinema hall: the seat chosen jumps and its ticket, with the seat’s name, flies down to the summary along a curve while the total counts; a seat let go calls its ticket back, and the others close up, staying in the order of the seats.
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 seat picker</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/spline-sans@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the seat picker: a seat chosen jumps and its ticket flies down into the summary, the total counts, and a seat
let go calls its ticket back -->
<section class="hall" aria-labelledby="hall-title" data-hall data-autoclic>
<header class="hall__head">
<h2 class="hall__title" id="hall-title">Choose your seats</h2>
<p class="hall__when">Saltwater Hours · Sat 9:15 pm · Hall 2</p>
</header>
<div class="hall__screen" aria-hidden="true">
<svg viewBox="0 0 300 24" preserveAspectRatio="none"><path d="M6 20 Q150 -6 294 20"/></svg>
<span>Screen</span>
</div>
<div class="hall__seats" role="group" aria-label="Seats" data-seats></div>
<p class="hall__tip" aria-hidden="true" data-tip></p>
<div class="hall__key" aria-hidden="true">
<span><i class="seat seat--key"></i>Free</span>
<span><i class="seat seat--key is-taken"></i>Taken</span>
<span><i class="seat seat--key is-on"></i>Yours</span>
</div>
<div class="sum">
<div class="sum__left">
<p class="sum__label" id="sum-label">Your seats</p>
<ul class="sum__chips" aria-labelledby="sum-label" data-chips></ul>
<p class="sum__none" data-none>None yet</p>
</div>
<div class="sum__right">
<p class="sum__total" aria-live="polite"><span class="sr">Total </span><span data-total>€0</span></p>
<button class="sum__go" type="button" disabled data-go>Continue</button>
</div>
</div>
<p class="sr" 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.
38 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 seat picker” from Animorio and fit it into my siteThe seats are made by the script: ROWS rows of PER_ROW buttons, split in half by an aisle (a grid whose columns come from two CSS variables); the seats in TAKEN are taken, and the prices are PRICES[0] in the first three rows and PRICES[1] in the others. Each seat says its row, number and price (aria-label) and whether it is chosen (aria-pressed).
The new ticket goes straight into the summary, hidden, in its place in the order of the seats; a copy sets off from the seat and heads for it, measured on every frame (the other tickets may move meanwhile): x with power2.inOut and y with another ease draw a curve, and the copy goes from the seat’s size to the ticket’s in FLIGHT seconds. On arrival the real ticket shows with a small bounce.
Letting a seat go, its ticket flies back from the summary to the seat, which takes it dipping to 0.82 and coming back with back.out; before and after every change the other tickets’ places are measured, and they slide to their new places (FLIP).
The total goes to the new value in 0.5 seconds; Continue lights up with the first seat. Past MAX seats the seat shakes (keyframes on x), and the label and an aria-live region say the limit.
The seats are a single Tab stop: the arrows move between rows and seats, Enter or space choose, and the label follows the focus. A click from a script (the library’s preview) is a pretend hand: it points at a seat, takes it or lets it go, one at a time, and ends with the hall as it was.
| Name | File | Default | What it changes |
|---|---|---|---|
ROWS | script.js | 'ABCDEFG' | The rows, from the screen to the back. |
PER_ROW | script.js | 10 | The seats in a row, split by the aisle in the middle. |
TAKEN | script.js | ['A3', 'A4', 'B6', …] | The seats already taken. |
MAX | script.js | 6 | How many seats can be chosen. |
PRICES | script.js | [8, 10] | The price of a seat in the first three rows, and in the others, in euros. |
FLIGHT | script.js | 0.55 | The seconds a ticket takes to fly between its seat and the summary. |
For choosing seats at a cinema, a theatre, a concert, on a train or a plane, the tables of a restaurant outside, the desks of an office.
The seats close up (22 pixels high and smaller gaps) so the ten of a row fit the width; on a tap the label does not show, as the finger would cover it: a chosen seat carries its name inside itself.
The seat chosen does not jump, the ticket appears in the summary without flying (and disappears without going back), the total changes at once, the seat too many does not shake and the screen does not draw itself.
GSAP 3.15.0, Spline Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 6.5 KB; the libraries: GSAP 28 KB.
Tested on 3 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.