
The merging filters
Tags, Physics, Transitions, Hover
NewFree
The menu of a paint and fabric shop as a fan deck of colour cards: card strips held at the bottom by a brass rivet. Pressing the cover, the strips fan out round the rivet, each on its own spring and a moment after the other; every strip is a section, with its colours and their names. Hovered, a strip rises out of the fan; the fan also opens and closes by hand and, thrown, carries on by itself; the chosen strip slides out and the others close behind it.
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 swatch fan menu</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/standard-italic.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the swatch fan menu: a deck of paint card strips held by a brass rivet. Pressed, the strips fan out round the
rivet, each on its own spring; each strip is a section of the site, with its colours and their names. The fan
can be opened and closed by hand, and a chosen strip slides out while the others close behind it -->
<div class="swatch" data-swatch>
<div class="fan" data-fan>
<nav class="fan__deck" id="swatch-menu" aria-label="Main" data-deck inert>
<ul class="fan__list">
<li>
<a class="strip" href="#paints" style="--c: #b8432f" data-strip>
<span class="strip__chips" aria-hidden="true">
<span class="chip chip--deep"><span class="chip__name">Madder Red</span></span>
<span class="chip chip--mid"><span class="chip__name">Clay Pot</span></span>
<span class="chip chip--pale"><span class="chip__name">Blush Plaster</span></span>
</span>
<span class="strip__label">Paints</span>
</a>
</li>
<li>
<a class="strip" href="#wallpaper" style="--c: #4c6b43" data-strip>
<span class="strip__chips" aria-hidden="true">
<span class="chip chip--deep"><span class="chip__name">Fern Hollow</span></span>
<span class="chip chip--mid"><span class="chip__name">Sage Leaf</span></span>
<span class="chip chip--pale"><span class="chip__name">Pale Lichen</span></span>
</span>
<span class="strip__label">Wallpaper</span>
</a>
</li>
<li>
<a class="strip" href="#fabrics" style="--c: #2d4878" data-strip>
<span class="strip__chips" aria-hidden="true">
<span class="chip chip--deep"><span class="chip__name">Indigo Dye</span></span>
<span class="chip chip--mid"><span class="chip__name">Chambray</span></span>
<span class="chip chip--pale"><span class="chip__name">Mist Linen</span></span>
</span>
<span class="strip__label">Fabrics</span>
</a>
</li>
<li>
<a class="strip" href="#inspiration" style="--c: #c07f17" data-strip>
<span class="strip__chips" aria-hidden="true">
<span class="chip chip--deep"><span class="chip__name">Saffron Thread</span></span>
<span class="chip chip--mid"><span class="chip__name">Honeycomb</span></span>
<span class="chip chip--pale"><span class="chip__name">Oat Milk</span></span>
</span>
<span class="strip__label">Inspiration</span>
</a>
</li>
<li>
<a class="strip" href="#visit" style="--c: #6a3456" data-strip>
<span class="strip__chips" aria-hidden="true">
<span class="chip chip--deep"><span class="chip__name">Plum Velvet</span></span>
<span class="chip chip--mid"><span class="chip__name">Heather</span></span>
<span class="chip chip--pale"><span class="chip__name">Rose Quartz</span></span>
</span>
<span class="strip__label">Visit us</span>
</a>
</li>
</ul>
</nav>
<!-- the cover of the deck is the menu button -->
<button class="strip strip--cover" type="button" aria-expanded="false" aria-controls="swatch-menu" data-cover data-autoclic>
<span class="cover__word" data-word>Menu</span>
<span class="cover__now" data-now>Paints</span>
<span class="cover__bars" aria-hidden="true" data-bars></span>
<span class="cover__spine" aria-hidden="true">Colour library</span>
<span class="sr" data-name>Open the menu</span>
</button>
<span class="fan__rivet" aria-hidden="true" data-rivet></span>
</div>
<p class="sr" 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.
44 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 swatch fan menu” from Animorio and fit it into my siteEach strip is an element standing on the rivet, with its transform-origin on the hole: every frame the script gives it rotate() for its angle and translateY() for how far it slides out along itself. The rivet and all the strips slide left together as the fan opens, by half the sum of its two ends (worked out from the sine and cosine of the angles), so the open fan sits in the middle like the closed deck.
Each strip has an angle, a speed and an angle it heads for; a damped spring (SPRING: strength and damping) takes it there in three small steps per frame, with the step capped at 1/30 of a second. Opening, the target angles set off one after another, STAGGER seconds apart from the back strip; closing, from the cover. The slide along the strip (on hover, for the choice, to stick out) has its own spring too.
With the deck in hand, the hand's angle round the rivet (atan2 of its position from the rivet's centre) moves the cover exactly, and how open the fan is comes from it; the other strips get their angle at that opening and chase it on their springs, lagging behind. Past either end the fan resists like a stiff hinge. Let go, the speed of the last hundred milliseconds decides where it ends up (THROW) and passes to every strip, which carries it on.
In the open fan each strip lies on the one to its left, and the cover leads on the right over all of them: so the left edge of every strip always shows, and that is where the section's name is, written vertically (writing-mode and a 180 degree turn) from the rivet outwards. The colours are inline variables on the strips; the lighter mixes are color-mix towards the card.
The chosen strip rises above its neighbours and slides out along itself; the others close behind it, the cover comes back in front, then the strip straightens up onto the closed deck's angle and comes down until it sticks out by PEEK, with the colour's name at the top in full view. It takes aria-current, the cover shows its name and an aria-live area reads it out.
The card has a grain made by an feTurbulence in an inline SVG, multiplied over paper and colours, and a shadow that lengthens when the strip is lifted. The cover is a button with aria-expanded; the strips are links in a nav, inert while the deck is closed. The arrows, Home and End move the focus through the strips, Enter chooses, Escape closes and brings the focus back to the cover.
| Name | File | Default | What it changes |
|---|---|---|---|
SPREAD | script.js | 100 | The angle the fan opens to, in degrees, from the first strip to the cover. |
SPRING | script.js | [210, 0.52] | The strips' springs: how hard they pull to their angle, and how damped (1 = no bounce). |
STAGGER | script.js | 0.045 | The seconds between one strip setting off and the next. |
LIFT | script.js | 16 | How far a strip rises out of the fan under the pointer, in units of the drawing. |
PEEK | script.js | 46 | How far the chosen strip sticks out of the closed deck. |
THROW | script.js | 0.2 | How far ahead a throw of the hand is followed, in seconds of its speed. |
For the menu of a site that lives on colour: a paint, wallpaper or fabric shop, an interior design studio, a cosmetics brand, a design portfolio. From four to seven short sections, each with its own colour; with more the strips cover each other too much and the names no longer read.
The whole drawing scales to the width of the screen (at 390 pixels a strip is about 250 long) and the open fan fits without spilling over. The finger opens and closes the fan as the hand does with the mouse, and the deck keeps touch-action: none so the finger does not scroll the page; a tap on a strip chooses it.
The strips do not turn or bounce: the fan is open or closed at once, the chosen strip is already in its place sticking out, and on hover the strip is lifted without travel. The hand still opens and closes it, but with no springs or inertia.
GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0, Fraunces (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 8.3 KB; the libraries: GSAP 28 KB.
Tested on 5 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.