Skip to content
animorio
IT
All components

The confetti button

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

Pressing Claim reward, the gift in the button rattles, opens and throws out a cloud of 3D paper confetti. The strips spin round their long axis and veer sideways, the squares rock and glide like leaves, the gold foil flashes when it catches the light and the curled streamers uncoil in the air; it all falls back in front of and behind the button and settles at the bottom of the window with its shadow.

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 confetti button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the paper is drawn on two canvases: the one behind the button holds what flies or lies behind it, the one in
       front holds the rest -->
  <canvas class="paper paper--back" data-back aria-hidden="true"></canvas>

  <main class="stage">
    <!-- the confetti button: pressed, the gift in it opens. The paper bursts out of the gift, turns and glides in the
         air and settles at the bottom of the window -->
    <div class="confetti" data-confetti>
      <button class="claim" type="button" aria-label="Claim reward, 500 points" data-claim data-autoclic>
        <span class="claim__shine" aria-hidden="true"></span>
        <span class="claim__face">
          <svg class="claim__gift" viewBox="0 0 24 24" aria-hidden="true">
            <g data-box>
              <rect class="gift__box" x="4.6" y="11.2" width="14.8" height="9.8" rx="1.5"/>
              <rect class="gift__band" x="10.7" y="11.2" width="2.6" height="9.8"/>
            </g>
            <g data-lid>
              <path class="gift__bow" d="M12 7.6C10.5 4.7 7.1 3.7 6.5 5.7 6 7.4 9 7.6 12 7.6zM12 7.6c1.5-2.9 4.9-3.9 5.5-1.9.5 1.7-2.5 1.9-5.5 1.9z"/>
              <rect class="gift__lid" x="3.4" y="7.4" width="17.2" height="4.2" rx="1.3"/>
              <rect class="gift__band" x="10.7" y="7.4" width="2.6" height="4.2"/>
            </g>
            <path class="claim__check" d="M5.2 12.4l4.4 4.4 9.2-9.6" pathLength="1" data-check/>
          </svg>
          <span class="claim__labels" aria-hidden="true">
            <span class="claim__label" data-label>Claim reward</span>
            <span class="claim__label" data-label>Opening your gift…</span>
            <span class="claim__label" data-label>+<span data-points>500</span> points</span>
          </span>
        </span>
      </button>
      <p class="sr" aria-live="polite" data-live></p>
    </div>
  </main>

  <canvas class="paper paper--front" data-front aria-hidden="true"></canvas>

  <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.

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

What it does

On a white background a dark button with a yellow gift box and the words Claim reward. With the mouse over it a light runs across the button and the lid of the gift lifts to peek. Pressing it, the words become Opening your gift… and the gift rattles harder and harder for a little under a second; then the lid pops and 150 pieces of confetti and 7 streamers burst out of the gift. They rise almost to the top of the window, fanning out, some towards the viewer and some far off, which the button covers when they pass behind it. The coloured strips spin fast round their long axis and the spin makes them veer sideways; the squares and dots rock back and forth gliding like leaves; the pieces of gold foil flash when they turn to the light; the streamers, curled into spirals, uncoil and sway as they fall. Every piece changes colour with its angle: bright when it faces the light up on the left, darker edge-on or turned away. It all falls back and settles at the bottom of the window, with a shadow that darkens as it comes down. Meanwhile the button turns yellow with a tick that draws itself and the points counting up to +500 points. After four seconds the paper lying there fades away and the button is ready again.

How it works

Each piece is a small plate in 3D

Each piece has a position, a speed, an orientation (a quaternion) and a spin. The air holds it back in two different ways: a lot against its broad face (0.05 times the speed squared) and little along its plane (0.003): that is why a tilted piece does not fall straight but slides sideways and glides. The burst is a blast of air out of the gift that dies down in 0.15 seconds: the pieces follow it and then leave it, so they fan out instead of shooting off like bullets.

Strips that spin, leaves that rock

The strips spin round their long axis, faster the faster the air goes past; the spin gives a push across it (the Magnus effect, the cross product of the spin and the wind) and makes them veer. The squares and dots instead are turned back towards lying flat by a restoring torque: they overshoot, come back and rock like a leaf, and every swing makes them glide sideways. The physics runs in fixed steps of 1/120 of a second, and the frame's step is capped at 1/30.

The light and the perspective

The two faces of a piece are projected on the screen with their perspective (the scale DEPTH / (DEPTH − z) and its derivative give the two axes), and become the canvas transform: a rectangle or a circle drawn flat comes out skewed just right. The colour comes from the angle between the face seen and a lamp up on the left, plus a glint aimed at the eye: soft for the paper, sharp and strong for the gold foil, which so flashes.

The streamers

Each streamer is a chain of 30 points 6.5 pixels apart (verlet: the speed is the difference between two positions, then four rounds that put the distances back). A twist turns each link against the one before round an axis of its own: that is what curls it into a spiral. The air holds it back little along the chain and a lot across it, so it uncoils as it flies. The broad side of the ribbon follows the chain's curve, and each stretch takes its own light.

In front, behind and on the floor

There are two canvases, one under the button and one over it: a piece with a negative z is drawn on the one under it and the button covers it. The button is solid: paper that goes through it from front to back bounces off. The floor is the bottom of the window: touching it, a piece lies down along the shortest turn that brings its face level, and its shadow, an ellipse squashed by the perspective, darkens as it comes down. Once everything is still, the loop draws nothing more.

The button's states

Rest, over (a passing light and the lid peeking, also at a touch and with the Tab key), opening (the gift rattles for OPEN seconds, aria-disabled), done (yellow, the tick and the points counting up) and ready again after DONE seconds. The colours of the paper are CSS variables read at every burst, so they can be changed live.

Values to change

NameFileDefaultWhat it changes
PIECESscript.js150How many pieces of paper fly out of the gift.
STREAMERSscript.js7How many curled streamers fly out with them.
POWERscript.js1How hard the gift throws the paper (1 = up to near the top of the window).
AIRscript.js1How thick the air is: more, and the paper glides and rocks for longer.
GRAVITYscript.js1500Gravity, in pixels per second squared.
OPENscript.js0.8The seconds the gift rattles before it opens.
DONEscript.js4The seconds the button shows the points before it is ready again.
POINTSscript.js500The points the reward is worth.

Try them in the Playground

When to use it

For the moment when someone earns something: a reward, a milestone reached, a first purchase, a plan activated, the end of a course. It is a party: right once, in the right place, not on every button.

On phones

The button is 328 pixels wide, or the screen minus 32; the paper spreads less to the sides on a narrow screen and flies less high on a short one, and the floor always stays inside the window. At a touch the button gives and the light runs across it as with the mouse. The canvases use at most twice the screen's density.

With reduced motion

No flight: pressing, the paper appears already lying at the bottom of the window with a fade, the gift turns into the tick at once and the points are already 500. The button does not move and does not come up on arrival.

Pitfalls

  • Thrown with their starting speed alone, the pieces shot off like pellets and fell at once: the air holds them back too much. The burst became a blast of air that dies down in 0.15 seconds, and the pieces fan out as from a real confetti cannon.
  • With only a push back towards lying flat, the squares stopped flat and fell straight like stones: the push must make them swing past it (little damping), and the air against the face must be much stronger than along the plane, so that they rock as they glide.
  • The light must be worked out on the face turned to the eye, not the front face: turned over, a piece shows its back, which needs its own light, or the upturned pieces go black.
  • A piece behind the button is drawn on the canvas below, but if it went from front to back through the button it would vanish into thin air: the button is solid and bounces it off.
  • The perspective must keep the floor inside the window: a piece too near the eye settled below the edge of the screen. The nearest z is worked out from the window's height.
  • The colours of the pieces come from the CSS and are read at every burst: read only once at the start, a colour changed in the Playground did not reach the paper.

Libraries

GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.

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