Skip to content
animorio
IT
All components

The graduated scale nav

Navigation, Hover, TextCanvas, GSAPMediumCompressed weight: Demo 5.8 KBGSAP 28 KBFreeDownload the zip

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.

The code

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>

Playground

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

Or ask Claude Code for it

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 site

What it does

On a white background a bar 60 pixels tall and 720 wide, closed below by a thin black rule. On the left the name Alidade, black and narrow; on the right four links in Anybody, Tools, Field, Notes and Studio, and under them, standing on the rule, a scale of close ticks, one every 6 pixels, longer every fifth. On arrival the rule is drawn from the left, the ticks come up one after the other and a vermilion index, a wire with a small tip, rises under Tools, the page you are on. The links are not black or grey: each takes weight, width and ink from how close the index is. With the mouse on another link the index runs there, goes a touch too far and comes back, and meanwhile the black flows from one word to the next; the ticks near the index grow as if under a lens, lean the way it runs and a faint ghost stays behind it for a moment. Leaving the bar it goes back to the page you are on. Pressing a link the index drops to half; letting go it stretches again with a small bounce, goes to the chosen link and when it settles a wave runs along the ticks left and right and dies away. From the keyboard the focused link has a thin frame and the index follows it; the arrow keys move from link to link, Enter chooses it.

How it works

Boxes that never move

At 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 index on a spring

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.

The weight that follows the index

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 scale drawn in a canvas

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.

The wave when it settles

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.

The finger

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.

Values to change

NameFileDefaultWhat it changes
SPRINGscript.js180How stiff the index spring is: higher, the quicker it gets there.
DAMPINGscript.js16How much the index is held back: lower, the more it swings before it settles.
REACHscript.js0.55How 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_MINscript.js330The weight of the links far from the index (100 to 900).
WEIGHT_MAXscript.js760The weight of the link under the index (100 to 900).
WIDTH_MINscript.js78The width of the links far from the index, on the width axis (50 to 150).
WIDTH_MAXscript.js112The width of the link under the index, on the width axis (50 to 150).
TICK_GAPscript.js6The distance between two ticks of the scale, in pixels.
MAGNIFYscript.js7How many pixels taller the ticks near the index get.
LEANscript.js5How much the ticks lean with the speed of the index, in pixels.
RINGscript.js2.6How strong the wave running along the ticks is when the index settles on a new page (0, no wave).

Try them in the Playground

When to use it

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.

On phones

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.

With reduced motion

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.

Pitfalls

  • If the word taking weight widened in its row, it would push the others and the centre of the link would move while the index went there: an endless chase. That is why every link sits in a box as wide as its fullest word, measured once.
  • Keyboard focus and click both arrive when clicking with the mouse: the focus took the index to the link before the click and then stayed there. Now the index follows the focus only when it is visible (:focus-visible), that is from the keyboard.
  • With a finger, lifting it after a drag also produced a click on the link under it: only the drag's choice counts.

Libraries

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.

Testing

Tested on 23 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

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.

All components