
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
A site's sections engraved round the black dial of a camera: it turns under the hand, keeps going when thrown, slows down and clicks into a notch on a spring, while a lens over the ring magnifies the chosen section. The arrow keys and the mouse wheel turn it too.
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 rotary dial menu</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the menu: a dial to turn like the dial of a camera. The sections are engraved round its ring; it is thrown
with inertia, clicks into its notches on a spring, and a magnifying window shows the section at the top -->
<nav class="dial" aria-label="Sections" data-dial data-autoclic>
<span class="dial__well" aria-hidden="true"></span>
<div class="dial__body" data-body>
<svg class="dial__knurl" viewBox="-180 -180 360 360" aria-hidden="true" data-knurl></svg>
<span class="dial__rimlight" aria-hidden="true"></span>
<span class="dial__chamfer" aria-hidden="true"></span>
<span class="dial__face" aria-hidden="true"></span>
<div class="dial__turn" data-turn>
<svg class="dial__ticks" viewBox="-180 -180 360 360" aria-hidden="true" data-ticks></svg>
<ul class="dial__items">
<li><a class="dial__item" href="#develop" data-item>Develop</a></li>
<li><a class="dial__item" href="#scan" data-item>Scan</a></li>
<li><a class="dial__item" href="#print" data-item>Print</a></li>
<li><a class="dial__item" href="#film" data-item>Film</a></li>
<li><a class="dial__item" href="#repair" data-item>Repair</a></li>
<li><a class="dial__item" href="#journal" data-item>Journal</a></li>
<li><a class="dial__item" href="#studio" data-item>Studio</a></li>
<li><a class="dial__item" href="#visit" data-item>Visit</a></li>
</ul>
</div>
<!-- the silver middle, with an aperture engraved in it: it stops down while the dial spins -->
<div class="dial__hub" aria-hidden="true">
<svg class="dial__iris" viewBox="-50 -50 100 100" data-iris></svg>
</div>
</div>
<!-- the window: a lens over the ring at the top, with a magnified copy of the dial inside -->
<div class="dial__lens" aria-hidden="true" data-lens>
<div class="dial__zoom" data-zoom></div>
<span class="dial__glass"></span>
</div>
<span class="dial__pawl" aria-hidden="true" data-pawl></span>
</nav>
<p class="sr" aria-live="polite" data-live></p>
</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 rotary dial menu” from Animorio and fit it into my siteThe knurled edge is an SVG of 96 teeth, the ring has 40 ticks, and the sections are links each put at its angle with rotate(a) translateY(-130 units). Every measure is in units of a 360 wide drawing, a CSS variable, so the dial keeps its look at any size. Only the engraved parts and the edge turn: the light on the metal (conic gradients on the bevel, on the ring and on the turned disc) stays still, as on a real dial.
The dial's angle is a number moved every frame, in four small steps. Thrown, the dial feels a friction (FRICTION) and the pull of the nearest notch, -K·s·sin(θ/s) with s = step/2π: a well for every notch. While it turns fast the friction rules, when slow the notches' damping (DETENT), and so it slows down and drops into the right notch with a bounce.
Turned by hand, the dial does not follow the finger exactly: the angle shown is x − STICKY·s·sin(x/s) of the hand's angle, so near a notch it lags a little and between two notches it catches up. On release the speed is that of the last tenth of a second, and if the hand stopped before letting go there is no swing.
The window is a copy of the dial (cloned, without links or focus) inside a pill with its overflow hidden, magnified ZOOM times around the point of the index; it turns by the same angle. Over it sits the glass: a curved light at the top, darker edges and the red line of the index. In the middle the silver disc has a six-bladed aperture engraved in it, redrawn in SVG: its opening follows the dial's speed, stopped down to a third when it runs fast and wide open at rest.
The arrows, the wheel (one notch a click, or WHEEL pixels of trackpad) and a touch on a section use a spring towards a chosen notch, which adds up if pressed again before it arrives. The focus goes with the section, and when the dial stops the chosen section is read out to screen readers, once and not for every section it passes. A click from a script on the dial throws it a number of notches, found by searching for the right speed.
| Name | File | Default | What it changes |
|---|---|---|---|
FRICTION | script.js | 1.6 | How quickly a thrown dial slows down: the share of its speed it loses each second. |
DETENT | script.js | [420, 0.55] | The notches: how hard one pulls the dial in, and how damped the click is (1 = no bounce). |
STICKY | script.js | 0.5 | How much the dial holds on to a notch while the hand turns it, from 0 to 0.9. |
ZOOM | script.js | 1.8 | How much the lens over the ring magnifies. |
WHEEL | script.js | 70 | The pixels of a trackpad's scroll that turn the dial by one notch (a wheel's click is one). |
For the menu of a site that wants a physical character: a camera or watch shop, a lab, an audio gear maker, a portfolio. From five to twelve short sections; with fewer the dial looks empty, with more the words no longer fit on the ring.
Under 760 pixels the dial is 340 pixels wide, or the screen minus 48. It turns with the finger as with the mouse (touch-action: none on the dial, so the finger does not scroll the page), and a tap on a section brings it to the top. The turning parts have their own layer on the graphics card, because on a phone repainting them every frame was too much.
The dial neither glides nor bounces: it follows the hand exactly and, let go, rests at once on the nearest notch; the arrows, the wheel and taps put it in its place without travel. The aperture in the middle stays open and the red index stays still.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 9.3 KB; the libraries: GSAP 28 KB.
Tested on 4 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.