Skip to content
animorio
IT
Back to the library

The pond under the pointer

Hover, PhysicsCanvas, GSAPAdvancedCompressed weight: Demo 15 KBGSAP 28 KBFreeDownload the zip

A pond seen from above, drawn on a canvas: the pointer leaves rings that spread and cross, the lily pads drift on the waves and bounce off each other, the koi dart away and then come back, curious. A click drops a pebble with a splash.

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 pond under the pointer</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/index.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/wght-italic.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="pond" data-pond>
    <!-- the water, the lily pads, the koi and the pebbles are all drawn here -->
    <canvas class="pond__canvas" data-canvas aria-hidden="true"></canvas>

    <header class="sign" data-sign>
      <p class="sign__tag" data-fade>Hollowmere Botanic Garden</p>
      <h1 class="sign__title">
        <span class="word" data-float><span class="word__in">The</span></span>
        <span class="word" data-float><span class="word__in">Lily</span></span>
        <span class="word" data-float><span class="word__in">Pond</span></span>
      </h1>
      <p class="sign__line" data-fade>East glasshouse, beyond the fern walk</p>
    </header>

    <footer class="foot">
      <p class="foot__note" data-fade data-hint>Move over the water. Click to drop a pebble.</p>
      <p class="foot__note foot__note--right" data-fade>Please do not feed the koi</p>
    </footer>
  </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.

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 “The pond under the pointer” from Animorio and fit it into my site

What it does

The screen is the pond of an invented botanic garden, Hollowmere, seen from above: petrol green water, darker in the middle and lighter towards the edges, a few smooth stones in the corners, nine lily pads (some with a pink flower) and four koi, white and red, gold, black and one with only a red circle on its head. Passing with the pointer, the water makes rings that spread, fade and cross the earlier ones; where the wave is steepest the light becomes a pale band. The lily pads move pushed by the waves, sway, squash for a moment when they hit another pad or a stone and bounce; then a weak spring takes them home. The koi swim with a body that waves and bends in the turns: if the pointer passes fast near them they dart away with a flick of the tail, then slow down and come back to circle around it, curious. A click drops a pebble: it falls getting smaller while its shadow catches up, hits the water with a crown of spray and droplets that fly and fall back making their own small rings, pushes the pads away and scares the fish. The words of the title float on the water under them too.

How it works

The water is a grid of heights

The pond is a grid of 5-pixel cells (4 on a phone). Seventy-two times a second every cell takes the average of its four neighbours, minus the value it had the step before, and loses a little (DAMPING). That is enough: a bump pushed into the grid spreads as a ring, and two rings add up by themselves.

The pointer leaves drops

On every frame the script checks how far the pointer has travelled: every 52 pixels (and no more than 14 times a second) a cosine bump is pushed into the grid, stronger when it moves fast. Spaced drops make separate rings instead of one single wake.

Drawing the light

For every cell the script reads the slope: towards the light it gets lighter, on the other side darker. Where the slope passes a threshold the pale glint appears, in a second transparent layer. Both pictures are as small as the grid and the canvas stretches them: the browser’s smoothing makes them soft.

Pads and stones

Under every pad the slope is read in five points and the pad slides downhill; a weak spring takes it home. Two overlapping circles are pushed apart and swap their speed along the normal (a collision with 0.62 bounce); the hit starts a small spring that squashes the pad and makes it round again.

The koi: a head and a chain

The head has a direction and a speed; the twelve points of the body follow it at a fixed distance, so the fish bends in the turns. A sway in the head’s direction makes the tail wave. Fast pointer close by: escape with a dash and a beating tail; once the scare is over every fish takes its place on a slow circle around the pointer.

Values to change

NameFileDefaultWhat it changes
FISHscript.js4How many koi swim in the pond.
LILIESscript.js9How many lily pads float.
RIPPLEscript.js1The strength of the rings left by the pointer.
DAMPINGscript.js0.988How much of a ring survives each step: lower and it dies sooner.
SPEEDscript.js1The speed of the whole pond: waves, fish and pads.
STONEscript.js3.5How much stronger a pebble is than the pointer.
--deep, --shallow, --glintstyle.css#0c3b40, #2c7a6f, #e6f5e4The colours of the water: in the middle, towards the edges and the glint on the crests.

Try them in the Playground

When to use it

For the opening of a site that lives on calm and nature: a garden, a spa, a tea brand, a Japanese restaurant, a retreat. Whoever arrives finds something to touch before even reading, and the pond stays alive on its own too.

On phones

Same pond, with smaller pads and fish and a finer grid. A finger dragged across the water makes the rings and scares the fish, a tap drops the pebble; the page does not scroll, so the finger belongs to the water.

With reduced motion

The pond keeps still: no waves, fish and pads motionless in their places. Under the pointer only a soft light fades in and out, and a click makes a glint appear and vanish.

Pitfalls

  • A drop on every pointer event makes a dense wake like a boat’s bow and covers the whole pond: drops must be spaced in distance (52 pixels) and in time.
  • Pointer speed computed on events explodes when two arrive in the same frame: measure it frame by frame and smooth it.
  • Drawing the water pixel by pixel at full resolution is slow: draw it as big as the grid and let the canvas stretch it with drawImage.
  • Pads pushed only by the waves all end up against one edge: a weak spring towards their home brings them back, and a push keeps them off the title.
  • A glint drawn with a hard threshold makes blocky steps on calm water: the threshold is a soft ramp and starts only on real slopes.
  • The autopilot sends a pointerleave that bubbles up to html on every change of element: listen only to the one whose target is html, or the pointer vanishes for a frame.

Libraries

GSAP 3.15.0, Fraunces (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.

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

Testing

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