
Standing letters with a long shadow
Text, Scroll, 3D
NewFree
Scroll inside the preview
A minimal-style scroll animation: an empty swimming pool drawn in thin lines, seen from above in perspective. As you scroll down it fills up: the water is a stack of fine blue lines that ripple harder the faster it rises, the floor beneath turns blue and shivers, and the title, lying light on the floor, floats up with the water and gains weight.
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>Lune public baths</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- a made-up public baths, Lune. The stage sticks while you scroll: an empty pool drawn in thin lines, seen in
perspective, fills up. The water is a stack of fine lines that ripple; the title lies on the floor, then floats
up with the water and gains weight as the pool fills. -->
<main>
<section class="corsa" data-corsa>
<div class="palco" data-palco>
<canvas class="vasca" data-vasca aria-hidden="true"></canvas>
<header class="testa">
<a class="marchio" href="#">Lune</a>
<p class="testa__nota">Public baths, open at seven</p>
</header>
<div class="titolo" data-titolo>
<h1 class="titolo__parole" data-parole>Still water.</h1>
</div>
<p class="livello" aria-live="polite"><span class="livello__nome">Depth</span> <span class="livello__cifra" data-livello>0.00 m</span></p>
<p class="nota" data-nota>The lanes stay quiet till nine.</p>
<p class="cenno" data-cenno><span>Scroll to fill</span><svg viewBox="0 0 20 20" aria-hidden="true"><path d="M10 3v13M4.5 10.5 10 16l5.5-5.5"/></svg></p>
</div>
</section>
<footer class="piede">
<p>Lune keeps two lanes free every morning. Bring your own towel.</p>
</footer>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lenis@1.3.26/dist/lenis.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.
19 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 pool that fills up” from Animorio and fit it into my siteThe basin is a box in its own units (8 wide, 14 long, 2.6 deep). A simple camera, raised and tilted down by 0.6 radians, projects every point onto the canvas; on load and on every resize the script projects the eight corners and picks the scale that fits the whole box between the header and the small text at the bottom, on a computer and in the phone box.
A ScrollTrigger without a timeline reads the section’s progress, Lenis smooths the scroll and an exponential average chases it once more (SMOOTH). Between 0.08 and 0.86 of the progress the water level goes from the floor to just under the rim, with power2.inOut.
The surface is a stack of lines from one wall to the other (LINES), each as high as the level plus two slow crossing swells. The size of the swells follows how fast the water rises: it grows quickly and calms down slowly. The waterline runs round the four walls and closes a very light blue wash.
The title is an HTML element placed on every frame on the projected point in the middle of the basin, at the height of the water (or on the floor, when it is empty), scaled by the perspective and moved by a small bob. Its Archivo axes go from weight 220 and width 118 to weight 700 and width 90 as the pool fills.
| Name | File | Default | What it changes |
|---|---|---|---|
DEPTH | script.js | 2.4 | The depth written at the bottom when the pool is full, in metres. |
LANES | script.js | 4 | How many lanes the floor is split into. |
LINES | script.js | 34 | How many fine lines draw the water surface (fewer on a phone). |
RIPPLE | script.js | 1 | How much the water ripples: 0 is a mirror. |
BOB | script.js | 1 | How much the title bobs on the water: 0 keeps it still. |
SMOOTH | script.js | 5 | How quickly the water catches up with the scroll: less is softer. |
RIDE | script.js | 1 | How much scroll it takes to fill: 2 is twice as long. |
For the opening of the site of a swimming pool, a spa, public baths, a hotel with a pool or a swimwear brand: a page that fills with water as you scroll and floats the name up.
The same animation: the basin’s scale is worked out from the window, so the whole pool fits even in the low, wide phone box; there are a few fewer surface lines.
Nothing moves and the scroll is not smoothed: the pool is already full, the water is still as a mirror and the title floats at full weight; the page fades in.
GSAP 3.15.0, ScrollTrigger 3.15.0, Lenis 1.3.26, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 6.4 KB; the libraries: GSAP + ScrollTrigger 45 KB, Lenis 5.3 KB.
Tested on 22 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.