Skip to content
animorio
IT
All components

The receipt button

Buttons, TransitionsGSAPMediumCompressed weight: Demo 4.7 KBGSAP 28 KBFreeDownload the zip

The button is a little printer: pressed, it hums and the receipt feeds out of its slot a line at a time, top first; at the end it is torn off with a jagged edge, jumps a little and stays there, leaning. Pressed again, the old receipt flies away and a new one comes out, with the next order number.

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 receipt button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/wix-madefor-display@5.3.0/index.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/victor-mono@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the receipt button: the button is a little printer; pressed, the receipt feeds out of its slot line by line,
         then it is torn off with a jagged edge and stays there, leaning -->
    <div class="printer" data-printer data-autoclic>
      <div class="printer__out">
        <div class="paper" data-paper>
          <div class="paper__sheet" data-sheet>
          <div class="paper__body" data-body>
            <p class="r__shop">Corner Café</p>
            <p class="r__meta">Table 4, order <span data-order>#0042</span></p>
            <div class="r__rule"></div>
            <p class="r__row"><span>1 Flat white</span><span>3.40</span></p>
            <p class="r__row"><span>1 Croissant</span><span>2.20</span></p>
            <p class="r__row"><span>1 Sparkling water</span><span>1.80</span></p>
            <div class="r__rule"></div>
            <p class="r__row r__total"><span>Total</span><span>€7.40</span></p>
            <p class="r__meta">Paid by card</p>
            <svg class="r__code" viewBox="0 0 120 26" preserveAspectRatio="none" aria-hidden="true" data-code></svg>
            <p class="r__thanks">Thank you, see you soon</p>
          </div>
          </div>
        </div>
      </div>
      <button class="printer__btn" type="button" data-btn>
        <span class="printer__slot" aria-hidden="true"></span>
        <span class="printer__face">
          <svg class="printer__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 9V3h10v6M7 17H5a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-2M7 14h10v7H7z"/></svg>
          <span class="printer__label"><span data-label>Print receipt</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.

25 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 receipt button” from Animorio and fit it into my site

What it does

On a black background a graphite button with a slot at the top, a printer drawing and Print receipt. Pressed, the button gives a little, the words become Printing and the button buzzes sideways while a white receipt rises out of the slot, a stretch at a time with a short pause in between: first Corner Café, then Table 4, order #0042, the lines Flat white, Croissant and Sparkling water with their prices, the total €7.40, Paid by card, a barcode and Thank you, see you soon. At the end the receipt is jerked down, its bottom edge turns jagged, and it jumps up leaning a little, with a shadow under it; the words become Print again. Pressed again, the receipt flies away up to the left, turning and fading, and a new one comes out with order #0043.

How it works

Three boxes for one sheet

The receipt is made of three boxes: the outer one moves, leans and carries the shadow; inside it, the sheet grows in height from the bottom, over the slot, and has its own clip-path for the jagged edge; inside that, what is printed is pinned to the top of the sheet, so the first line comes out first.

A line at a time

The height to reach is that of what is printed plus 14 pixels. The timeline has a tween for each 18 pixel stretch, of LINE seconds with power1.inOut, followed by an empty 0.04 second pause: the paper feeds and stops, as in a thermal printer. Meanwhile an endless back and forth tween moves the button by SHAKE pixels every 0.045 seconds: the hum.

The tear

At the end the hum stops, the receipt drops 5 pixels in 0.07 seconds, the sheet takes a polygon clip-path with a tooth every 8 pixels, 5 deep, and it jumps up 14 pixels leaning TILT degrees with back.out(2.4), while a shadow comes in (drop-shadow).

The next one

Pressed again, the receipt flies away (up 150 pixels, left 50, turning 16 degrees and fading in 0.45 seconds with power2.in), the order number goes up by one, always written with four digits, and the new one prints from scratch: no height, no cut, no lean.

Words, keys and the preview

The button's words roll (out at the top, in from the bottom); presses while printing and while the receipt flies away are ignored. It is a real button, so Enter and Space print, and an aria-live region says Printing the receipt and then Receipt printed, order #0042. A click from a script (the library's preview) prints, and once printed prints the next one.

Values to change

NameFileDefaultWhat it changes
LINEscript.js0.12The seconds the printer takes to feed a stretch of paper.
SHAKEscript.js0.6How much the printer shakes while it prints, in pixels.
TILTscript.js-2.5How the receipt leans once it is torn off, in degrees.

Try them in the Playground

When to use it

To confirm an order or a payment in a way people remember: the till of a café or a restaurant, an order at the table, a donation, the receipt of a subscription, a ticket, a shopping summary.

On phones

The printer is 280 pixels wide, or the screen minus 48, the receipt 212, and the room above the printer stays fixed, so the receipt coming out does not move the page; the tap does not wait for a double tap (touch-action manipulation).

With reduced motion

The receipt appears whole at once, already torn off and leaning, with no hum, no jerk and no shadow; the old one disappears where it is instead of flying away, the button's words change without rolling and the button does not give or come up on arrival.

Pitfalls

  • The sheet grows in height, not with a scale: with scaleY the letters would be squashed. And it grows upwards because the box is pinned at the bottom, over the slot.
  • The jagged edge is a clip-path worked out on the sheet's real size at the end of printing: set earlier, it would cut the lines still to print.
  • The hum is an endless tween (repeat -1): it must be stopped by hand with kill() and the button put back at x 0, or it would stay half a pixel off.
  • The room above the printer is fixed (300 pixels) and lets the pointer through: the receipt coming out does not push the page down or cover the button.
  • Presses while printing and while the receipt flies away are ignored: two prints at once would put two timelines on the same sheet.

Libraries

GSAP 3.15.0, Wix Madefor Display (font variabile) 5.3.0, Victor Mono (font variabile) 5.3.0.

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

Testing

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