Skip to content
animorio
IT
All components

The fingerprint button

Buttons, Transitions, HoverCanvas, GSAPAdvancedCompressed weight: Demo 14 KBGSAP 28 KBFreeDownload the zip

A hold-to-sign-in Sign in with Touch ID button with a real sensor in the round end of the pill: a steel ring round a dark sapphire, and on it a fingerprint that is grown, not drawn, with its core, its loops and its delta. Held down, ink fills the ridges from the point touched outwards, running along the ridges faster than it jumps the valleys, with a wet edge; let go too soon and it drains back (Keep holding…). Once read, the ridges fold one after the other into a tick and the pill opens on Signed in as Ada; Lock opens them out again.

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 fingerprint button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the fingerprint button: Sign in with Touch ID, held down. In the round end of the pill a sensor with a
         fingerprint grown from a field of directions (a loop round its core, a delta below). Held, ink fills the
         ridges from the point touched outwards, running along them faster than it crosses the valleys; let go too
         soon and they empty again. Read, the ridges fold into a tick and the pill opens on the person signed in -->
    <div class="touch" data-touch>
      <button class="touch__btn" type="button" data-btn data-autoclic>
        <span class="touch__fill" aria-hidden="true" data-fill></span>
        <canvas class="touch__sensor" aria-hidden="true" data-sensor></canvas>
        <span class="touch__faces">
          <span class="touch__face" data-face="a">
            <span class="touch__word" data-wide="Sign in with Touch ID" data-word>Sign in with Touch ID</span>
          </span>
          <span class="touch__face" data-face="b" aria-hidden="true">
            <span class="touch__word" data-word></span>
          </span>
          <span class="touch__face touch__face--done" data-face="done" aria-hidden="true">
            <span class="touch__who">
              <span class="touch__lead" data-lead-text>Signed in as</span>
              <span class="touch__name" data-user-text>Ada</span>
            </span>
            <span class="touch__lock" data-lock-text>Lock</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 fingerprint button” from Animorio and fit it into my site

What it does

On a white background a graphite pill 60 pixels tall, with a thread of light along the top and a soft shadow under it. On the right, in ivory Mona Sans, Sign in with Touch ID; in the round left end a sensor like a phone's: a ring of brushed steel, bright at the upper left, and inside it an almost black sapphire with its reflection. On the sapphire a fingerprint in thin grey lines: a loop in the middle opening to one side, wider arches below, ridges that end and fork as in real prints. On arrival the button rises gently and the print grows out from its core. Under the mouse the words widen and the fill swells with a bounce. Pressed and held, the fill squashes, the print sinks a hair into the glass and the words become Reading…: from where the finger is (or from the edge of the print nearest to it, when the press is on the words) red ink fills the ridges, runs along each one and jumps from one to the next more slowly, with a peach tip where it is still wet. Let go before a little over a second and the ink drains back to the finger, the words say Keep holding… in peach and then go back to rest. Held to the end, the words become Signing in… and the ridges, the inner ones first, tighten with a slight turn and settle on a tick, going from red to green; in their place a clean green tick remains, the ring takes a thread of green and the pill widens on Signed in as and, under it, Ada, with a small Lock pill. A click on Lock: Locking…, the tick opens back into the ridges, the ink drains towards the point touched, Locked and then Sign in with Touch ID again. A plain click, a short tap or Enter start a reading that goes on by itself; with the keyboard, Space held down is the finger.

How it works

The fingerprint, grown

The ridges are the lines where a phase comes back to zero. The phase grows with the distance from a stroke that starts at the middle of the print and runs out past its edge (the rings round a segment are nested hairpins: the loop), and under the loop it gives way, through a soft maximum, to wide arches across the finger; where the two families meet the ridges crowd and split three ways, as round a delta. Two octaves of smooth noise make it wander, so the ridges end and fork. The side of the loop and the noise depend on SEED.

Marching squares on the ridges

On a grid of half a pixel the sine of the phase is worked out; marching squares follows the lines where it is zero and keeps only those where the cosine is positive (the ridges, not the valleys) and that lie inside the slightly ragged outline of the fingertip. The segments are chained into polylines through the cell edges they share, smoothed twice, and the ones shorter than three and a half pixels are dropped. It is done once: every frame only draws the polylines.

The ink under pressure

At every press each point of every ridge gets a distance: crossing costs CAPILLARY times the straight distance from the finger, running along a ridge costs its length, and two passes along each ridge (forwards and back) keep the shorter. The ink front moves out over that distance while the press lasts (in HOLD seconds, with a pace that slows towards the end) and each segment is cut at the exact point where the front crosses it: behind the front the red, in the last five steps the peach of the wet ink. Letting go, the front goes back.

The ridges folding into the tick

Each ridge knows its length travelled at every point, from 0 to 1, and is laid on the tick along the same fraction (from its left end), with a small sideways offset that tightens. The ridges start in order of their distance from the middle, with a power3.inOut pace and a turn of e(1−e) round the middle that reads as folding; the colour goes from the ink to green in the second half. At the end the ridges fade and a clean three-pixel tick with round ends remains.

Holding, clicking, Space

The button captures the pointer (setPointerCapture), so the finger does not lose it if the pill moves, and while the finger is down the pill never narrows. A press shorter than a quarter of a second is a tap and starts a reading that goes on by itself; so do the click of Enter and a script's click (detail 0), and the preview shows the whole round. Space held is the finger: keydown and keyup with preventDefault, so the button does not also make its own click. The click on Lock counts only if the press began with the sign-in already done.

The words and the states

Two faces for a line of words, taking turns (the old one leaves in a blur, the new one comes in after), plus the face of the person signed in. Before every change the tweens still running on the faces are stopped, so two changes close together never leave two lines on top of each other. The pill takes the measured width of the words with back.out. It is a real button: aria-disabled while it signs in and locks, an aria-live region says Reading…, Keep holding…, Signed in as Ada and Locked. Signed out.

Values to change

NameFileDefaultWhat it changes
LABELscript.jsSign in with Touch IDThe words at rest. If they are too long for the room, the type gets smaller.
READINGscript.jsReading…The words while it is held down.
AGAINscript.jsKeep holding…The words when it is let go too soon.
BUSYscript.jsSigning in…The words while the ridges fold into the tick.
LEADscript.jsSigned in asThe small line over the name.
USERscript.jsAdaThe person signed in. The sign-in is simulated: in a real site this is the name your server returns after WebAuthn.
LOCKscript.jsLockThe small pill that signs out.
LOCKINGscript.jsLocking…The words while the tick turns back into the print.
LOCKEDscript.jsLockedThe words once signed out, before going back to rest.
HOLDscript.js1.2The seconds the finger has to stay down. A reading started by a click takes a third longer.
SPACINGscript.js2.8The distance between two ridges, in pixels: lower, a denser print.
CAPILLARYscript.js3How much slower the ink crosses a valley than it runs along a ridge: 1 it spreads in a circle, 6 it follows the ridges one by one.
SEEDscript.js7The finger: another number, another print (and the loop on the other side).

Try them in the Playground

When to use it

For the sign-in button that uses biometrics: Sign in with Touch ID or with a passkey in a banking app, a password manager, a wallet, the confirmation of a payment or of a delicate action (Hold to confirm). It has to be wired to the WebAuthn API, which asks the system for the finger: here it is all simulated and no sensor is asked anything.

On phones

The pill at rest is about 270 pixels wide and the open one about 220: at 390 pixels they fit with room to spare, and if the words are too long the type gets smaller. A finger held on the pill reads, a short tap starts the reading by itself; the long-press menu and the selection are switched off on the button.

With reduced motion

No print growing in, no swelling fill or widening words (under the mouse the fill only lightens a little). Held down, the ink fades in on all the ridges at once, and let go too soon it fades away; once read, the ridges fade and the tick fades in in their place, the pill takes its new width while the words are gone and Signed in as Ada fades in. Lock goes back the same way.

Pitfalls

  • Pressing on the right side of the pill started the reading by itself: Reading… is shorter than Sign in with Touch ID, the centred pill narrowed, slipped out from under the pointer, pointerleave came seventy milliseconds later and the press counted as a tap. Now the button captures the pointer with setPointerCapture and, while the finger is down, the pill can only widen.
  • With Enter pressed just after Locked two lines showed on top of each other, one wider than the pill: the delayed tween bringing Sign in with Touch ID in started after the one sending it out. Now before every change the faces' tweens are stopped with killTweensOf.
  • The first print, rings round a centre plus a spiral in the phase, was a snail shell: it looked like an icon, not a finger. Arches round a far centre with a core and a delta gave a knot of hairpins under the core. The true loop came from rings round a segment running out past the edge, joined to the arches with a soft maximum.
  • With the preview clicking every 2.8 seconds the second click fell on the sign-in just done and the open pill showed for an instant. The reading by itself takes a third more than HOLD and the fold 1.35 seconds: the sign-in is ready after about 3.6 seconds, the second click falls in the wait and Signed in as Ada stays in view for a whole round.

Libraries

GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 14 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