
The cookie banner
Consent, Transitions, SVG, Physics
NewFree
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.
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>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
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 siteEvery 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.
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 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 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.
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.
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.
| Name | File | Default | What it changes |
|---|---|---|---|
CHORES | script.js | ['Change the bed sheets', 'Descale the kettle', …] | The chores when the page opens. |
START_DONE | script.js | 2 | How many of them, counting from the end, are already done, in the ink. |
FLOOD | script.js | 0.24 | The seconds the ink takes to run through a chore ticked. |
GRAVITY | script.js | 3000 | How fast a drop falls, in pixels per second squared. |
WAVES | script.js | [330, 2.6] | The surface of the ink: how fast its waves run (pixels per second), and how quickly they calm down. |
SPLASH | script.js | 1 | How big the splash of a drop is. |
SPRING | script.js | [380, 0.8] | The springs that move the chores: how stiff, and how damped (1 = no bounce). |
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.
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.
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.
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.
Tested on 6 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.