Skip to content
animorio
IT
All components

The cloche button

Buttons, Physics, SVGGSAP, Canvas, CSS onlyAdvancedCompressed weight: Demo 12 KBGSAP 28 KBFreeDownload the zip

A hotel's room service button on a black background: in the round end of the night-blue pill a silver cloche on its plate, mirroring a dark room. Under the pointer a hand lifts the cover a crack and a thread of steam slips out; at a click the cover rattles on the plate like a pot lid while the order goes, then lifts and tilts back, the steam rolls up over the croissant and the pill says On its way. A moment later the cover comes down with a clink and settles.

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 cloche button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the cloche button: the room service button of a hotel, with a silver cloche on its plate in the round left end
         of the pill. Under the pointer the cover lifts a crack and a breath of steam slips out; a click rings the
         kitchen and the cover rattles on its plate while the order goes; then a hand lifts it, the steam rolls out
         over the breakfast and the pill says it is on its way. A moment later the cover comes down with a clink -->
    <div class="cloche" data-cloche>
      <div class="cloche__unit">
        <button class="cloche__btn" type="button" data-btn data-autoclic>
          <span class="cloche__fill" aria-hidden="true"></span>
          <span class="cloche__faces">
            <span class="cloche__face" data-face="rest">
              <span class="cloche__word" data-rest-text>Order breakfast</span>
              <span class="cloche__price" data-rest-price>€24</span>
            </span>
            <span class="cloche__face cloche__face--two" data-face="busy" aria-hidden="true">
              <span class="cloche__small" data-busy-small>Room 214 · Continental</span>
              <span class="cloche__big" data-busy-text>Calling the kitchen</span>
            </span>
            <span class="cloche__face cloche__face--two" data-face="done" aria-hidden="true">
              <span class="cloche__big" data-done-text>On its way</span>
              <span class="cloche__small" data-done-small>At your door in 25 min</span>
            </span>
          </span>
        </button>
        <!-- the plate, the breakfast and the cover, and above them the steam; the pointer goes through both -->
        <canvas class="cloche__steam" aria-hidden="true" data-steam></canvas>
        <svg class="cloche__art" viewBox="-16 -60 96 124" aria-hidden="true" data-art></svg>
      </div>
      <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.

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

What it does

On a black background a night-blue pill 60 pixels tall, with a thread of gold on its edge and a bluish shadow under it; on the right Order breakfast in cream Fraunces and the price €24 in gold. In the round left end, where the icon would be, a china plate with a gold rim and on it a silver cloche: a polished dome mirroring a dark room (a bright window high up, the dark horizon, the warm plate at its foot), with a long glint on the left and the knob on top. Passing over the pill the words grow fuller and softer, the fill swells with a bounce and a hand lifts the cover by its left side: a warm light shows under the rim and threads of steam slip out of the gap, rising and curling. At a click the pill says Room 214 · Continental and Calling the kitchen, and the cover rattles on the plate like the lid of a boiling pot: one side then the other jumps and drops back, and each jump lets out a puff of steam. When the kitchen answers the hand lifts the cover high and tilts it back, a golden croissant is on the plate, the steam rises in a cloud that curls in the black air and the pill says On its way · At your door in 25 min. A moment later the cover comes down, knocks on the plate with a clink, bounces a hair and stops, and Order breakfast is back. With the keyboard the focus shows a gold ring and lifts the cover as the pointer does; Enter or Space order. On a phone a tap makes the cover jump and orders.

How it works

The cloche in an SVG

A single SVG lies over the end of the pill, in the pill's coordinates (pointer-events: none, so the click reaches the button). The dome is a path with a horizontal silver gradient and, clipped inside it with a clipPath, a second vertical gradient that is the room it mirrors: light at the top, a dark band for the horizon, the plate's warmth at its foot. Over it, two glints softened with a feGaussianBlur. The gradients take their colours with stop-color: var(--silver) and the like, so the Playground's swatches change them. Every frame only the transform of the cover's group changes.

The cover: two rims on two springs

The cover has no single height: its two rims, left and right, each have a height and a speed and a spring pulling them where the hand wants them (at rest 0, under the pointer 7.5 and 0.8 pixels, open LIFT + 9 and LIFT − 9). The plate stops them from below: a rim that hits it bounces back with 34% of its speed. The average height is how high the cover is, the difference gives its angle (atan2 of the difference over its width). A constraint keeps the difference within what a rigid cover can do.

The rattling cover

While the order goes, every 0.1–0.23 seconds a random rim gets a kick upwards (34–74 pixels a second times RATTLE), sometimes the other one a little too: the spring brings it down, the plate stops it and it bounces, and the two rims together make the rattle of a lid on a pot. Each time a rim is up, the gap lets out steam; each hard knock on the plate jolts the pill's fill.

Steam on curled noise

The steam is puffs on a canvas: each has a position, a speed, an age and a lifetime, and every step its speed chases a wind that is the curl of a Perlin noise drifting in time, plus a lift that grows with age. The curl of a smooth field has no sources or sinks, so the puffs swirl instead of bunching up. The dish breathes from three spots that wander slowly: puffs born at the same spot follow the same wind and draw threads instead of a fog. Each puff is a soft disc drawn once and stamped, stretched along its way.

The states and the savings

Three faces on top of each other, as wide as their words (at rest, ordering, on its way); the pill is measured once on the widest. The button is a real button with aria-disabled while it orders and while the cover is up, an aria-live region that says Calling the kitchen… and then On its way. At your door in 25 min., and an aria-label that changes with the state. GSAP's loop works only while something moves, and stops off screen (IntersectionObserver).

Values to change

NameFileDefaultWhat it changes
LABELscript.jsOrder breakfastThe words at rest.
PRICEscript.js€24The price beside the words.
ORDERscript.jsRoom 214 · ContinentalThe small line while the order goes: the room and what was ordered.
CALLINGscript.jsCalling the kitchenThe words while the cover rattles; the aria-live region says them too.
DONEscript.jsOn its wayThe words once the cover is lifted.
ETAscript.jsAt your door in 25 minThe small line under them, with the delivery time.
WAITscript.js1.6The seconds the order takes: the cover rattles all the while. In a real site it is the time the server takes to answer.
HOLDscript.js2.6The seconds the cover stays up before it comes down.
LIFTscript.js34How high the hand lifts the cover, in pixels.
STEAMscript.js1How much steam: 0 none, 2 a cloud.
RATTLEscript.js1How hard the cover rattles while the order goes: 0 it waits still, 3 it jumps hard.

Try them in the Playground

When to use it

For a hotel's or a holiday home's room service, for ordering at the table in a restaurant, for a kitchen's or a bakery's delivery, for the Order now of an online menu. The button fakes the order: in a real site the click calls the kitchen, the cover rattles until the server answers and lifts when the order is confirmed.

On phones

The pill is about 320 pixels wide and the steam rises over its left end: at 390 pixels it fits. A tap makes the cover jump, squashes the fill and orders. The cloche keeps its size.

With reduced motion

The cover does not move and there is no steam: when the order is confirmed the cover fades away and the croissant shows, then it fades back. The words fade in, the pill does not swell and the words do not change shape (under the mouse the fill only lightens a little).

Pitfalls

  • The noise's curl was taken over a step of half a pixel and divided by half a pixel: the derivatives came out thirty times too small and the steam rose straight like a column. Now the step and the division are in the noise's own units, and the wind really curls.
  • Puffs born at random spots over the plate made an even fog. Now the plate breathes from three spots that wander slowly with the noise: the puffs from one spot follow the same wind and become threads.
  • A dome 46 pixels wide and a plate 55 wide came out of the curve of the pill's end at the bottom left. Now the cloche is a little smaller and two pixels further in.
  • The croissant drawn as five ovals side by side looked like a row of balls. Now it is a single crescent with the folds of its roll on the slant and the shine of the egg wash on its back.

Libraries

GSAP 3.15.0, Fraunces (font variabile) 5.3.0.

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

Testing

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