Skip to content
animorio
IT
All components

The hourglass button

Buttons, Physics, Transitions, SVGCanvas, GSAPAdvancedCompressed weight: Demo 9.1 KBGSAP 28 KBFreeDownload the zip

A Download · 248 MB button that, pressed, opens up round a small glass hourglass: the sand really falls grain by grain from the top bulb to the bottom one, digging a crater above and heaping into a cone below, and the sand let through the neck is the progress of the download. At the end the hourglass turns over on a spring and the button says Open file.

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 hourglass button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the hourglass button: pressed, it opens up round a little glass hourglass. The sand is a cellular automaton on
         a canvas, grain by grain, and the grains let through the neck are the progress of the download. At the end the
         hourglass turns over on a spring and the button opens the file -->
    <div class="dl" data-dl>
      <button class="dl__btn" type="button" aria-describedby="dl-progress" data-btn data-autoclic>
        <!-- the hourglass: walnut caps and brass posts, the sand, and the glass over it -->
        <span class="dl__glass" aria-hidden="true" data-glass>
          <span class="dl__cap dl__cap--top"></span>
          <span class="dl__post dl__post--left"></span>
          <span class="dl__post dl__post--right"></span>
          <svg class="dl__back" data-back></svg>
          <canvas class="dl__sand" data-sand></canvas>
          <svg class="dl__vial" data-vial></svg>
          <span class="dl__cap dl__cap--bottom"></span>
        </span>
        <span class="dl__icon" aria-hidden="true" data-icon>
          <svg viewBox="0 0 24 24"><path class="dl__arrow" d="M12 4.5v10.5M7.5 10.5L12 15l4.5-4.5"/><path d="M5 19.5h14"/></svg>
        </span>

        <!-- the words: one line at rest, two lines while it works -->
        <span class="dl__rest" aria-hidden="true" data-rest>
          <span class="dl__title">Download</span>
          <span class="dl__size">· 248 MB</span>
        </span>
        <span class="dl__busy" aria-hidden="true" data-busy>
          <span class="dl__title" data-title>Downloading</span>
          <span class="dl__meta" data-meta>0% · 0 of 248 MB</span>
          <span class="dl__hint" data-hint>Press to pause</span>
        </span>
        <span class="dl__done" aria-hidden="true" data-done>
          <span class="dl__title">
            <svg class="dl__file" viewBox="0 0 24 24"><path d="M14 3.5H7.5a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2V8z"/><path d="M14 3.5V8h4.5"/><path d="M9 13h6M9 16.5h4"/></svg>
            Open file
          </span>
          <span class="dl__meta">field-notes.pdf · 248 MB</span>
        </span>
        <span class="sr" data-name>Download field-notes.pdf, 248 megabytes</span>
      </button>

      <span class="sr" id="dl-progress" role="progressbar" aria-label="Download progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" data-progress></span>
      <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.

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

What it does

On a black background a dark pill with a sand coloured arrow and the words Download · 248 MB. With the mouse over it the edge warms to sand and the arrow dips and comes back up as if downloading. Pressed, the pill widens and grows taller with a small bounce, the arrow and the words fade and on the left, turning a little, a glass hourglass appears between two walnut caps and two brass posts, its top bulb full of sand; on the right Downloading, the percentage with the megabytes and Press to pause. The sand starts to go through the neck one grain at a time, in a thin thread falling into the bottom bulb: there the grains heap into a cone that widens as they slide down its sides, while above the surface sinks into a funnel. The download goes in fits and starts and the thread thins and thickens with it, because the neck only lets through the grains the download has reached, and the percentage counts exactly those. Pressing during the download shuts the neck at once: the last grains finish falling and the words say Paused and Press to resume. When the last grain is through the hourglass turns over on a spring, rocks a little and stops; the sand, now on top, settles onto the neck, and on the right Open file appears with a document icon and field-notes.pdf · 248 MB. Pressing again the pill closes and Download is back.

How it works

A grid of grains

The hourglass is a grid of 27 × 47 cells, two pixels each, drawn on a canvas of the same size and scaled up with image-rendering: pixelated, so each grain stays a crisp little square. A second grid says which cells are inside the glass: the half width at each height is a curve that narrows quickly towards the neck, one cell wide, and the same curve, a little wider, is the SVG path of the glass.

The rules of the sand

Every step the grid is read from the bottom up (so a grain moves only once) and every other row the other way along. A grain falls if the cell below is free, otherwise it tries one diagonal at random and then the other; with probability REPOSE it slides two cells across over its neighbour, which flattens the heaps below the 45 degrees of the simple rules. On a step of the glass it slides towards the middle. FALL steps per frame set the speed of the fall.

The neck is the download

The neck cell is a gate: a grain goes in only while the grains through are fewer than the ones allowed. The pretend download is a GSAP timeline in fits and starts taking the progress from 0 to 1 in SECONDS seconds, and at each update the grains allowed become progress × total grains. The percentage shown is through / total: the fallen sand really is the progress. On pause the allowed grains become the ones through at once and the thread breaks.

The colours, and the light on the glass

Each grain has one of the GRAINS colours, picked by a fixed generator, and the grains on the surface are a little lighter, the ones under three layers a little darker: the cones and craters read without outlines. The glass is two SVGs either side of the canvas: behind, a faintly lighter tint; in front, the edge and the highlights, strokes that follow the curve of each bulb a little inside it, long on the left and short on the right.

The turn over on a spring

When the last grain is through and the sand is still, the angle of the hourglass goes to 180 degrees on a damped spring (stiffness 70, damping BOUNCE) while it shrinks a touch, so its corners stay clear of the words. With the spring at rest the angle goes back to 0 and the grid is turned round (turning by 180 degrees is reversing the order of the cells): the picture is the same, and the sand hanging from the cap falls onto the shut neck.

Values to change

NameFileDefaultWhat it changes
SIZEscript.js248The size of the file, in MB.
SECONDSscript.js6How long the pretend download takes, in seconds.
FILLscript.js0.74How full the top bulb is at the start.
REPOSEscript.js0.3How easily the grains slide across: 0 = steep 45 degree heaps, 1 = flat ones.
FALLscript.js4How many cells a grain falls in each frame.
BOUNCEscript.js0.3The spring of the turn over: low, it rocks before it settles; 1, it just stops.
GRAINSscript.js['#e6be78', '#dcb26a', '#eecb8c', '#d2a660', '#c79a56', '#f2d7a0']The colours of the grains.

Try them in the Playground

When to use it

For a download, an export, a backup or an upload that lasts a few seconds: wherever the wait is there anyway and the hourglass makes it pleasant, and where a natural action follows (opening the file). It suits a desktop app, a download page, a creative tool. For instant operations it is too much.

On phones

The open pill is at most 330 pixels wide and fits a 390 screen without spilling over; below 380 pixels the hourglass and the words move closer to the edge. A tap starts, pauses and resumes, and the hint says Tap to pause instead of Press to pause.

With reduced motion

The pill changes size at once, the words and the hourglass fade in without sliding or turning. The sand is not seen falling: at every five per cent the automaton runs to the end within the same frame and the hourglass shows the sand already settled. The turn over is a fade.

Pitfalls

  • With only the down and diagonal rules, a grain on a step of the glass (where the row below is two cells narrower) hung there for ever and the download stopped at 99%: on a step it slides across towards the middle.
  • Turning, the hourglass lying flat reached over Open file with its corner: the words sit further right and the hourglass shrinks a little as it turns.
  • The spring of the turn over, lightly damped, took almost three seconds to fall below a quarter of a degree and a click on Open file did nothing: the spring stops sooner, and a click during the turn ends it at once.
  • The library’s preview clicks by itself and paused the download halfway: a click from neither a hand nor the keyboard does not pause. The Enter key on the button clicks with detail 0 just like a script: it is told apart by its keydown.
  • With grain colours too far apart the sand looked like a mosaic: close tones, lighter on the surface and darker deep down, read as sand.

Libraries

GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0.

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

Testing

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