Skip to content
animorio
IT
All components

The time clock button

Buttons, Physics, TransitionsCanvas, GSAPAdvancedCompressed weight: Demo 13 KBGSAP 28 KBFreeDownload the zip

The Clock in button of a shift app, built as a factory time clock: the pill is the machine, enamelled oxblood, with its dial in the round end (the hands show the time of the computer you are on, and the minute hand jumps once a minute) and the slot along the top, where a manila card waits with a name printed on it. At a click the card goes into the slot, the machine strikes, and the card springs back up on a spring, bobbing and rocking, with the real time printed on it in slightly smudged violet ink. The words become Clocked in · and the time, its figures rolling in like type wheels. The next click stamps Clock out on the line below, in red; the one after takes a new card.

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 time clock button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/courier-prime@5.3.0/700.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the time clock button: the Clock in button of a shift app, built as a factory time recorder. The pill is the
         machine, enamelled, with its dial in the round left end (the hands show the time of the computer you are on)
         and the card slot along its top, with a time card waiting in it. A click pushes the card down into the slot,
         the machine strikes, and the card springs back up with the time printed on it in smudged ink; the next click
         clocks out on the line under it -->
    <div class="clock" data-clock>
      <div class="clock__card-win" aria-hidden="true" data-win>
        <canvas class="clock__card" data-card></canvas>
      </div>
      <button class="clock__btn" type="button" data-btn data-autoclic>
        <span class="clock__fill" aria-hidden="true"></span>
        <span class="clock__slot" aria-hidden="true" data-slot></span>
        <svg class="clock__dial" viewBox="-24 -24 48 48" aria-hidden="true" data-dial>
          <defs>
            <linearGradient id="clock-bezel" x1="0" y1="0" x2="1" y2="1">
              <stop offset="0" stop-color="#ffffff"/>
              <stop offset="0.35" stop-color="#c9ccd0"/>
              <stop offset="0.62" stop-color="#7d8288"/>
              <stop offset="1" stop-color="#e9ebee"/>
            </linearGradient>
            <radialGradient id="clock-face" cx="0.42" cy="0.36" r="0.7">
              <stop class="clock__stop-light" offset="0"/>
              <stop class="clock__stop" offset="1"/>
            </radialGradient>
          </defs>
          <circle class="clock__bezel" r="22.5" fill="url(#clock-bezel)"/>
          <circle class="clock__rim" r="19.4"/>
          <circle class="clock__face" r="18.6" fill="url(#clock-face)"/>
          <g class="clock__ticks" data-ticks></g>
          <g data-shake>
            <path class="clock__hand clock__hand--hour" d="M-1.5 2.6 L-0.9 -8.6 L0 -10.2 L0.9 -8.6 L1.5 2.6 Z" data-hour/>
            <path class="clock__hand" d="M-1 3.4 L-0.6 -14.2 L0 -15.6 L0.6 -14.2 L1 3.4 Z" data-minute/>
            <circle class="clock__cap" r="1.9"/>
          </g>
          <circle class="clock__glass" r="18.6"/>
        </svg>
        <span class="clock__faces">
          <span class="clock__face" data-face="ready">
            <span class="clock__word" data-wide="Clock in" data-ready-text>Clock in</span>
          </span>
          <span class="clock__face" data-face="next" aria-hidden="true">
            <span class="clock__lead" data-next-lead>Clocked in · 09:12</span>
            <span class="clock__word" data-wide="Clock out" data-next-text>Clock out</span>
          </span>
          <span class="clock__face clock__face--busy" data-face="busy" aria-hidden="true">
            <span class="clock__shine" data-busy-text>Clocking in…</span>
          </span>
          <span class="clock__face" data-face="big" aria-hidden="true">
            <span class="clock__big" data-big-text>Clocked in · 09:12</span>
          </span>
        </span>
      </button>
      <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.

28 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 time clock button” from Animorio and fit it into my site

What it does

On a white background a pill enamelled oxblood, 60 pixels tall, with a soft reflection along its top and a warm shadow under it. In the round left end the dial of a factory clock, 46 pixels across: a polished nickel bezel, a cream face, sixty ticks (heavier every five), two pointed black hands and a red cap; the hands show the computer's time, and the minute hand jumps to the next minute with a small shiver, as on real time clocks. Along the top edge, the slot: a dark slit with nickel lips. In the slot a manila time card is waiting, with its fibres, the name NOOR HADDAD printed in red and a double rule under it; only its head shows. In ivory Archivo, Clock in. On arrival the machine rises gently and the card drops into the slot and rocks. With the mouse over it the words widen on the width axis, the enamel swells with a bounce and the card lifts a little and sways, as if to be taken; pressing pushes it down a little. At a click the words become Clocking in…, with a sheen running through them; the card is pushed all the way down into the slot, a moment inside the machine, then the strike: the enamel squashes and comes back with a bounce, the dial jumps and the hands shake. The card is thrown back up, overshoots, drops, bounces and settles higher than before, rocking in the slot: on its first line is the time printed, IN and the computer's time, in violet ink with the figures a little crooked, a second faint strike beside them, the ink bled and paler where the ribbon is worn, still a little glossy and dark until it dries. The words become Clocked in · 09:12 (the real time), the figures rolling like type wheels before they stop; then the line shrinks and rises, and Clock out arrives under it. Another click: the card goes back in, the strike, and it comes up with the second stamp under the first, OUT and the time in red; the words say Clocked out and the time, then Clock in. The click after that is a new shift: the old card is pulled out upwards and disappears, a blank one drops into the slot and is stamped. With the keyboard the focus shows an oxblood ring, the words widen and the card lifts; Enter or Space stamp. On a phone the tap stamps.

How it works

The machine and the dial

The pill is a button with its enamel on a layer of its own (so it swells and squashes without moving anything) and the slot in CSS: a slit with a dark gradient and four box-shadows for the nickel lips. The dial is an SVG: the bezel with a linear gradient, the face with a radial one, the sixty ticks made by the script, and the hands turned by GSAP round the middle (svgOrigin). The time is new Date(Date.now()); a GSAP delayedCall waits for the turn of the minute and jumps the hand with elastic.out, as on real time clocks, with nothing redrawn between one minute and the next.

The card in the slot

The card is a canvas of 60 by 74 pixels inside a window with overflow: hidden whose bottom edge is the slot itself: what goes below it disappears into the machine. Its height out of the slot is h, and the script moves it with translateY(−h) and rocks it with rotate, with the transform-origin h pixels from its head, that is where the slot grips it. The board is painted once off screen: manila with a darker edge, seventy pale and dark fibres placed by a hash, the name printed with the canvas's letterSpacing and the blue rules.

The spring and the strike

At rest the card follows a damped spring towards its height (SPRING swings a second, DAMPING damping): under the mouse the target rises 5 pixels, pressing lowers it 5. To stamp, GSAP pushes it down with power3.in all the way, 0.22 seconds inside the machine, then the strike: the enamel squashes by a tenth and comes back with elastic.out, the dial jumps and the hands turn 7 degrees and back. Then the card gets an upward speed of 330 · KICK pixels a second: the spring carries it past its height, catches it, bounces it; the bottom of the slot is a hard stop. A second, stiffer spring rocks it after a push to the side. Steps of 1/240 of a second, the frame capped at 1/30; once the card is still, the loop sleeps.

The smudged ink

Each stamp is printed once on a canvas of its own: IN or OUT and the time, in bold Courier Prime, one figure at a time, each a little off its line (like type wheels), the whole line slightly crooked. A second faint pass, half a pixel aside, is the wheel bouncing on the ribbon; a shadowBlur of the same colour is the ink spreading into the fibres. Then the pixels go through a noise mask: two octaves of smooth value noise make the ink uneven, a sine along the line pales it where the ribbon is worn, and where the fine noise is low a few voids remain. SMUDGE sets it all, from 0 (a clean print) to 2 (an old ribbon). The newest stamp is born wet, darker, and dries in two and a half seconds.

The rolling figures

Once the card is up, the words Clocked in · 09:12 are built with a span for each figure. Each figure shows random figures, changed by a GSAP tween (not a timer, so the page can slow them down), for 0.32 seconds plus 0.09 for each figure before it: they stop one after the other, from the left, each with a small hop on back.out. The type has tabular figures, so the line does not jiggle while they roll. Then the big line is measured and carried with its own scale exactly onto the small line, and the next action rises under it.

The states

Three states going round: before the shift (Clock in), during it (Clock out), and before the shift again, with a new card: the old one is pulled out upwards and fades, the blank one drops into the slot with power2.in and is stamped. The button is a real button, aria-disabled while it works; an aria-live region says Clocking in…, then Clocked in at and the time. With HOURS_24 set to false the time is on twelve hours (5:46 PM, and on the card 5:46P). A round takes about 3.3 seconds, more than the 2.8 between two clicks of the preview: one click falls in the wait and every stamp stays in view.

Values to change

NameFileDefaultWhat it changes
PERSONscript.jsNoor HaddadThe name printed at the head of the card, in capitals.
CLOCK_INscript.jsClock inThe words before a shift.
CLOCK_OUTscript.jsClock outThe words during a shift.
CLOCKING_INscript.jsClocking in…The words while it clocks in; also what the aria-live region says.
CLOCKING_OUTscript.jsClocking out…The words while it clocks out.
CLOCKED_INscript.jsClocked inThe words once clocked in, before the time.
CLOCKED_OUTscript.jsClocked outThe words once clocked out, before the time.
HOURS_24script.jstrueThe time on twenty-four hours (17:46); off, on twelve (5:46 PM).
SPRINGscript.js2.6The card's spring, in swings a second: higher, quick short bounces; lower, slow long ones.
DAMPINGscript.js0.16How fast the bounces die: 0.05 the card bobs a long time, 0.7 it hardly bounces.
KICKscript.js1How hard the machine throws the card back up after the strike: 0 it rises gently on its spring, 2 it flies high.
SMUDGEscript.js1How smudged the ink is: 0 a clean print, 2 an old ribbon, with crooked figures and voids.

Try them in the Playground

When to use it

For the button that marks the start and the end of something: clocking in on a shift or attendance app, the timer of an app for billing hours, starting a work or study session, checking into a coworking space, a gym or a building site. It has to be wired to your site's real clocking (the call to the server that records the time): here it is all simulated, and the time is that of the computer you are on.

On phones

The machine is about 245 pixels wide and the card stands out over the slot: at 390 pixels it fits with room to spare, and with longer words the pill widens up to the edge. The tap pushes the card a little way down (as a pressing finger does) and stamps.

With reduced motion

The card already stands out of the slot and does not move; the machine does not squash, the pill does not swell and the words do not widen (under the mouse the enamel only lightens a little). Stamping, the new line fades in on the card and the words fade from one to the next, with no rolling figures; the new card fades in where the old one was. The hands show the time without jumps.

Pitfalls

  • The dial's gradient had stop-color="var(--dial)" written as an SVG attribute: presentation attributes do not read CSS variables and the face stayed black. The stops have a class and the colour lives in the CSS.
  • The card's window was placed with calc(50% − half the pill): but the box is as wide as the pill, and the card ended up off the slot. The window is now placed straight on the slot's position.
  • For the new card, a rotation from a tween and the spring that straightens it fought over the same value, and the card trembled in jerks. Now the card going out only gets a push to the side, and the spring does the rest.
  • The ink, at 8.6 pixels and with a noise mask taking away up to half its density, was pale and hard to read. Now the type is 9.2 pixels, the first strike is full and the mask takes away at most 42 per cent.
  • The hands read from Date.now() follow the virtual clock in the site's player: slowing the preview down slows the minute too. The minute check is a GSAP delayedCall, not a setInterval, so it stays in step with the player.

Libraries

GSAP 3.15.0, Archivo (font variabile) 5.3.0, Courier Prime 5.3.0.

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

Testing

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