Skip to content
animorio
IT
All components

The interlocking line-up

Tags, SVG, TransitionsGSAPAdvancedCompressed weight: Demo 14 KBGSAP 28 KBFreeDownload the zip

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.

The code

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>

Playground

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

Or ask Claude Code for it

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 site

What it does

On a white background the question Who’s missing from the band?, a white field holding two jigsaw pieces locked together, Drums in coral and Lead guitar in yellow, each with its small cross, and the tab of Lead guitar sticking out towards the box Search instruments; under it, Room for two more players. Tapping the field or typing opens the list of instruments, with the part typed in bold and the band’s section on the right (Rhythm, Strings, Keys, Vocals, Horns & winds); the lit row takes the soft tint of its section. A row chosen, its highlight becomes the piece: it closes round the name, takes the full colour, the tab and the socket, is lifted with a soft shadow, goes up into the field and is lowered into its place, where the socket closes over the tab of the piece before and the corners that meet turn square as in one strip, with a little click. The box makes room and the field, if it has to, grows by a line: the strip wraps like a word broken at the end of a line, with the tab at the end of one line and the socket at the start of the next. With four pieces the last one’s tab draws back and the strip closes; the box says Line-up full, and an instrument chosen anyway flies to the end, bumps against the closed end, shakes and falls, while the line under says in red An ad can list up to four players. A piece tapped is lifted and gone, and the ones after it slide back and lock in; one that changes line is picked up and put down there. In the empty field the first backspace lifts and outlines the last piece, the second takes it away; a name already there makes its piece jiggle.

How it works

A real combobox

The 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.

The piece in one path

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.

From the row to the piece

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.

The others make room

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.

Full, keys and the preview

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.

Values to change

NameFileDefaultWhat it changes
MAXscript.js4How many players an ad can ask for.
STARTscript.js['Drums', 'Lead guitar']The players in the ad when the page opens.
INSTRUMENTSscript.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).
KNOBscript.js14How far, in pixels, a piece’s tab reaches into the next one (0: pieces without joints).
LIFTscript.js1.1How much bigger a piece gets while it is lifted.
FLIGHTscript.js0.5The seconds a piece takes from the list to its place.

Try them in the Playground

When to use it

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.

On phones

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.

With reduced motion

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.

Pitfalls

  • A piece’s tab sits inside the next piece: it shows because the next piece’s socket is a hole in its outline made with the same curve gone the other way. If the two curves do not have exactly the same points and the same size, a gap or an overlap is left between the two pieces.
  • While a piece flies the others can move (a piece taken away, the field narrower): the flight’s end is not fixed at the start but read again at every frame from the flow (offsetLeft, offsetTop), and the transform is the difference.
  • A piece changing line, slid diagonally, passed over the others’ words: now it is lifted and put down, bigger and with its shadow, so it reads as passing over. The box changing line fades in again instead, once the flying piece has passed.
  • Two tweens on the same value (the piece lifted by the first backspace and lowered again) without overwrite fight over it and the one that ends later wins: the piece stayed lifted. Now they have overwrite auto.
  • A delayedCall already finished, called with progress(1), made its call again: the preview finishes the previous step only if it is still going (isActive).
  • Choosing with the pointer the box would lose the focus before the click: the pointerdown on the list is stopped (preventDefault). A box under 16 pixels makes Safari on iPhone zoom the page.

Libraries

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.

Testing

Tested on 7 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

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.

All components