
Words that melt into each other
Text, Scroll, SVG
NewFree
Scroll inside the preview
The page of a synthesizer oscillator, in the minimal style: as you scroll a chain of circles turns, each on the tip of the one before, and the tip of the last one writes a wave. With one circle it is a pure sine; every new circle pops in with a small spring and the wave gets squarer, until it almost fills a blue dashed square. The word below widens and gains weight with it.
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 wave made of circles</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- the product page of a made-up synthesizer maker, Odalo. Scrolling turns a chain of circles, each spinning on the
tip of the one before, and the tip of the last one writes a wave. One circle writes a pure sine; every new circle
pops in on the tip of the chain and the wave gets squarer, until it almost fills a thin dashed square. The word
under it widens and gains weight with the wave -->
<main>
<section class="apertura">
<p class="piccolo">Odalo, synthesizers</p>
<h1 class="titolo">Every sound<br>is made of circles.</h1>
<p class="piccolo piccolo--tenue">Scroll to add them.</p>
</section>
<section class="racconto" data-racconto>
<div class="palco" data-palco>
<header class="testa">
<p class="marchio">Odalo</p>
<p class="piccolo piccolo--tenue">Square One oscillator</p>
</header>
<svg class="tavola" data-tavola aria-hidden="true">
<g data-quadro>
<line class="asse" data-asse></line>
<path class="bersaglio" data-bersaglio></path>
<g data-cerchi></g>
<line class="filo" data-filo></line>
<path class="onda" data-onda></path>
</g>
</svg>
<div class="scritta">
<p class="conto" data-conto aria-live="polite">1 circle</p>
<p class="parola" data-parola>square</p>
</div>
</div>
</section>
<section class="apertura apertura--fine">
<h2 class="titolo titolo--medio">Square One.<br>Out in the spring.</h2>
</section>
</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="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.
21 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 wave made of circles” from Animorio and fit it into my siteA square wave is a sum of odd sine waves: sin(x) + sin(3x)/3 + sin(5x)/5 and so on, times 4/π. Each term is a circle with a radius of 1/n spinning n times faster than the first, resting on the tip of the arm of the one before. The script draws the circles and the arms in an SVG group and, every frame, redraws the wave with 260 points: the height at each point is the same sum worked out at a slightly older phase.
Everything is drawn in a frame of its own: u along the wave, v its height. On a computer the group is only moved and the wave runs to the right; on a phone, where there is no width, the same group is turned by 90 degrees and the wave runs down the screen, without rewriting anything. The big circle’s radius and the graph’s start and length are worked out again on every ScrollTrigger refresh and on every resize.
The timeline, tied to the scroll with scrub SCRUB, carries a number from 0 to 1 that becomes the phase: the big circle makes TURNS turns over the whole story. Each circle also has a weight w from 0 to 1 that multiplies its radius: new circles arrive with a tween of w on the POP curve, a back.out that takes it a little past 1 and back. Since the wave uses w too, the wave makes the same spring.
The dashed square is the sign of the same base sine wave (+1 or −1), drawn with horizontal and vertical strokes where the sign flips, so it runs along with the wave. The dotted blue thread goes from the tip of the last arm to the start of the wave: that is where you see that the wave is written by the circles.
The word square uses Anybody, whose wdth axis runs from 50 to 150. The sum of the circles’ weights says how square the wave is: with one circle the word is at 50 wide and almost weightless, with all the circles at 150 and full. The count above the word changes when a circle is half grown.
| Name | File | Default | What it changes |
|---|---|---|---|
CIRCLES | script.js | 8 | How many circles at the end: the more there are, the squarer the wave. |
TURNS | script.js | 7 | How many turns the big circle makes over the whole story. |
PERIODS | script.js | 2 | How many waves fit in the graph. |
POP | script.js | 'back.out(1.8)' | How each new circle grows in: the number in brackets is how far it overshoots before coming back. |
TARGET | script.js | true | The dashed square to aim for. |
SCRUB | script.js | 0.6 | How many seconds the drawing takes to catch up with the scroll. |
For the page of a musical instrument, an audio plugin, a maths or physics course, or any product that explains itself by showing how it is built from simple pieces: one circle at a time, until the shape is the right one.
The same, turned on its side: the circles sit at the top in the middle and the wave runs down the screen, with a vertical thread; the word sits at the bottom and takes almost the full width when it is square.
Nothing spins and nothing grows: the chain stands still at a fixed phase and each new circle, with its wave, appears at once behind a short cross-fade; the word changes width and weight in steps with the count.
GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Anybody (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 5.7 KB; the libraries: GSAP + ScrollTrigger 45 KB.
Tested on 19 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.