
The menu that opens from its button
Menus, Transitions, Text
Free
In a minimal style: the filters of a recipe book set as light words on thin ruled lines. Choose one and the word rises along a curve into the top line, above a black rule, takes weight and a small vermilion cross draws itself after it; the others close the gap one after the other, and the ones that change line run out at one end of theirs and come back in at the other end of the next, like type reflowing. Underneath, the number of recipes left changes digit by digit.
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 filters that rise into line</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the filters of a recipe book, set as words on ruled lines. Choosing one, it rises into the top line, takes
weight and gets a small cross to take it away; the words after it close the gap, and the ones that change
line run out at one end of their line and come in at the other end of the next, like type reflowing. The
buttons are real and stay in the layout; the words you see are drawn over them by the script, so they can
travel. The filters are made by the script from its list -->
<div class="pantry" data-pantry data-autoclic>
<div class="sheet" data-sheet>
<div class="rules" aria-hidden="true" data-rules></div>
<span class="rule-ink" aria-hidden="true" data-rule-ink></span>
<p class="hint" aria-hidden="true" data-hint>Pick what you fancy</p>
<div class="picked" role="group" aria-label="Chosen filters" data-picked></div>
<div class="rest" role="group" aria-label="Filter the recipes" data-rest></div>
<div class="ink" aria-hidden="true" data-ink></div>
</div>
<div class="foot">
<button class="clear" type="button" aria-disabled="true" data-clear>Clear</button>
<p class="count" aria-hidden="true"><span class="count__n" data-count></span> <span class="count__noun" data-noun>recipes</span></p>
<p class="sr" aria-live="polite" data-live></p>
</div>
</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.
32 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 filters that rise into line” from Animorio and fit it into my siteEvery filter is a button with aria-pressed, in two role="group" elements: the chosen ones on top, in the order they were chosen, and the others in the order of the list. Choosing, the button really moves from one group to the other (and gets its focus back), with the style of its place: so the layout, with flex-wrap, says where every word belongs. The buttons have transparent text; what you see is a copy of every word in a layer above, moved by the script, with the keyboard's ring travelling along with it.
At every change the script measures where the buttons ended up (getBoundingClientRect, once) and every drawn word reaches its place on a damped spring (SPRING), integrated on the GSAP ticker in steps of a quarter of a frame, with the step capped at 1/30 of a second. Weight and width follow a second, softer spring, from WEIGHT[0] to WEIGHT[1] and from WIDTH[0] to WIDTH[1], which goes a little past and settles; speed takes width away (SQUEEZE). A change halfway is just a new place to reach. When nothing moves the ticker stops.
A word that changes group flies on a cubic Bézier curve: its two control points stand above the start and above the end, at the height of the black rule. So it leaves straight up (or down), runs along the rule with its text resting on it, without passing over the words of the top line, and arrives straight into its place. How far along the curve it is comes from a spring (FLIGHT); past the end the curve carries on along its tangent, so the overshoot is a pixel, upright.
A word that stays in its group but changes line never crosses the others: its copy runs out at the end of the line it was on (a cloned ghost, removed afterwards) and the word comes in at the other end of its new line. A gradient mask, worked out in pixels in the word's own coordinates, fades it over the 16 pixels past the end of the rule. The line is counted from the start of its group, so when the line of the chosen ones opens another, the words below move down all together, with the black rule, instead of reflowing.
The delay of every word (RIPPLE) depends on its direction: words closing a gap go from the gap forwards, after a tenth of a second that lets the chosen word get away; words making room go from the far end backwards. So no word ever catches up with the one in front. With Clear the chosen words go back one after the other, the last one first. The count sits in windows one tabular figure wide: the old digit and the new one slide together on the same spring, the new one in vermilion fading to black; a digit no longer needed closes its window.
Tab, Enter and Space work as always, and an aria-live region says what changed and how many recipes are left. With reduced motion the words that change place fade out and back in already in place, the digits with a fade. A click from a script on the component (detail 0, the library's preview) plays a round: it chooses Vegetarian, Spicy and One pot, drops Weeknight, empties everything with Clear and puts Weeknight back, ending as it started.
| Name | File | Default | What it changes |
|---|---|---|---|
FILTERS | script.js | ['Vegan', 'Weeknight', 'Gluten-free', …] | The filters, in their order on the lines (names the example's book does not know get random recipes). |
START | script.js | ['Weeknight'] | The filters already chosen when the page opens. |
RECIPES | script.js | 186 | How many recipes the example's book has. |
NOUN | script.js | ['recipe', 'recipes'] | What is being counted, singular and plural. |
SPRING | script.js | [240, 0.8] | The springs the words travel on: how stiff, and how damped (1 lands without overshoot). |
FLIGHT | script.js | 0.4 | How quick the flight between the lines and the top line is, against the other springs. |
RIPPLE | script.js | 0.035 | The seconds between one word moving and the next. |
WEIGHT | script.js | [330, 640] | The weight of the words on the lines and of the chosen ones (200 to 800). |
WIDTH | script.js | [90, 100] | The width axis of the words on the lines and of the chosen ones (75 to 100). |
SQUEEZE | script.js | 12 | How much a running word narrows on the width axis. |
For filters that add up above a list: the recipes of a food blog, the products of a shop, the stays of a travel site, the courses of a school. Wherever the choices need to be in view all together, with the number of results left, and taking a choice away must be as easy as making it.
At 390 pixels the lines are taller (44 pixels, good for a finger) and the words go on three lines; the line of the chosen ones opens a second one when it fills up and the lines below move down together, so the component keeps its height. A tap chooses and removes, and pressing squeezes the word a hair; the pointer's hover is not there.
Nothing flies and nothing slides: the words that change place fade out and back in already in place, with the right weight and the cross already drawn; the number changes with a fade and the rules are already drawn when the page opens.
GSAP 3.15.0, Bricolage Grotesque (font variabile, con gli assi del peso, della larghezza e della grandezza ottica) 5.3.0.
Compressed with gzip, the three demo files weigh 12 KB; the libraries: GSAP 28 KB.
Tested on 16 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.