Skip to content
animorio
IT
Back to the library

The number on a spring

Physics, TextGSAPAdvancedCompressed weight: Demo 8.8 KBGSAP 28 KBFreeDownload the zip

In the minimal style: a newsletter's subscriber count hanging from a thin coiled spring. A click or the pointer pulls it down, let go it bounces with real physics, the spring stretches and squeezes, the number narrows and widens in its own axes, and every bounce counts one more subscriber.

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>Sprung</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the whole page is the button that plucks the spring; the number can also be grabbed and pulled down -->
  <main class="stage" data-stage data-autoclic tabindex="0" role="button" aria-label="A subscriber count hanging from a spring. Press to pull it down and let it bounce.">
    <svg class="lines" data-lines aria-hidden="true">
      <path class="rule" data-rule d="" />
      <path class="dim" data-dim d="" />
      <path class="coil coil--back" data-back d="" />
      <path class="coil" data-front d="" />
      <rect class="mount" data-mount x="0" y="0" width="0" height="3" rx="1" />
    </svg>
    <div class="body" data-body aria-hidden="true">
      <span class="rail" data-rail></span>
      <div class="count" data-count></div>
      <p class="label" data-label></p>
    </div>
    <p class="hint" data-hint>Pull the number down and let go. Every bounce is one more reader.</p>
    <p class="read" data-readout><span class="read__label">Today</span> <b class="read__value" data-today>+0</b></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>

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.

17 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 number on a spring” from Animorio and fit it into my site

What it does

A warm white page with a thin line at the top, the ceiling, drawing itself from the middle outwards. A small clamp appears in the middle and from it comes down a thin spring, drawn as a coil seen a little from above: the front of each turn in black, the back in light grey. At the end of the spring a hair-thin black line, the rail, and under it the digits of 12,480 dropping in one after the other from the middle, heavy and then lighter; below, small, Sprung subscribers. Then the hand that held the number lets it go: the spring stretches under its weight, bounces a few times and stops. A click (or Enter) pulls the number down, a little to one side: the spring stretches and its turns open, the number narrows and gets lighter on the width and weight axes, as if pulled. Let go, it shoots back up, the spring squeezes until its turns almost touch, the number widens and gets heavier, then falls back, and so on, less and less. At every real bounce the number counts one more: the old digit leaves upwards, the new one comes up from below in vermilion, heavy, gets lighter and stays lit until the next one arrives. The ceiling bends a hair under the jerk. With the mouse or a finger you can grab the number and take it down or to the side, and past a point the spring stiffens; let go, it bounces and swings. On the left a thin dimension line measures the spring, with a tick where it rests; bottom right, Today says how many subscribers have arrived.

How it works

A real spring pendulum

The number is a single weight with a position and a velocity, moved in fixed steps of a four-hundred-and-eightieth of a second inside gsap.ticker. The spring has its own natural length and pulls along its direction by Hooke’s law, gravity pulls down and a damping slows it: three forces in all. The stiffness comes from the bounce frequency (in hertz) and gravity from how much the weight stretches the spring, so the number always comes to rest at the same spot on the page and the pendulum does not fall into resonance with the bounce.

A coil seen from above

The spring is a helix redrawn at every frame along the line between the clamp and the rail: for each point an angle, a shift sideways (the sine) and one downwards (the cosine, a little: the turn seen from above). The radius grows slowly at the start and shrinks at the end, so the wire leaves the clamp straight. The cosine also says whether a piece is in front or behind: front pieces go into a black path, back ones into a light grey one. When the spring gets shorter the pitch closes and the turns come together by themselves.

The type feels the tension

How far the spring is stretched compared with rest drives three things: the width axis (font-stretch), the weight (font-weight) and a little scaleY. The value does not go straight to the number: it passes through a small spring of its own, faster and less damped, so the type arrives a moment later and trembles just before it settles. In the same way the angle of the number follows the spring with a small delay, and the ceiling bends a few pixels in the drawing only.

Counting the bounces

The velocity along the spring tells when the number reaches the bottom (it turns from positive to negative) and when it reaches the top (from negative to positive). At the top we look at how far it has risen since the last bottom: more than twelve pixels is a real bounce and the number goes up by one. It only counts after a click or a throw, not during the entrance. The changed digits roll from right to left inside a slot cut by clip-path: the old one leaves upwards, the new one comes up from below with back.out, in vermilion and heavy; the weight drops at once, the colour stays until the next digit turns it black again.

The click, the hand and the rest

The click is a GSAP timeline: the number goes down with power2.inOut to three quarters of the spring, waits a moment and is let go from still. When dragging, a stiff, well damped spring takes the number towards the pointer, so a throw has a real speed; past the longest stretch the spring gives less and less. When everything is almost still, the number is put at its exact resting point and the loop falls asleep: the page always comes back the same. With reduced motion nothing moves and a click changes the digit with a fade.

Values to change

NameFileDefaultWhat it changes
STARTscript.js12480The number the counter starts from.
LABELscript.js'Sprung subscribers'The small line under the number (the newsletter’s name and what is counted).
BOUNCEscript.js1.4How many times a second it bounces, in hertz: 0.8 is a soft, slow spring, 3 a stiff, nervous one.
DAMPINGscript.js0.09How soon the bouncing dies down: 0.03 bounces for a long time (and counts many subscribers), 0.3 stops almost at once.
PULLscript.js0.75How far a click pulls the number down, as a share of the spring at rest.
COILSscript.js12How many turns the spring has.
PER_BOUNCEscript.js1How much the number grows at every bounce (0 = it does not count).
--weightstyle.css560The weight of the number’s typeface at rest, from 100 to 1000.
--stretchstyle.css88The width of the number’s typeface at rest: pulled it narrows, squeezed it widens.

Try them in the Playground

When to use it

For a number you can touch: the subscribers of a newsletter or a channel, tickets sold, downloads of an app, signatures on a petition. It fits a sign-up page, the thank-you page after signing up, a landing page or a panel in an app.

On phones

The same physics with the sizes adapted: the number is bigger relative to the screen, the spring narrower and the same share of the page. A tap pulls the number down, and a finger can grab it and throw it.

With reduced motion

Nothing moves: the ceiling, the spring and the number fade in, already in place. A click adds one subscriber and the digit changes with a fade.

Pitfalls

  • With tight letters (negative letter-spacing) the 4 and the 8 touched and the comma leaned on the 4: the digits get a little more room, and they stay apart when the number widens in the bounce.
  • The old digit leaving and the new one arriving showed on top of each other, one grey behind the other red: each digit sits in a slot cut by clip-path and moves by a whole digit, so it disappears past the edge.
  • Dragged sideways and down, the number turned and ended up below the line at the bottom of the page: the longest stretch accounts for the height of the number and the margin, and sideways the pointer only takes it so far.
  • Without a threshold the last half-pixel bounces would have counted subscribers forever: only a rise of at least twelve pixels counts.
  • A spring pendulum whose swing frequency is half its bounce frequency passes the energy from the up and down into the swing and starts going round in circles: the weight stretches the spring by 42 per cent, and the ratio between the two frequencies stays well away from two.
  • The card’s video stops when the picture stays the same for one second: without the exact rest (the number put at its precise point when it is almost still) a tremble of a tenth of a pixel would have kept it going to the limit.

Libraries

GSAP 3.15.0, Roboto Flex (font variabile) 5.3.0.

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

Testing

Tested on 15 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 animations