Skip to content
animorio
IT
Back to the library

Hold and pour

Physics, HoverCanvas, GSAPAdvancedCompressed weight: Demo 12 KBGSAP 28 KBFreeDownload the zip

An oil bottle that tips while you hold: the oil inside always stays level, runs out of the neck once it reaches it and falls in a stream the pointer aims. The bowl fills with rings where the stream lands; whatever misses it ends on the board.

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>Hold and pour</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/young-serif@5.3.0/index.css">
  <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>
  <header class="bar">
    <a class="brand" href="#">Casale Verde</a>
    <nav class="bar__nav" aria-label="Sections">
      <a href="#">The oil</a>
      <a href="#">Groves</a>
      <a href="#">Shop</a>
    </nav>
  </header>

  <main class="page">
    <section class="copy">
      <p class="kicker">Cold-pressed, first harvest</p>
      <h1 class="title">Pour it slowly. We pressed it slowly.</h1>
      <p class="note">Hold the table to tip the bottle, and move to aim. Fill the bowl without spilling a drop.</p>
      <button class="pour" type="button" data-pour data-autoclic>Pour a measure</button>
    </section>

    <!-- the table: a bottle that tips while you hold, a stream that falls, a bowl that fills; all drawn on the canvas -->
    <section class="stage" data-stage aria-label="Pouring olive oil into a bowl">
      <canvas class="stage__canvas" data-canvas aria-hidden="true"></canvas>
      <p class="served" data-served aria-live="polite"></p>
      <p class="hint" data-hint>Hold to pour</p>
    </section>
  </main>

  <!-- the round cursor that says what to do, stretched by its speed -->
  <div class="cursor" data-cursor aria-hidden="true">
    <span class="cursor__disc" data-disc></span>
    <span class="cursor__text" data-cursor-text>Hold &amp;<br>pour</span>
  </div>

  <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 “Hold and pour” from Animorio and fit it into my site

What it does

The page of an invented olive oil, Casale Verde: on the left the title «Pour it slowly. We pressed it slowly.» and a button, on the right a table with a bottle and a bowl on a board, drawn as engravings: white, with ink hatching that changes drawing eight times a second. Holding the table tips the bottle; the oil inside stays level and, once it reaches the neck, runs out, gently at first and then harder the further the neck is below the level. The stream is a chain of drops that fall and are drawn as one ribbon, thicker where it comes out and thinner as it speeds up. Moving the pointer makes the bottle follow it, more the further it is tipped, and the stream moves: in the bowl the oil rises and rings spread where it lands, outside it ends in a puddle on the board. The full bowl says «That’s a proper dip.», or that the board had its share too, and once the bottle is upright again it slides away and an empty one comes, with the bottle full again. The button pours one measure: it keeps the bottle tipped for a second and a half. On a computer a round cursor says «Hold & pour»: it shrinks while you hold and stretches the way it moves.

How it works

Level oil

The bottle is a polygon in its own space. Every frame the script turns and moves it to where it is and looks, by bisection, for the horizontal line that leaves exactly the oil there is below it: the area is measured by cutting the polygon with that line. The piece of polygon below the line is the oil, and it is drawn in the page’s own space, so it stays level whatever the bottle does. When the bottle speeds up or slows down the surface tilts a little and swings back, like a spring.

When it runs

The neck pours when its lower lip is under the level, at a rate that grows like the square root of how far under it is, like water from a hole (Torricelli), times FLOW. So a full bottle pours early and a nearly empty one must be tipped further. While you hold, the bottle reaches ANGLE degrees in TILT seconds on a soft curve, and loses whatever runs out.

The stream

Ninety drops a second are born at the neck, in its direction, at a speed that grows with the flow plus a little of the bottle’s own; GRAVITY pulls them down and the air slows them sideways. They are drawn as a ribbon through all of them in the order they left, in three passes: ink, gold and a thread of light. Its width comes from the flow (THICK at full flow) and falls with speed, because the same oil goes through a narrower section. A new ribbon only starts after a real pause, so the stream never splits in two.

The bowl

The bowl is seen a little from above: rim and foot are ellipses. The oil is an ellipse that rises from the bottom and widens; since the bowl widens upwards, the level for a share of oil comes from a cube root, as for a cone’s frustum. Where the drops land a ring is born every RINGS seconds, spreading and fading; the near side of the bowl is drawn after the stream and covers its end. SHARE of the bottle fills it; full, if you keep pouring, it overflows onto the board.

The cursor

A disc follows the pointer with a lag, a tenth of the distance every frame. Its speed, smoothed, stretches it the way it moves and narrows it across by a tenth (STRETCH, four times as much while you hold); pressing shrinks it to half and the words disappear.

The engraving

Bottle, bowl and board are filled white and hatched with patterns of wavy lines (the canvas’s createPattern), three versions per pattern; every outline also has a different wobble in each version. The versions take turns BOIL times a second.

Values to change

NameFileDefaultWhat it changes
TILTscript.js1.1The seconds the bottle takes to tip right over while you hold.
ANGLEscript.js112How far it tips, in degrees from upright.
FLOWscript.js1How fast the oil runs out of the neck.
GRAVITYscript.js2600How hard the stream is pulled down, in pixels a second squared.
THICKscript.js10The stream’s width at full flow, in pixels.
MEASUREscript.js1.5The seconds the button keeps the bottle tipped.
RINGSscript.js0.12The seconds between two rings where the stream meets the oil.
FOLLOWscript.js0.1How quickly the bottle follows the pointer, each sixtieth of a second (0 to 1).
SHAREscript.js0.22How much of the bottle it takes to fill the bowl.
BOILscript.js8How many times a second the engraving changes drawing.
STRETCHscript.js0.01How much the round cursor stretches with its speed.

Try them in the Playground

When to use it

For a product that pours: oil, wine, coffee, syrups, paints. Holding turns the wait into a game: it suits the opening of a product page, or the place of a loader.

On phones

You hold the table with a finger and move it to aim; at the bottom a label says «Hold to pour». The table lets the page scroll vertically (touch-action: pan-y): if the finger goes up or down the page scrolls and the bottle stands up again.

With reduced motion

The bottle still tips and pours, because it answers a gesture, but it does not sway, the oil’s surface does not swing, no rings spread on the oil and the hatching does not change drawing; the cursor does not stretch.

Pitfalls

  • The level must be found and drawn in the page’s own space: drawn inside the bottle’s rotated transform, it would turn with it.
  • The bisection looks for the level between the highest and lowest point of the turned polygon: 26 steps are enough for an error under a pixel.
  • With the flow coming and going right on the lip, every restart would be a new ribbon next to the old one and the stream would split: a new ribbon only starts after 0.12 s without oil.
  • A stream that is too fast jumps the bowl: the speed out of the neck is low and the bottle’s resting place is worked out from ANGLE, so the neck, tipped right over, reaches above the bowl.
  • The button ignores clicks while it pours (the previews’ pilot clicks every 2.8 s), and on a full bowl it brings the empty one instead of pouring.
  • The round cursor exists only with a fine pointer: on phones the fixed label takes its place.

Libraries

GSAP 3.15.0, Young Serif 5.3.0, Instrument Sans (font variabile) 5.3.0.

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

Testing

Tested on 21 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 animations