Skip to content
animorio
IT
All components

The dripping list

Lists, Physics, SVG, TransitionsGSAPAdvancedCompressed weight: Demo 18 KBGSAP 28 KBFreeDownload the zip

Sunday chores in a list that keeps the ones done at the bottom, in a pool of blue ink. Ticking one, the ink runs out of its box through the words, which turn white; then it goes back into the box taking them along, the box gathers into a drop that falls into the pool with a splash, and the ink rises into the place left free, where the chore is again, done.

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 dripping list</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/rethink-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the dripping list: the chores done lie in a pool of ink at the bottom of the list. Ticking one, the ink runs
         out of its box through the words, goes back into the box taking them along, and the box drips: the drop falls
         into the pool, which rises into the place left free, and the chore is there, done, in the ink -->
    <section class="todo" aria-labelledby="todo-title" data-todo data-autoclic>
      <header class="todo__head">
        <h2 class="todo__title" id="todo-title">Sunday reset</h2>
        <p class="todo__count"><span class="todo__roll" data-left><span class="todo__line"><span class="todo__roll todo__n" data-left-n>4</span> left</span></span></p>
      </header>

      <form class="add" data-add>
        <span class="add__icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 5.5v13M5.5 12h13"/></svg></span>
        <input class="add__field" type="text" placeholder="Add a chore" aria-label="Add a chore" maxlength="48" autocomplete="off" enterkeyhint="done" data-field>
        <button class="add__go" type="submit" aria-label="Add the chore" data-go>
          <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 18.5v-13M6.5 11 12 5.5l5.5 5.5"/></svg>
        </button>
      </form>

      <div class="board" data-board>
        <ul class="rows" aria-label="To do" data-todo-list></ul>
        <ul class="rows" aria-label="Done" data-done-list></ul>
        <!-- the ink: a copy of the list in white, cut out by the shape of the ink, drawn again at every frame -->
        <div class="ink" aria-hidden="true" data-ink>
          <svg class="ink__art" data-ink-art>
            <defs>
              <linearGradient id="ink-depth" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="1" data-depth>
                <stop offset="0" class="ink__stop"/>
                <stop offset="1" class="ink__stop ink__stop--deep"/>
              </linearGradient>
            </defs>
            <rect fill="url(#ink-depth)" data-depth-rect/>
            <path class="ink__shine" data-shine/>
          </svg>
          <div class="ink__rows" data-ink-rows></div>
        </div>
      </div>

      <p class="sr" id="todo-move">Up and down arrow keys move the chore.</p>
      <p class="sr" aria-live="polite" data-live></p>
    </section>
  </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.

30 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 dripping list” from Animorio and fit it into my site

What it does

On a white background a white card 390 pixels wide: the title Sunday reset, on the right the count 4 left, below it the field Add a chore with a blue plus, four chores to do (Change the bed sheets, Descale the kettle, Wipe the fridge shelves, Book the boiler service), each with its square box and its three-line handle. The bottom of the card is a pool of ultramarine ink, darker deeper down, its surface climbing the walls a little and a line of light just under it; in it, in white, the two chores already done, Take out the recycling and Water the herbs. When the page opens the ink pours in from the bottom and the chores come in one after another. Ticking a chore its box pops, the ink runs out of the box along the row with its front bulging, and the words turn white where it reaches them; a moment later it goes back into the box with its front hollow, taking the words along, and the box gathers into a round drop that sags, stretches and falls, while the chores below move up to close the place. The drop touches the surface, which reaches up to it, with a splash of droplets and waves that run to the walls and come back; the ink rises into the place left free and the chore is there, white, done. The count’s number rolls over to the new one; with all of them done, the count says All done, the ink fills the whole list and a wave sets off from each wall. Unticking a chore that is done, the ink goes down through the words, which turn dark again, and leaves a few drops hanging from the letters that fall back into the pool; if the chore was deeper down, it comes up over the others inside the ink. With the mouse over a chore a light band and the cross appear, and the cross slides it away to the left; swiping it to the left with a finger (or the mouse) uncovers the red with the bin behind it, which snaps ready past a third of the width: let go, the chore flies away, the red folds shut and the place closes. Typing in the field the blue button appears, and Enter adds the chore at the top while the others and the ink move down. Taken by its handle a chore lifts with a shadow and the others make room for it; carried down over the ink, its box shows the tick it will get and the ink reaches up to it: let go there, it sinks in and is done.

How it works

The list and its wet copy

Every chore exists twice: the real one, an li with the real checkbox, the cross and the handle, and a white copy inside a layer the colour of the ink laid over everything (aria-hidden, pointer-events none, so clicks go through). That layer has a clip-path: path() written again at every frame: wherever the shape of the ink is, the white copy on blue shows, elsewhere the real list. So the words turn white exactly where the ink reaches, pixel by pixel and at every moment: the surface passing through the middle of a line cuts the letters in half, half white and half dark.

One shape, in pieces

The shape is a single path made of several pieces all drawn clockwise, which with the nonzero rule add up: the surface of the pool (44 points joined by quadratic curves, the meniscus climbing 3 pixels up the walls, a little swell under a drop about to touch it), the ink inside a chore (a rounded box growing from the box to the whole row with its front bulging, and going back with its front hollow), the box gathering into a drop, the falling drops (teardrops stretched by their speed), the splashes and the drops hanging from the words. Under the white copy a gradient darkens the ink deeper down, and a white line 2 pixels under the surface is its shine.

The waves

The surface is a wave equation: each point is pulled by its two neighbours (c² times the difference, with c = WAVES[0] pixels a second), slowed down by WAVES[1] and drawn back to the level; the walls send the waves back. It is worked out in steps of 1/240 of a second with the frame capped at 1/30. A drop pushes down a bell 21 pixels wide and throws three droplets which, falling back, make small waves of their own; when the level speeds up, a cosine wave makes the middle lag behind the walls, like a liquid shaken. Under 0.02 pixels the waves are set to zero and, if nothing else moves, the loop stops.

The level, hooked to the chores

The level is the top edge of the first chore that is in the ink (or the bottom of the list) plus a spring of its own. When the chore it rests on changes (a drop arrives, a tick is taken off, a chore is deleted) the spring takes up the difference, so the ink never jumps: it rises quickly (stiffness 150) and drains slowly (58), and when the chores all move together the ink goes with them. A chore ticked already waits in its place, unseen, until the ink covers it; the drop that lands first takes the lowest place among those waiting, because the ink fills from the bottom.

Chores on springs, fingers and handle

Every chore sits in its place in absolute position, carried by a spring (SPRING); the order on screen is the order of two lists in the page, To do and Done, written again when it changes, giving the focus back to the element that had it. Swiping, after 8 pixels (and 1.3 times more than vertically) the row is taken: its insides follow the finger, the red is uncovered from the right edge with a clip-path inset, and past 36% of the width or flung faster than 700 pixels a second the chore goes; the red folds shut vertically before the place closes, and the click that ends the gesture is thrown away. The handle holds the pointer and the others make room when the middle of the chore carried passes theirs; carried down with its middle under the surface, let go it is done and sinks into the top of the ink.

Keys, voices and the preview

The boxes are real checkboxes with their label: Space ticks and unticks, Delete or Backspace on a box deletes the chore, and on the handle the up and down arrows move it (aria-describedby says so). An aria-live region says done, not done, deleted, added, moved to place n of m, and how many chores are left. The focus ring shows on the white copy too, inside the ink. A click from a script (detail 0, the library’s preview) shows one thing at a time: two chores ticked, one moved, one added and swiped away, two taken out of the ink, and the list as it was again.

Values to change

NameFileDefaultWhat it changes
CHORESscript.js['Change the bed sheets', 'Descale the kettle', …]The chores when the page opens.
START_DONEscript.js2How many of them, counting from the end, are already done, in the ink.
FLOODscript.js0.24The seconds the ink takes to run through a chore ticked.
GRAVITYscript.js3000How fast a drop falls, in pixels per second squared.
WAVESscript.js[330, 2.6]The surface of the ink: how fast its waves run (pixels per second), and how quickly they calm down.
SPLASHscript.js1How big the splash of a drop is.
SPRINGscript.js[380, 0.8]The springs that move the chores: how stiff, and how damped (1 = no bounce).

Try them in the Playground

When to use it

For the chores of a home app, the things to pack for a trip, the steps of a move, the tasks of a project or a team, a shopping list: wherever things get ticked off and it is nice to see how much is done already.

On phones

The card takes the width of the screen minus the margins (358 pixels at 390) and the chores stay 54 pixels tall, easy for a finger. The cross is not shown: a chore is deleted by swiping it to the left (the rows have touch-action pan-y, so the page still scrolls up and down) and the cross stays for screen readers; the handle has touch-action none and is dragged with a finger. The field is at 16 pixels, so Safari does not zoom the page, and the keyboard shows Done.

With reduced motion

No spreading ink, drops, waves or slides: ticked, a chore fades and comes back already in the ink, which has risen to its place; unticked, it comes back dry at the end of the chores to do. Chores deleted or added fade and the others are already in their places; the handle still follows the hand, but the others jump straight to the right place, and the surface stays still.

Pitfalls

  • A pointer at rest sends no pointermove: the chore ticked stayed «under the mouse» and carried its light band and its cross right into the ink. Ticking, unticking or carrying it into the ink takes the hover off, and the first movement puts it back.
  • Woken in the middle of a frame, the loop sees zero seconds go by: without a step at zero time the level did not follow the list and, with less movement, the loop stopped with the old level (the chore ticked came back dry over the ink). At zero time a step is taken that updates the level without dividing by the time.
  • A chore taken out of the bottom of the ink, with another one just under it, has no room to drip: waiting for its drops its rise never ended and it stayed enlarged, with the loop always running. It ends when it is in its place and the ink has let go of it, drops or not.
  • The red of the bin, meant for swiping, also showed when deleting with the cross, and after a swipe it stayed full width over the chore moving up into the place: with the cross there is no red, and swiping, the red folds shut vertically before the place closes.
  • The plate that takes a chore over the others inside the ink had the opacity transition: for a moment two white lines of text lay one over the other. It appears at once and fades as it goes.
  • The box emptying from the top into a drop hanging under it made a T; now it gathers itself into a drop, smaller and rounder, that sags, stretches and goes. And the drops hanging from the words were born already on the surface and vanished at once: they let go once the ink has gone down below the letters.
  • Moving in the page the element that has the focus (the chore goes from the To do list to the Done list) loses it for keyboard users: after every reorder the focus goes back to whoever had it. And the opacity left inline by a tween won over the class that hides a chore waiting: every fade ends with clearProps.

Libraries

GSAP 3.15.0, Rethink Sans (font variabile) 5.3.0.

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

Testing

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