Skip to content
animorio
IT
All components

The bell subscribe button

Buttons, Physics, SVGGSAPAdvancedCompressed weight: Demo 8.7 KBGSAP 28 KBFreeDownload the zip

A channel's Subscribe button, with a brass bell. Pressed, the bell swings like a pendulum and inside it the clapper is a second pendulum: it lags behind, strikes the rim and at every strike drawn rings of sound go out, as strong as the blow, while the subscriber count rolls up figure by figure. Unsubscribing, the bell is caught and a bar is drawn through it.

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 bell subscribe button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/onest@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the subscribe button, with the subscriber count beside it and a hint under it. Subscribing, the bell swings
         like a pendulum with its clapper as a second pendulum inside it: each time the clapper strikes the rim, rings
         of sound go out, and the count rolls up like an odometer. Unsubscribing, the bell is stopped and a bar is
         drawn through it -->
    <div class="subscribe" data-subscribe>
      <div class="subscribe__row">
        <button class="sub" type="button" aria-pressed="false" aria-label="Subscribe to the channel" data-sub data-autoclic>
          <span class="sub__bell" aria-hidden="true">
            <svg class="sub__waves" viewBox="-90 -90 180 180" data-waves></svg>
            <svg class="sub__icon" viewBox="0 0 32 32" data-icon>
              <defs>
                <linearGradient id="brass" gradientUnits="userSpaceOnUse" x1="7" y1="0" x2="25" y2="0" data-light>
                  <stop offset="0" class="brass-a"/><stop offset="0.45" class="brass-b"/><stop offset="1" class="brass-c"/>
                </linearGradient>
              </defs>
              <g data-bell>
                <g data-clapper>
                  <path class="bell__rod" d="M16 9v15.6"/>
                  <circle class="bell__ball" cx="16" cy="26.6" r="2.7"/>
                </g>
                <path class="bell__loop" d="M14.2 5.6a1.8 1.8 0 1 1 3.6 0"/>
                <path class="bell__body" d="M16 5.4c-5.4 0-8 4-8 8.8v4.6c0 2.3-1.3 3.7-2.8 4.6-.6.4-.3 1.3.4 1.3h20.8c.7 0 1-.9.4-1.3-1.5-.9-2.8-2.3-2.8-4.6v-4.6c0-4.8-2.6-8.8-8-8.8z"/>
                <path class="bell__shine" d="M11.2 11.2c.7-1.8 2-2.9 3.4-3.3"/>
              </g>
              <path class="bell__slash" d="M5.4 4.6l21.8 23.6" pathLength="1" data-slash/>
            </svg>
          </span>
          <span class="sub__labels">
            <span class="sub__label" data-label="subscribe">Subscribe</span>
            <span class="sub__label" data-label="subscribed">Subscribed</span>
            <span class="sub__label sub__label--off" data-label="unsubscribe">Unsubscribe</span>
          </span>
        </button>
        <dl class="stat">
          <dt>Subscribers</dt>
          <dd><span class="count" data-count aria-hidden="true"></span><span class="sr" data-count-text></span></dd>
        </dl>
      </div>
      <p class="subscribe__hint"><span data-hint></span></p>
      <p class="sr" aria-live="polite" data-live></p>
    </div>
  </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.

21 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 bell subscribe button” from Animorio and fit it into my site

What it does

On a black background a coral button with a brass bell in a circle and the word Subscribe; beside it, the subscriber count, 48,299, with the word Subscribers above it, and below a grey line, Get a ring when a new video is out. With the mouse over it the bell wobbles slightly. Pressing it, the button turns dark and says Subscribed, gives and springs back, and the bell rings: it swings round its loop to about 45 degrees and inside it the clapper swings on its own, lags behind and strikes the rim, now on one side and now on the other. At every strike three orange arcs open from the side that was hit, grow and fade, fainter on the other side, the wider the harder the blow, and the button shakes a hair. The swings die down and the strikes get lighter and lighter. The light on the brass slides as the bell turns. Meanwhile the subscriber count goes up to 48,300: the figures that change roll like an odometer, through every figure in between, the right-hand ones first; the line below says New videos will ring the bell. With the mouse over it, a subscribed button becomes Unsubscribe, warms towards the coral and shows a faint bar on the bell; pressed, the bell is caught, the bar is drawn right through it, the button goes back to coral, the count back to 48,299 and the line says Unsubscribed. The bell is quiet. After a few seconds the bar draws back and the bell is ready again.

How it works

A damped double pendulum

The bell turns round its loop (angle θ) and the clapper hangs a little lower (angle φ from the vertical). Every frame the script writes the equations of motion of the two angles: a 2 × 2 mass matrix that depends on cos(θ − φ), the centrifugal terms with sin(θ − φ), the weight of each and a damping on the bell. It solves the system with the determinant formula and steps on in 1/600 of a second, with the frame's step capped at 1/30. The two pendulums' own frequencies are the BELL and CLAPPER values: from them the script works out the gravity and stiffness it needs.

The clapper strikes

The clapper is slower than the bell, so it lags behind. When its angle against the bell passes the rim (0.5 radians) and it is still heading outwards, it bounces: an impulse with a restitution of 0.3 swaps momentum between the two, so the bell feels the blow too. If the speed of the impact is above a threshold it is a real strike, and its strength decides the rings.

The hand that rings it

Pressed, the bell gets a kick of speed and for half a second a force in the direction it is going, like a hand shaking it: so it reaches about 45 degrees and the clapper strikes at once. Unsubscribing, the hand stops it: a force against its speed and its angle brings it down in a moment.

The rings of sound

At every strike, round the middle of the bell (turned with it) WAVES SVG arcs open on the side that was hit and as many fainter ones on the other. Each is a path with an «A» arc redrawn at every step of a GSAP tween: the radius grows, the stroke thins, the opacity rises fast and falls slowly. The strength of the strike decides how far they go and how bright they are.

The rolling count and the bar

Each figure of the number has its own slot with hidden overflow and a mask that fades it at the top and bottom. A figure that changes becomes a strip with every figure in between, from the old one to the new, that rolls up with back.out; the right-hand figures go first. The bar on the bell is a path with pathLength 1 drawn with stroke-dashoffset, with an edge in the button's colour made of two drop-shadows, so it cuts the bell cleanly.

Values to change

NameFileDefaultWhat it changes
COUNTscript.js48299The subscribers before you.
SWINGscript.js1How hard the bell is rung (1 = about 45 degrees).
RINGscript.js0.8The seconds the swing takes to die down to a third.
BELLscript.js2.2The bell's own swings per second.
CLAPPERscript.js1.3The clapper's own swings per second: slower than the bell, so it lags and strikes.
WAVESscript.js3How many rings of sound go out at each strike.
QUIETscript.js2.4The seconds the bar stays through the bell after unsubscribing.

Try them in the Playground

When to use it

For subscribing to a channel, a newsletter, notifications from a product or an author: wherever the bell means «I will let you know». The movement is short and dies down on its own, so it holds up on a busy page too.

On phones

The button is 60 pixels tall, big enough for a thumb, and at 390 pixels the count still sits beside it; on a narrower screen it goes under it. At a touch it gives and the bell rings as with the mouse; without a mouse there is no Unsubscribe under the finger: a second tap unsubscribes and shows the bar.

With reduced motion

The bell does not swing: subscribing, two still arcs light up on either side of it and fade, the words change without sliding and the number changes at once. Unsubscribing, the bar is already there and the bell dims.

Pitfalls

  • With the clapper faster than the bell almost nothing happened: the two pendulums went together and there were two strikes in all. The clapper must be slower, so it lags at every turn and strikes.
  • The clapper, resting against the rim, «strikes» hundreds of times in a row at almost no speed: only impacts above a threshold are real strikes, otherwise the rings went off in bursts.
  • The double pendulum's equations become unstable with a big step: it steps on in 1/600 of a second within the frame, and the frame itself is capped at 1/30.
  • The rings live in an SVG bigger than the button, centred on the bell: inside the bell's circle they were cut off. The button's words sit over the rings (z-index), or the arcs crossed in front of them.
  • The white bar on the bell did not stand out from the brass: it has an edge in the button's colour made of two drop-shadows, which changes with the button's colour.
  • The warm colour of Unsubscribe must only be given when the button really offers it: with :hover it showed right after the click that subscribed, while the words still said Subscribed.

Libraries

GSAP 3.15.0, Onest (font variabile) 5.3.0.

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

Testing

Tested on 12 October 2026

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

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