
The elastic button
Buttons, Hover, Text
NewFree
The top navigation bar of a maker of measuring instruments, in the minimal style: under the links runs a graduated scale of fine ticks with a vermilion index on a spring. The index slides to the link under the pointer and back to the page you are on, and every word takes weight and width from how close the index is, so as it runs the black flows from one word to the next. The ticks near the index grow taller, lean with its speed and, when it settles on a new page, a wave runs along them.
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 graduated scale nav</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the top bar of a maker of surveying instruments, Alidade. Under the links runs a fine graduated scale with a
vermilion index on a spring: the index slides to the link under the pointer and back to the current page, and
every word takes weight and width by how close the index is. The ticks near the index grow, lean with its
speed and ring once when it settles on a new page -->
<header class="bar" data-bar data-autoclic>
<span class="bar__rule" aria-hidden="true" data-rule></span>
<a class="brand" href="#" aria-label="Alidade, home" data-brand>Alidade</a>
<nav class="nav" aria-label="Main" data-nav>
<ul class="list">
<li class="item"><a class="link" href="#tools" data-link aria-current="page"><span class="link__word" data-word>Tools</span></a></li>
<li class="item"><a class="link" href="#field" data-link><span class="link__word" data-word>Field</span></a></li>
<li class="item"><a class="link" href="#notes" data-link><span class="link__word" data-word>Notes</span></a></li>
<li class="item"><a class="link" href="#studio" data-link><span class="link__word" data-word>Studio</span></a></li>
</ul>
<canvas class="scale" aria-hidden="true" data-scale></canvas>
</nav>
</header>
</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.
22 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 graduated scale nav” from Animorio and fit it into my siteAt start and whenever the sizes change every word is set for a moment to the largest width and weight (WIDTH_MAX, WEIGHT_MAX) and its box takes that width in pixels. So when the words change axes as things move, none pushes the others: the centres of the links stay still and the index always has the same target.
The position of the index follows the target on a damped spring (SPRING, DAMPING), stepped at most 1/120 of a second at a time and never more than 1/30 per frame. The target is the link with keyboard focus, if any, then the one under the mouse, then the current page. The length of the index has its own spring too: pressing it drops to half, letting go it comes back with a small bounce.
Every frame each word takes a closeness p = exp(-(d/s)²), where d is the distance between the index and its centre and s is REACH times the distance between two links. With p the weight (font-variation-settings 'wght'), the width ('wdth') and the colour between grey and black are mixed: there is no lit link and dim others, but a wave of black that runs with the index.
The ticks are one-pixel lines in a canvas at the screen's density. Each takes extra height (MAGNIFY) on a bell around the index, and its tip moves sideways in proportion to the index's speed (LEAN), so the ticks bend like grass. Behind the running index a faint copy stays, shifted by its speed over a thirtieth of a second.
Choosing a new page arms the wave: as soon as the index is still on its target an oscillation sin(r/7 - 16t) starts, damped over time and distance, spreading at 260 pixels a second and added to the height of the ticks (RING). When nothing moves and there is no wave, the frame loop stops.
On a phone a tap chooses the link; dragging along the bar the index follows the finger, held between the first and the last link, and letting go it goes to the nearest link. The bar still lets the page scroll vertically (touch-action: pan-y), so you can scroll down over it.
| Name | File | Default | What it changes |
|---|---|---|---|
SPRING | script.js | 180 | How stiff the index spring is: higher, the quicker it gets there. |
DAMPING | script.js | 16 | How much the index is held back: lower, the more it swings before it settles. |
REACH | script.js | 0.55 | How far the weight spreads around the index, in links: small, only the link under the index is black; large, the neighbours light up too. |
WEIGHT_MIN | script.js | 330 | The weight of the links far from the index (100 to 900). |
WEIGHT_MAX | script.js | 760 | The weight of the link under the index (100 to 900). |
WIDTH_MIN | script.js | 78 | The width of the links far from the index, on the width axis (50 to 150). |
WIDTH_MAX | script.js | 112 | The width of the link under the index, on the width axis (50 to 150). |
TICK_GAP | script.js | 6 | The distance between two ticks of the scale, in pixels. |
MAGNIFY | script.js | 7 | How many pixels taller the ticks near the index get. |
LEAN | script.js | 5 | How much the ticks lean with the speed of the index, in pixels. |
RING | script.js | 2.6 | How strong the wave running along the ticks is when the index settles on a new page (0, no wave). |
For the header of anyone who measures, draws or builds with precision: measuring instruments, an architecture or engineering studio, a lab, a project app, a type foundry. It suits three, four or five short links on a light, empty bar. Colours, weights and the density of the scale change in the variables.
At 390 pixels the bar is almost as wide as the screen and the four links all fit, smaller, next to the name. A tap chooses the link and the index runs there with the same spring and the same wave; dragging a finger along the bar the index follows it and the words light up one after another, and letting go it settles on the nearest link. Vertically the page scrolls as usual.
No springs, no leaning ticks and no wave: the index is already on the link, the words already have their weight and changing link everything is set again in place at once. When the page opens the bar fades in.
GSAP 3.15.0, Anybody (font variabile, con gli assi della larghezza e del peso) 5.3.0.
Compressed with gzip, the three demo files weigh 5.8 KB; the libraries: GSAP 28 KB.
Tested on 23 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.