
The time wheel
Pickers, 3D, Physics
NewFree
The bottom bar of a board game nights app, in green felt: the chosen tab sits under an ivory game piece with its icon carved in the top. Choosing another, the piece is tossed there, flips over in the air showing the new icon carved on its other face, lands on its rim and rattles like a coin spinning down on a table, faster and faster, until it lies flat.
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 game piece tab bar</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 tab bar of a board game nights app, in green felt. The tab you are on sits under an ivory game piece with
its icon carved in the top. Choosing another tab, the piece is tossed there: it flips over in the air and
shows the new icon, carved on its other face, lands on its rim and rattles down flat like a coin spun on a
table. The piece is built by the script from the icons below, in layers, and moved in 3D -->
<nav class="bar" aria-label="Main" data-bar>
<button class="tab" type="button" data-tab data-autoclic>
<span class="tab__print" data-print><svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true" data-icon>
<path d="M12 3.6c1.55 0 2.75 1.2 2.75 2.7 0 .85-.4 1.6-1 2.05l4.45 1.6c1.05.4 1.55 1.3 1.25 2.15-.3.8-1.1 1.1-2 .9l-2.1-.4 2.5 5.95c.35.9-.25 1.8-1.25 1.8h-2l-2.6-3.85-2.6 3.85h-2c-1 0-1.6-.9-1.25-1.8l2.5-5.95-2.1.4c-.9.2-1.7-.1-2-.9-.3-.85.2-1.75 1.25-2.15l4.45-1.6c-.6-.45-1-1.2-1-2.05 0-1.5 1.2-2.7 2.75-2.7z"/>
</svg></span>
<span class="tab__label">Games</span>
</button>
<button class="tab" type="button" data-tab>
<span class="tab__print" data-print><svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true" data-icon>
<path d="M18.9 14.3a7.6 7.6 0 1 1-9.3-9.3a6.2 6.2 0 0 0 9.3 9.3z"/>
<path d="M17.3 3.4l.6 1.5 1.5.6-1.5.6-.6 1.5-.6-1.5-1.5-.6 1.5-.6z"/>
</svg></span>
<span class="tab__label">Nights</span>
</button>
<button class="tab" type="button" data-tab>
<span class="tab__print" data-print><svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true" data-icon>
<path d="M3.6 20.2h16.8M9.2 20.2V11.2h5.6v9M3.6 20.2v-5.4h5.6M20.4 20.2v-4h-5.6"/>
<path d="M12 3.7l.75 1.7 1.85.2-1.4 1.25.4 1.85L12 7.75l-1.6.95.4-1.85-1.4-1.25 1.85-.2z"/>
</svg></span>
<span class="tab__label">Scores</span>
</button>
<button class="tab" type="button" data-tab data-autoclic>
<span class="tab__print" data-print><svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true" data-icon>
<rect x="4.2" y="15.4" width="15.6" height="4.8" rx="1.2"/>
<rect x="6.4" y="10.6" width="13" height="4.8" rx="1.2"/>
<rect x="4.8" y="5.8" width="11.6" height="4.8" rx="1.2"/>
</svg></span>
<span class="tab__label">Shelf</span>
</button>
<button class="tab" type="button" data-tab data-autoclic>
<span class="tab__print" data-print><svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true" data-icon>
<path d="M12 4.2a3.6 3.6 0 1 0 0 7.2a3.6 3.6 0 1 0 0-7.2zM5 19.8c.8-3.6 3.6-5.6 7-5.6s6.2 2 7 5.6"/>
</svg></span>
<span class="tab__label">Profile</span>
</button>
<!-- the piece's shadow on the felt (clipped to the bar) and the piece itself: both drawn over the tabs, neither
takes the taps -->
<span class="bar__shade" aria-hidden="true"><span class="bar__shadow" data-shadow></span></span>
<span class="piece" aria-hidden="true" data-piece><span class="piece__body" data-body></span></span>
</nav>
</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.
21 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 game piece tab bar” from Animorio and fit it into my siteThe piece is a CSS 3D element: eight discs stacked a pixel apart, in two alternating tones, make the ridged side, and on top and underneath there are two faces with backface-visibility hidden, each with an SVG: the round groove and the icon drawn twice, a light lip underneath and the dark cut on top. Edge on the discs would leave gaps: a band at right angles to the faces makes the side solid, and only shows then. The icons on the faces are copied from the bar's own.
Each toss is a hand-written ballistic flight: along the bar the piece goes straight at a steady speed, its height is a parabola (starting from where it is now, if it is already in the air) and its turn about the upright axis is even. The half turns are odd, so the other face comes up, and that face, while it faces down, is given the new icon; FLIPS adds whole turns for far tabs. The height shows as size and as a rise on the screen, and the shadow on the felt slides sideways, grows and softens.
The turn stops TILT degrees short of flat, and at that moment the same rotation is written again as a tilt about an axis in the plane (rotateZ, rotateX, rotateZ back): no jump. From there the tilt shrinks as the square root of the time left, and its direction turns at a speed inversely proportional to the tilt, as in Euler's disk: slow at first, a quick shiver at the end, then a knock. The same tilt, towards a tab, is the gesture when the mouse goes over it.
On every frame, with the same rotations CSS uses, the normal of the face looking up and its two axes on the screen are worked out. The normal gives how much the face brightens or darkens under the light, which comes from the top left, and where the gloss slides; its axes give which side of the carving the light lip is on. The shadow narrows when the piece is edge on and stretches out on the raised side when it leans.
The tabs are buttons in a nav and the chosen one has aria-current="page"; the arrows, Home and End choose and move the focus, which only shows from the keyboard. The loop on GSAP's ticker writes nothing while the piece is still. The library's preview clicks Games, Shelf and Profile in turn: they have data-autoclic.
| Name | File | Default | What it changes |
|---|---|---|---|
START | script.js | 2 | The tab chosen when the page opens (0 is the first, 2 the middle one). |
TOSS | script.js | 0.44 | The seconds a toss to the next tab takes (a far one takes a little more). |
HEIGHT | script.js | 24 | How high the piece flies to the next tab, in pixels (a little higher to a far one). |
FLIPS | script.js | 1 | The extra turns of a far toss (0: every toss a single half turn). |
RATTLE | script.js | 1.15 | The seconds the piece rattles on its rim before it lies flat (0: it lands flat). |
TILT | script.js | 24 | How far it leans as it lands on its rim, in degrees. |
LEAN | script.js | 12 | How far it leans towards a tab under the pointer or the finger, in degrees. |
For the bottom bar of an app made for phones, with four or five sections, when the navigation can have some character: board games, a club, a card or quiz app, an app for children. The piece says where you are even standing still, and the toss shows where you come from and where you go.
The bar is at most 420 pixels wide and on a phone narrows to the screen with a 16 pixel margin each side (358 on a 390 phone); it stays 70 tall and each tab is a target of about 69 by 70 pixels. A finger down on a tab makes the piece lean and sink like the mouse over it, and the tap tosses it. Vertically the page still scrolls (touch-action: pan-y).
The piece does not fly, flip or rattle: it fades off the old tab and back in, flat, on the new one, and the name lights up with a fade. On arrival the bar only fades in, with the piece already in place; no leaning towards the mouse, no press.
GSAP 3.15.0, Gabarito (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 11 KB; the libraries: GSAP 28 KB.
Tested on 6 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.