
The send button
Buttons, Transitions, SVG
NewFree
A field for choosing several instruments in a band’s ad, where every instrument chosen is a jigsaw piece: the highlight of the row becomes the piece, which is lifted, carried into the field and lowered into place, its socket closing over the tab of the piece before. Taken away, a piece comes out and the others slide back to lock in again; with the line-up full the strip closes.
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 interlocking line-up</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/gabarito@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the players a band is looking for, in its ad: every instrument chosen is a jigsaw piece. The highlight of the
row chosen in the list becomes the piece, which is lifted, carried up and lowered into the field, where its
socket closes over the tab of the piece before. The pieces are made by the script -->
<div class="band" data-band data-autoclic>
<label class="band__label" id="band-label" for="band-input">Who’s missing from the band?</label>
<div class="band__box">
<div class="band__field" data-field>
<ul class="strip" role="list" aria-label="Players the band is looking for" data-strip></ul>
<input class="band__input" id="band-input" type="text" role="combobox" aria-expanded="false" aria-controls="band-options" aria-autocomplete="list" aria-describedby="band-hint" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" enterkeyhint="done" placeholder="Search instruments" data-input>
</div>
<div class="pop" hidden data-pop>
<p class="pop__note" hidden data-note></p>
<ul class="pop__list" id="band-options" role="listbox" aria-label="Instruments" data-options></ul>
</div>
</div>
<p class="band__hint" id="band-hint" data-hint></p>
<p class="sr" aria-live="polite" data-live></p>
</div>
</main>
<!-- the soft shadow under a piece held up in the air -->
<svg class="defs" aria-hidden="true" width="0" height="0" focusable="false">
<filter id="piece-soft" x="-30%" y="-80%" width="160%" height="260%">
<feGaussianBlur stdDeviation="4"/>
</filter>
</svg>
<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.
67 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 interlocking line-up” from Animorio and fit it into my siteThe box is an input with role combobox, aria-expanded, aria-controls and aria-activedescendant on the lit row; the list is a listbox of options, moved with the arrows, Enter chooses and Esc closes. The pieces are a list of buttons with aria-label Remove and the name, and an aria-live region says what was added or taken away and how much room is left.
Every piece is an SVG path drawn again by the script: the corners, the classic tab on the right (six Bézier curves, nineteen points: the narrow neck and the round head) and on the left the socket, which is the same curve gone round the other way. Two numbers from 0 to 1, knob and sock, grow the tab and the socket from a point to their full size (KNOB pixels); the corners are square where two pieces meet on the same line and round at the two ends of the strip.
A row chosen, the row and its name are measured (with a Range): the piece is born lined up with the name and its outline starts as big as the row, then closes round the name while the colour goes from the soft tint to the full one and the tab grows. Meanwhile the piece is lifted (LIFT scale and a shadow blurred with feGaussianBlur), follows a quadratic curve to its place, read again at every frame from the flow, and is lowered: an elastic squash and the neighbour giving a little make the click.
Before every change the places of the pieces and the box are measured, after it they slide from the old place to the new one (FLIP done by hand); a piece that changes line is lifted and put down, the box changing line fades in again, and the field grows or shrinks with a tween of its height. A piece taken away leaves the flow where it is, is lifted and gone.
With MAX pieces the last one’s tab draws back and the strip closes; one instrument more makes the same flight to the end, bumps, shakes and falls, and the line under the field says so in red. Backspace in the empty field lifts and outlines the last piece, a second one takes it away; the left arrow goes onto the pieces, Delete takes them away. A click from a script (detail 0, the library’s preview) types and chooses, fills the line-up, tries a fifth instrument and takes two pieces away, without taking the focus.
| Name | File | Default | What it changes |
|---|---|---|---|
MAX | script.js | 4 | How many players an ad can ask for. |
START | script.js | ['Drums', 'Lead guitar'] | The players in the ad when the page opens. |
INSTRUMENTS | script.js | [['Drums', 'rhythm'], ['Bass guitar', 'rhythm'], …] | The instruments that can be chosen, each with its section: rhythm, strings, keys, voice or winds (it gives the piece its colour). |
KNOB | script.js | 14 | How far, in pixels, a piece’s tab reaches into the next one (0: pieces without joints). |
LIFT | script.js | 1.1 | How much bigger a piece gets while it is lifted. |
FLIGHT | script.js | 0.5 | The seconds a piece takes from the list to its place. |
For choosing several items from a list: the instruments or roles a band or a team is looking for, the skills on a profile, the ingredients to leave out in a recipe app, the languages a guide speaks, the filters of a search. The jigsaw says that the items chosen belong together.
The field takes the width of the screen and the pieces wrap, with the strip going on from one line to the next; a tap on the field opens the list. The pieces are 44 pixels tall and take a touch over 48, the rows of the list are 44 tall, the box is 16 pixels, so Safari on iPhone does not zoom the page, and autocorrect and automatic capitals are off.
The pieces appear and disappear in their place with a fade, tabs, sockets and corners take their shape at once, nothing flies, lifts or shakes and the others move without sliding; the list opens and closes with a fade. The line under the field still says what happens, and backspace outlines the last piece before taking it away.
GSAP 3.15.0, Gabarito (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 14 KB; the libraries: GSAP 28 KB.
Tested on 7 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.