
Words that melt into each other
Text, Scroll, SVG
NewFree
Scroll inside the preview
A cake shop’s page: as you scroll, a cake is built on a slowly turning stand. The first sponge drops and bounces, the spatula spreads the cream, berries rain down, the second sponge lands, chocolate glaze runs down the sides in fat drips, the piping bag adds rosettes and the candles go in, lit. At the end two cuts, and a slice slides out and turns to show its layers. Scroll back up and the cake comes apart.
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="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>La torta a strati</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.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>
<!-- la testata della pasticceria inventata -->
<header class="testata">
<p class="marchio">Bramble <span>& Butter</span></p>
<nav class="menu" aria-label="Main">
<a href="#torta">Cakes</a>
<a href="#fine">Order</a>
<a href="#fine">Visit</a>
</nav>
</header>
<main>
<!-- l'apertura -->
<section class="apertura">
<p class="apertura__etichetta" data-entra>A small cake shop on Mill Lane</p>
<h1 class="apertura__titolo">
<span class="riga"><span data-titolo>Built</span></span>
<span class="riga"><span data-titolo><em>layer by layer.</em></span></span>
</h1>
<p class="apertura__testo" data-entra>Our Sunday sponge, from the first bounce to the last candle. Scroll down and watch it rise on the stand.</p>
<p class="apertura__cenno" data-entra>
Scroll to build
<svg viewBox="0 0 24 32" aria-hidden="true"><path d="M12 3V27M4 19L12 28L20 19" /></svg>
</p>
<div class="ciliegie" aria-hidden="true">
<svg class="ciliegia" viewBox="0 0 60 90" data-ciliegia><path d="M31 46C30 30 34 16 46 6" class="ciliegia__gambo" /><path d="M46 6C52 8 56 13 55 18C49 18 46 13 46 6Z" class="ciliegia__foglia" /><circle cx="30" cy="64" r="22" class="ciliegia__corpo" /><path d="M17 58C18 52 22 48 27 47" class="ciliegia__luce" /></svg>
<svg class="ciliegia" viewBox="0 0 60 90" data-ciliegia><path d="M31 46C30 30 34 16 46 6" class="ciliegia__gambo" /><path d="M46 6C52 8 56 13 55 18C49 18 46 13 46 6Z" class="ciliegia__foglia" /><circle cx="30" cy="64" r="22" class="ciliegia__corpo" /><path d="M17 58C18 52 22 48 27 47" class="ciliegia__luce" /></svg>
<svg class="ciliegia" viewBox="0 0 60 90" data-ciliegia><path d="M31 46C30 30 34 16 46 6" class="ciliegia__gambo" /><path d="M46 6C52 8 56 13 55 18C49 18 46 13 46 6Z" class="ciliegia__foglia" /><circle cx="30" cy="64" r="22" class="ciliegia__corpo" /><path d="M17 58C18 52 22 48 27 47" class="ciliegia__luce" /></svg>
</div>
</section>
<!-- la torta: il palco resta fermo e, scorrendo, si monta strato dopo strato -->
<section class="storia" id="torta" data-storia>
<div class="palco">
<div class="racconto">
<nav class="ricetta" aria-label="Steps">
<button type="button" data-voce>Sponge</button>
<button type="button" data-voce>Cream</button>
<button type="button" data-voce>Berries</button>
<button type="button" data-voce>Stack</button>
<button type="button" data-voce>Glaze</button>
<button type="button" data-voce>Pipe</button>
<button type="button" data-voce>Candles</button>
<button type="button" data-voce>Slice</button>
</nav>
<div class="passi">
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The sponge</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Drop the</span></span>
<span class="riga"><span data-riga>first <em>layer.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Vanilla sponge, baked the night before so it holds its shape. It lands, it bounces, it settles.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The cream</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Spread it thin,</span></span>
<span class="riga"><span data-riga>turn the <em>stand.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Mascarpone from the middle out. The stand does the turning, the spatula stays still.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The berries</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Let it rain</span></span>
<span class="riga"><span data-riga><em>berries.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Raspberries, blueberries and strawberries, wherever they land. No two cakes look the same inside.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The stack</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Second layer,</span></span>
<span class="riga"><span data-riga><em>gently.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Just enough weight for the cream to peek out at the edges, and no more.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The glaze</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Pour it warm,</span></span>
<span class="riga"><span data-riga>let it <em>drip.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Dark chocolate, warm but never hot, so it rolls over the edge in slow, fat drips.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The piping</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>One swirl</span></span>
<span class="riga"><span data-riga>per <em>turn.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Raspberry buttercream round the rim. The bag stays put and the stand brings every spot to it.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The candles</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Light them</span></span>
<span class="riga"><span data-riga><em>all.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Striped candles in the middle. Make a wish before the knife comes out.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The slice</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Two cuts,</span></span>
<span class="riga"><span data-riga>lift it <em>out.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Sponge, cream, berries, sponge, glaze. Scroll back up and the cake comes apart again.</p>
</article>
</div>
<p class="misura">On the stand <strong><span data-peso>0</span> g</strong></p>
</div>
<svg class="scena" data-scena viewBox="0 130 600 630" preserveAspectRatio="xMidYMax meet" aria-hidden="true">
<defs>
<linearGradient id="grad-alzata" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="stop-alzata-scura" />
<stop offset="0.4" class="stop-alzata" />
<stop offset="0.6" class="stop-alzata-chiara" />
<stop offset="1" class="stop-alzata-scura" />
</linearGradient>
<linearGradient id="grad-acciaio" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" class="stop-acciaio-chiaro" />
<stop offset="0.5" class="stop-acciaio" />
<stop offset="1" class="stop-acciaio-scuro" />
</linearGradient>
<linearGradient id="grad-rame" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="stop-rame-scuro" />
<stop offset="0.45" class="stop-rame" />
<stop offset="1" class="stop-rame-scuro" />
</linearGradient>
</defs>
<!-- l'alzata: piede, gambo e piatto; le scanalature del bordo girano -->
<g data-alzata>
<ellipse cx="300" cy="744" rx="150" ry="16" class="ombra-alzata" />
<path d="M195 718V730A105 22 0 0 0 405 730V718Z" fill="url(#grad-alzata)" />
<ellipse cx="300" cy="718" rx="105" ry="22" class="alzata-sopra" />
<path d="M276 600C276 640 286 660 286 680C286 700 240 706 222 716C250 726 350 726 378 716C360 706 314 700 314 680C314 660 324 640 324 600Z" fill="url(#grad-alzata)" />
<path d="M100 590V604A200 60 0 0 0 500 604V590Z" fill="url(#grad-alzata)" />
<path class="scanalature" data-scanalature />
<ellipse cx="300" cy="590" rx="200" ry="60" class="alzata-sopra" />
<ellipse cx="300" cy="590" rx="186" ry="54" class="alzata-incavo" />
</g>
<!-- la torta (i pezzi li disegna lo script) -->
<ellipse class="ombra-torta" data-ombra />
<g data-torta></g>
<g data-fetta></g>
<!-- gli attrezzi -->
<g data-spatola>
<path d="M150 0C186 -4 196 -30 214 -54" class="spatola-collo" />
<path d="M0 -5C-7 -5 -9 5 0 6L156 7C162 7 164 -6 156 -6Z" fill="url(#grad-acciaio)" class="spatola-lama" />
<path d="M206 -46L282 -100" class="spatola-manico" />
</g>
<g data-pentola>
<g data-pentola-corpo>
<path d="M-96 18L-196 4" class="pentola-manico" />
<path d="M2 -3C-4 0 -8 3 -10 8L-12 52C-12 62 -20 68 -30 68H-86C-96 68 -104 62 -104 52L-104 6C-104 2 -100 0 -96 0H-14C-8 -2 -3 -4 2 -3Z" fill="url(#grad-rame)" class="pentola" />
<path d="M-100 4H-12" class="pentola-bordo" />
</g>
</g>
<path class="filo-glassa" data-filo />
<g data-sac>
<path d="M-8 -16C-30 -56 -44 -104 -26 -142L44 -152C58 -112 40 -56 8 -16Z" class="sac" />
<path d="M-26 -142C-14 -150 30 -158 44 -152L48 -166C30 -172 -12 -166 -28 -156Z" class="sac-nodo" />
<path d="M-14 -40C-2 -38 8 -40 18 -46" class="sac-piega" />
<path d="M0 2L-9 -18H9Z" fill="url(#grad-acciaio)" />
</g>
<g data-coltello-clip-g>
<clipPath id="taglio"><path data-coltello-clip /></clipPath>
<g clip-path="url(#taglio)">
<path class="coltello-lama" fill="url(#grad-acciaio)" data-lama />
<path class="coltello-manico" data-manico />
</g>
</g>
<!-- dove il puntatore fa tremare la torta -->
<ellipse cx="300" cy="540" rx="210" ry="150" class="presa" data-presa />
</svg>
</div>
</section>
<footer class="fine" id="fine">
<p class="fine__frase">Your slice is waiting. <em>Come by on Sunday.</em></p>
<a class="fine__bottone" href="#torta"><span>Order a cake</span></a>
</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.
98 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 layer cake that builds as you scroll” from Animorio and fit it into my siteThe section is SCROLL_LENGTH screens tall and holds a sticky stage 100lvh tall: the story on the left, on the right an SVG with a fixed viewBox and preserveAspectRatio xMidYMax meet, so the stand stays sitting at the bottom at any size. The stand is drawn once; the cake, the berries, the rosettes and the candles are made by the script, and the tools (spatula, pan, piping bag, knife) sit on top of everything.
Everything that moves is a number in one object: how far each sponge has fallen, how much it wobbles, how far the cream has spread, the glaze, the drips, the piping bag, the turn of the stand, the knife, the slice. A single paused timeline moves them, each with its own curve (bounce.out for the sponges and the berries, back.out for the tools coming in, elastic.out for the flames). A tween takes its time from 0 to the end with a scrubbed ScrollTrigger: scroll up and the timeline goes back and the cake comes apart.
Every layer is a squashed cylinder: an ellipse on top (the radius times 0.3 in height) and the band in front, the angles from 0 to 180 degrees. A GSAP ticker rebuilds the paths every frame from the bottom, height and radius of each layer: a sponge landing drops and widens on a damped sine. Everything on the cake (crumbs, berries, drips, rosettes, candles) has its own angle: the stand’s turn is added, and what goes round the back disappears or is sorted behind the rest.
The rosettes don’t chase the bag: the stand turns a full 360 degrees while the bag stays over one spot of the rim. Each rosette’s angle is worked out so that it passes under the nozzle exactly when its turn comes, and it grows there with elastic.out. The candles sit on a small circle, turned so that at the end none of them is where the knife will go.
After the two cuts the same function draws two pieces: the cake with the gap (the angles from 108 to 432 degrees) and the slice (from 72 to 108). Each piece has the faces of its cut, quadrilaterals from the centre to the edge, shown only when they face us, with the berries and the sponge’s holes inside. The slice moves and its angle drops by 108 degrees: at the end its cut faces us straight on. The knife is trimmed by a clipPath that hides the part already inside the cake.
| Name | File | Default | What it changes |
|---|---|---|---|
SCROLL_LENGTH | script.js | 7 | How many screens of scrolling the whole cake takes: more is slower. |
BERRIES | script.js | 18 | How many berries rain on the cream. |
DRIPS | script.js | 14 | How many drips of glaze run down the sides. |
DRIP_LENGTH | script.js | 1 | How far the drips run: 0.4 short, 1.6 almost to the plate. |
ROSETTES | script.js | 12 | How many buttercream rosettes round the rim. |
CANDLES | script.js | 5 | How many candles in the middle (7 at most, so the knife can pass between two). |
SPIN | script.js | 1 | How far the stand turns while you scroll: 0 keeps it still (it still goes round once for the rosettes). |
SQUASH | script.js | 1 | How much the sponges squash and wobble when they land; next to it is CAKE_GRAMS for the counter. |
--glassa | style.css | #4a2216 | The colour of the glaze; next to it are those of the sponge, the cream, the berries, the rosettes, the candles and the stand. |
For anyone who sells or tells about something built in layers: a cake shop, made-to-order cakes, a caterer, a cake decorating course, a recipe to follow step by step, but also a product made of stacked parts, like a sandwich, a mattress or a plan with its tiers.
The same animation with the sizes adapted: the story sits at the top, smaller, with the step names on two lines and the grams in small type below, and the stand in the room left, resting on the bottom of the screen. A tap on the cake makes it wobble, a tap on the cherries makes them hop.
No falling, no dripping, no turning, no smooth scrolling: at every step the cake and the text fade out and come back with the step already done (the sponge in place, the cream spread, the berries, the glaze run down, the rosettes, the candles lit with still flames, the slice out). The opening title and cherries fade in too.
GSAP 3.15.0, Lenis 1.3.26, Fraunces (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 19 KB; the libraries: GSAP + ScrollTrigger 45 KB, Lenis 5.3 KB.
Tested on 11 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.