Skip to content
animorio
IT
All components

The rating in words that weigh

Ratings, Text, HoverGSAPAdvancedCompressed weight: Demo 11 KBGSAP 28 KBFreeDownload the zip

In the minimal style: the rating is a single word, from Poor to Superb, over a hairline with five notches. Sliding along the line, the word takes on weight and width live, on the variable type’s axes, and the weight runs through it one letter after the other; where the grade changes, the letters the two words share slide to their new places and the others swap in a row. Once the grade is picked, the notch lights up blue and the word settles on the line.

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 rating in words that weigh</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">
    <!-- a rating given with one word: a hairline scale with a notch for each grade, and over it the word for the grade
         under the pointer, which takes weight and width as the pointer moves along the scale. Where the word changes,
         the letters the two words share slide to their new places and the others swap, one after the other. Picked,
         the notch lights up and the word settles on the line. Under the scale there are real radio buttons; the
         letters and the scale are drawn by the script -->
    <form class="weigh" data-weigh onsubmit="return false">
      <p class="weigh__ask" id="weigh-ask">How did you sleep?</p>
      <fieldset class="weigh__pad" aria-labelledby="weigh-ask" data-pad data-autoclic>
        <div class="weigh__word" aria-hidden="true" data-word></div>
        <div class="weigh__scale" data-scale>
          <svg class="weigh__art" aria-hidden="true" data-art>
            <defs>
              <clipPath id="weigh-fill"><rect x="0" y="0" width="0" height="40" data-fill/></clipPath>
            </defs>
            <path class="weigh__line" data-line/>
            <path class="weigh__line weigh__line--ink" clip-path="url(#weigh-fill)" data-line-ink/>
            <g data-ticks></g>
            <line class="weigh__needle" data-needle/>
          </svg>
          <div class="weigh__choices" data-choices></div>
        </div>
      </fieldset>
      <p class="weigh__note" role="status" aria-live="polite" data-note></p>
    </form>
  </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.

23 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 rating in words that weigh” from Animorio and fit it into my site

What it does

On a white background the question How did you sleep?, small and black; under it, large and grey, the word Rate, and lower down a thin grey line with five short notches hanging from it, one for each grade, and the words Slide along the line. Moving the pointer over it, a black needle appears over the line, the line turns black up to the needle and the word becomes the one for the grade pointed at, in black: Poor, hairline thin and narrow, Fair, Good, Great and Superb, black and wide. The type does not jump from grade to grade: between two notches the word has a weight and a width in between, and near a notch it keeps its own shape. The weight does not reach the whole word at once: it runs along the letters, from the left going towards the high grades, from the right coming back. When the grade changes, the letters the two words share (the r between Poor and Fair, the G between Good and Great) slide to their new places on a spring, a pixel past and back; the others fade out upwards and the new ones rise from below one after the other. On a click the notch for the grade grows with a little bounce and lights up blue, the word settles on the line (the letters sink by a pixel or two, the middle ones first, more the heavier the word) and the line under it gives a little and straightens. Below appears Thank you. Sleep well., and at every change of mind Changed to followed by the new grade. Leaving, the word goes back to the grade picked, or to Rate if there is none yet. A finger slides along the line or across the word and the grade falls where it lifts; with the keyboard the arrows move the word at once and log the grade after a short pause, Enter logs it straight away.

How it works

Five notches over five real radio buttons

Over the notches lie five real radio buttons, see-through and with no pointer events, in a fieldset tied to the question (aria-labelledby): Tab goes into them, the arrows change the grade, screen readers read the word (aria-label) and the form sends the value. The hand works on the word and the line through pointer events; the arrows move the word at once and log the grade after a 0.55 second pause (a gsap.delayedCall that every key restarts), Enter and Space log it straight away. The keyboard’s ring sits round the notch.

The type measured just once

Every letter is a span placed by the script, with its own wght and wdth axes. So as not to ask the page for sizes on every frame, at the start every letter of the words, and every pair of neighbours for the kerning, is measured at 100 pixels on a grid of five weights by five widths (Anybody goes from 100 to 900 and from 50 to 150); any shape in between is read off the grid by bilinear interpolation. The type’s size comes from the same numbers: the widest word along the whole line must fit the box, and on resize the sum is done again.

Weight that runs along the word

The place on the line goes from 0 to 4 and is chased by a lightly damped spring. The place is pulled a little towards the nearest notch (a power curve, DETENT), so near a notch the word keeps its own shape and halfway it is exactly the shape in between; from there weight and width are read between THIN and BOLD, NARROW and WIDE. Every letter chases that shape with a first order filter whose time constant grows by RIPPLE seconds for each place away from the side the hand comes from: the weight enters the word like a wave.

The shared letters stay

When the place crosses halfway between two notches (with a small margin, so the word does not flicker on the border) the two words are lined up by their longest common subsequence: the letters that stay are the same spans, and the jump between their old and new places becomes an offset that a spring takes to zero with one pixel too many. New letters are born in their places under the word’s line and rise with back.out(0.9), one after the other (STAGGER) in the hand’s direction; the old ones stay where they were, rise and fade within 0.15 seconds.

The word that settles

Once the grade is picked, the notch grows and takes the accent with back.out(2.4). When the right word has reached the notch, the letters sink by SETTLE pixels for the heaviest word (a third of that for the lightest) with a one pixel squash, rise back by a third and settle, the middle ones first; at the same moment the line dips under the notch along a gaussian and straightens. Everything runs in a single loop on GSAP’s ticker, with the step capped at 1/30 of a second, which is removed when nothing moves.

Fingers, keys, the preview

A finger slides sideways along the line or across the word (touch-action: pan-y) and the grade falls where it lifts; a mouse button let go far away picks nothing. A click from a script (detail 0, the library’s preview) is a pretend hand in a GSAP timeline: it slides to the grade and picks in turn Superb, Fair, Great and Poor, then puts everything back to rest and starts again.

Values to change

NameFileDefaultWhat it changes
LABELSscript.js['Poor', 'Fair', 'Good', 'Great', 'Superb']The word for each grade, from the lowest to the highest (and how many notches: 2 to 7).
IDLEscript.js'Rate'The word shown, in grey, before a grade is picked.
STARTscript.js0The grade picked when the page opens (0 = none).
THINscript.js130The weight of the lowest grade’s word (100 to 900).
BOLDscript.js900The weight of the highest grade’s word (100 to 900).
NARROWscript.js54The width of the lowest grade’s word (50 to 150).
WIDEscript.js140The width of the highest grade’s word (50 to 150): the wider it is, the smaller the word gets to fit the box.
SIZEscript.js64The largest size of the word, in pixels; in a narrow box it gets smaller.
DETENTscript.js0.6How much each notch holds the word in its own shape (0 = the weight changes evenly along the line).
RIPPLEscript.js0.03The delay between one letter and the next as the weight runs along the word, in seconds.
STAGGERscript.js0.045The time between one letter and the next as they swap, in seconds.
SETTLEscript.js2.5How many pixels the heaviest word sinks as it settles on the line.

Try them in the Playground

When to use it

To ask how a night in a hotel or a holiday home went, to rate a product after buying it, a dish or a delivery, for the survey at the end of an event: wherever a word says more than five stars and the rating has to sit in one sober line, with the type as the lead.

On phones

The line is 300 pixels long at 390 too, and the word gets just small enough for Superb, the widest, to fit the box (about 56 pixels). A finger slides sideways along the line or across the word and the grade falls where it lifts; up and down the page still scrolls (touch-action: pan-y). A tap picks straight away, with the same letter swap and the same settling. The note under it reads Slide or tap along the line.

With reduced motion

No sliding, no waves and no settling: the word takes the pointed grade’s shape at once, and when it changes the old one fades and the new one appears in its place; the notch lights up in a fade, the needle and the note change without moving.

Pitfalls

  • The first swap faded the old letters out on the same curve as their rise (power2.in): they stayed solid to the end and for a moment the two words read one over the other. Now opacity and movement are two separate tweens: the old letters fade within 0.15 seconds, the new ones start 0.08 seconds later.
  • In the first try the word's band was one and a half times the type's size, with the word centred: between Poor and the line there was a forty pixel gap and the word did not seem to rest on the line. Now the band is 1.45 times the size, just enough for the p of Superb and the rising letters not to be cut by the fade at its edges.
  • With reduced motion the shared letters jumped to their new places while the others faded, and a mixture of both words showed: now with reduced motion the whole word fades and the new one appears after.

Libraries

GSAP 3.15.0, Anybody (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 11 KB; the libraries: GSAP 28 KB.

Testing

Tested on 16 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