
Words that melt into each other
Text, Scroll, SVG
NewFree
An open music box seen up close: the pinned cylinder plucks the teeth of the comb, the dancer spins in front of the mirror and notes float up. As the spring runs down it slows and stops, then a hand turns the crank and winds it up again. A click winds it at once.
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>Il carillon</title>
<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="banco" data-banco>
<header class="testo">
<p class="marchio">Wren & Willow</p>
<h1 class="titolo">A little tune,<br>kept in a box.</h1>
<p class="frase">Music boxes tuned by hand in our gift shop on Mill Lane. Wind the key and it plays for you.</p>
<button class="carica" type="button" data-carica>
<span class="carica__fondo" aria-hidden="true"></span>
<svg class="carica__chiave" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="2.6" fill="none" stroke="currentColor" stroke-width="1.8" /><path d="M12 9.4V3.6M8.6 3.6h6.8" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" /><path d="M12 14.6v5.2" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" /><circle cx="12" cy="20.4" r="1.6" fill="currentColor" /></svg>
<span class="carica__scritta">Wind it up</span>
</button>
</header>
<div class="palco" data-palco>
<svg class="scena" data-scena viewBox="0 0 900 820" preserveAspectRatio="xMidYMid meet" role="img" aria-label="An open music box: the pinned cylinder turns and plucks the comb, a dancer spins in front of the mirror, notes float up. Click to wind it.">
<defs>
<linearGradient id="g-cilindro" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" style="stop-color: var(--ottone-scuro)" />
<stop offset="0.32" style="stop-color: var(--ottone-chiaro)" />
<stop offset="0.62" style="stop-color: var(--ottone)" />
<stop offset="1" style="stop-color: var(--ottone-scuro)" />
</linearGradient>
<linearGradient id="g-specchio" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" style="stop-color: var(--specchio-chiaro)" />
<stop offset="1" style="stop-color: var(--specchio)" />
</linearGradient>
<linearGradient id="g-fronte" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" style="stop-color: var(--legno)" />
<stop offset="1" style="stop-color: var(--legno-scuro)" />
</linearGradient>
<linearGradient id="g-velluto" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" style="stop-color: var(--velluto-scuro)" />
<stop offset="1" style="stop-color: var(--velluto)" />
</linearGradient>
<clipPath id="c-specchio"><ellipse cx="486" cy="236" rx="114" ry="82" /></clipPath>
<clipPath id="c-vassoio"><polygon points="196,510 704,510 672,394 228,394" /></clipPath>
</defs>
<ellipse class="ombra" cx="458" cy="752" rx="340" ry="22" />
<g class="scatola" data-scatola>
<!-- il coperchio aperto, visto dal davanti: il velluto, lo specchio e il riflesso della ballerina -->
<g data-coperchio>
<polygon class="legno" points="210,384 690,384 676,112 224,112" />
<polygon fill="url(#g-velluto)" points="228,376 672,376 661,128 239,128" />
<path class="cucito" d="M246 366L253 140H647L654 366Z" />
<ellipse class="cornice" cx="486" cy="236" rx="120" ry="88" />
<ellipse fill="url(#g-specchio)" cx="486" cy="236" rx="114" ry="82" />
<g clip-path="url(#c-specchio)">
<g class="riflesso" data-riflesso transform="translate(540 356) scale(-0.92 0.92)"></g>
<path class="luce-specchio" d="M380 330L470 140H500L410 330ZM430 330L520 140H534L444 330Z" />
</g>
</g>
<!-- il piano della scatola e il vassoio col meccanismo, sotto un vetro -->
<polygon class="legno-alto" points="168,522 732,522 692,382 208,382" />
<polygon class="vassoio" points="196,510 704,510 672,394 228,394" />
<g clip-path="url(#c-vassoio)">
<rect class="piastra" x="234" y="404" width="440" height="100" rx="6" />
<!-- la molla nel suo tamburo -->
<g transform="translate(254 452) scale(1 0.8)">
<g data-tamburo>
<circle class="dentatura" r="31" />
<circle class="tamburo" r="26" />
</g>
<path class="molla" data-molla d="" />
<circle class="ottone" r="5" />
</g>
<g data-rinvio>
<circle class="dentatura dentatura--piccola" cx="0" cy="0" r="9" transform="translate(284 432)" />
</g>
<!-- il cilindro con le punte -->
<line class="asse" x1="286" y1="432" x2="622" y2="432" />
<rect x="300" y="414" width="310" height="36" rx="3" fill="url(#g-cilindro)" />
<rect class="ottone-scuro" x="294" y="412" width="8" height="40" rx="2" />
<rect class="ottone-scuro" x="608" y="412" width="8" height="40" rx="2" />
<g data-punte></g>
<!-- il pettine: i denti nascono sulla piastra e arrivano sotto il cilindro -->
<polygon class="pettine" points="296,488 614,472 614,504 296,504" />
<g data-denti></g>
<circle class="vite" cx="318" cy="496" r="3.4" />
<circle class="vite" cx="592" cy="486" r="3.4" />
<!-- il regolatore: la ventola frena la corsa -->
<rect class="staffa" x="630" y="418" width="40" height="52" rx="4" />
<line class="asse" x1="650" y1="414" x2="650" y2="474" />
<rect class="ventola" data-ventola x="638" y="434" width="24" height="12" rx="2" />
<rect class="vetro" x="196" y="394" width="508" height="116" />
</g>
<path class="bordo-vassoio" d="M196 510H704L672 394H228Z" />
<!-- la ballerina sul suo perno, davanti allo specchio -->
<g class="perno" data-ballerina transform="translate(410 400) scale(1.22)"></g>
<!-- il coperchio chiuso, che si alza all'apertura -->
<g data-chiuso>
<polygon class="legno-alto" points="166,524 734,524 694,380 206,380" />
<path class="intarsio" d="M214 510H686L660 394H240Z" />
</g>
<!-- il fronte -->
<rect class="cornicione" x="160" y="512" width="580" height="16" rx="4" />
<rect x="170" y="526" width="560" height="200" fill="url(#g-fronte)" />
<path class="venatura" d="M184 560C300 552 420 572 560 556S700 566 716 560M184 640C320 630 400 652 540 636S690 646 716 642M184 698C300 690 460 708 600 694" />
<rect class="intarsio" x="200" y="550" width="500" height="150" rx="4" />
<rect class="ottone" x="350" y="602" width="200" height="42" rx="7" />
<rect class="incisione" x="357" y="608" width="186" height="30" rx="4" />
<text class="targa" x="450" y="628">WREN & WILLOW</text>
<rect class="zoccolo" x="152" y="720" width="596" height="26" rx="5" />
<!-- la manovella sul fianco destro -->
<rect class="ottone-scuro" x="726" y="609" width="40" height="12" rx="3" />
<g data-manovella>
<circle class="ottone" cx="770" cy="615" r="15" />
<rect class="ottone" x="764" y="609" width="56" height="12" rx="6" />
</g>
<circle class="ottone-scuro" cx="770" cy="615" r="5" />
<circle class="pomello" data-pomello cx="814" cy="615" r="11" />
</g>
<g data-note></g>
<!-- la mano che ricarica -->
<g class="mano" data-mano transform="translate(1300 600)">
<rect class="manica" x="36" y="-21" width="420" height="42" rx="10" />
<rect class="polsino" x="28" y="-24" width="18" height="48" rx="6" />
<path class="guanto" d="M34 -16C18 -22 0 -22 -10 -14C-18 -8 -18 8 -10 14C0 22 18 22 34 16Z" />
<path class="guanto-segno" d="M-5 -9C-1 -5 -1 5 -5 9M4 -12C8 -6 8 6 4 12" />
<path class="guanto" d="M22 -15C14 -30 -2 -31 -7 -23C-3 -19 10 -17 16 -10Z" />
</g>
</svg>
</div>
</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.
37 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 music box” from Animorio and fit it into my siteThe state of the music box is three numbers: G, the degrees turned by the cylinder (always growing), carica, the spring turns left, and mano, from 0 (off stage) to 1 (on the knob). One draw function, called by GSAP’s ticker every frame, works out everything else from them: the pins, the teeth, the fan, the gears, the spring, the crank, the hand and the dancer.
The tune is a string of tooth numbers: each step becomes one or more pins on the cylinder, one every 360 / steps degrees. The cylinder is seen from above: a pin at angle φ is a stroke from r·sin φ to (r + 6)·sin φ, visible only while cos φ is positive, so it looks like a dot in the middle and a dash at the edges. Between 48° and 60° the pin lifts its tooth; when it passes 60° between two frames the tooth snaps: its amplitude goes from 1 to 0 in 1.3 s and the tip moves by amplitude × sin(time × frequency), with a different frequency for each tooth.
The run is a single tween from 0 to 1 of fixed length with a hand-made curve, (t − t⁴/4) / 0.75: its speed is 1 − t³, full at first and then slower and slower down to zero. So the video loop always comes back the same and the cylinder ends on a whole number of turns, with the pins back in place. The dancer turns by G × PIROETTE, the fan by G × 12, the barrel by G / GIRI: at the end they are all back where they started.
The spring is a 110-point spiral with radius 6 + 19·s^p: with a high p (wound) the coils bunch up in the middle, with a low p they open out against the barrel; the inner end turns with the crank, the outer one with the barrel. The crank sits at carica × 360 degrees: unwinding it turns back, winding it turns forward. The hand follows the knob every frame, blending its off-stage position with the knob’s by mano.
A timeline repeating forever: the run, a pause, the hand arriving, three crank turns with a curve that speeds up and slows down at each turn (and an elastic jolt of the box), the hand leaving. The click stops the timeline, brings G inside a whole turn as the new base, has the hand turn only the missing turns and then starts over: no pin jumps. The dancer and her reflection, turned by 180° and mirrored with scale(−0.92, 0.92), are the same shapes moved every frame: the passé knee goes in front of or behind the standing leg, the arms narrow by |cos| and the bun disappears behind the head.
| Name | File | Default | What it changes |
|---|---|---|---|
MELODIA | script.js | 24 passi | One turn of the cylinder: the teeth plucked at each step, from 0 (lowest) to 14 (highest); 3+10 is a chord, - a rest. |
DURATA_CORSA | script.js | 11 | Seconds of music per winding, slowing down to a stop. |
GIRI | script.js | 3 | Cylinder turns per winding, and crank turns the hand makes to wind it again. |
PIROETTE | script.js | 2 | Dancer spins for each turn of the cylinder. |
--legno, --velluto, --ottone | style.css | #8C4A2C, #9B2E4E, #DDAE55 | The box, the lid lining and the brass. |
For gift, toy and vintage shops, baby registries, greeting cards, Christmas or Valentine pages: a scene people happily watch twice and that invites a touch.
The shop copy goes on top and the box below, smaller but the same: same movement, same notes and same hand. It winds by tapping the box or the button.
The music box is already open and still, with the dancer in place and five floating notes that fade in; a click fades them out and fades in five others, with nothing moving.
GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 11 KB; the libraries: GSAP 28 KB.
Tested on 10 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.