
Parole che si fondono
Testo, Scroll, SVG
NuovaGratis
Scorri dentro l’anteprima
La pagina di una torrefazione: scendendo, una tazza vista di tre quarti si riempie. Prima l’espresso cade a filo dai due beccucci e sale la crema, poi una lattiera entra, si inclina e versa il latte, dondola e disegna una foglia sulla superficie, e alla fine sale il vapore a riccioli. Tornando su la tazza si svuota.
Una cartella che funziona da sola: index.html, style.css, script.js e le librerie da CDN. Nelle schede React e Vue la stessa demo è già un componente, che spegne le sue animazioni quando esce dalla pagina.
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Il caffè allo scroll</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 torrefazione inventata -->
<header class="testata">
<p class="marchio">Ashgrove <span>Roasters</span></p>
<nav class="menu" aria-label="Main">
<a href="#tazza">The cup</a>
<a href="#fine">Beans</a>
<a href="#fine">Visit</a>
</nav>
</header>
<main>
<!-- l'apertura -->
<section class="apertura">
<p class="apertura__etichetta" data-entra>Small-batch coffee, roasted every Tuesday</p>
<h1 class="apertura__titolo">
<span class="riga"><span data-titolo>Pulled slow,</span></span>
<span class="riga"><span data-titolo>poured <em>by hand.</em></span></span>
</h1>
<p class="apertura__testo" data-entra>Our house flat white, from the first drop to the last curl of steam. Scroll down and watch it fill.</p>
<p class="apertura__cenno" data-entra>
Scroll to brew
<svg viewBox="0 0 24 32" aria-hidden="true"><path d="M12 3V27M4 19L12 28L20 19" /></svg>
</p>
<div class="chicchi" aria-hidden="true">
<svg class="chicco" viewBox="0 0 60 80" data-chicco><ellipse cx="30" cy="40" rx="26" ry="36" class="chicco__corpo" /><path d="M30 6C14 26 46 52 30 74" class="chicco__solco" /></svg>
<svg class="chicco" viewBox="0 0 60 80" data-chicco><ellipse cx="30" cy="40" rx="26" ry="36" class="chicco__corpo" /><path d="M30 6C14 26 46 52 30 74" class="chicco__solco" /></svg>
<svg class="chicco" viewBox="0 0 60 80" data-chicco><ellipse cx="30" cy="40" rx="26" ry="36" class="chicco__corpo" /><path d="M30 6C14 26 46 52 30 74" class="chicco__solco" /></svg>
</div>
</section>
<!-- la tazza: il palco resta fermo e, scorrendo, si riempie -->
<section class="storia" id="tazza" data-storia>
<div class="palco">
<div class="racconto">
<nav class="ricetta" aria-label="Steps">
<button type="button" data-voce>Shot</button>
<button type="button" data-voce>Crema</button>
<button type="button" data-voce>Pour</button>
<button type="button" data-voce>Leaf</button>
<button type="button" data-voce>Steam</button>
</nav>
<div class="passi">
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The shot</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Eighteen grams,</span></span>
<span class="riga"><span data-riga>a thin <em>thread.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Slow and steady from both spouts. If it gushes the grind is too coarse, if it drips it is too fine.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The crema</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Tiger stripes</span></span>
<span class="riga"><span data-riga>on <em>top.</em></span></span>
</h2>
<p class="passo__testo" data-linea>The oils rise into a hazelnut foam. The last drops fall and the machine goes quiet.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The pour</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Milk under,</span></span>
<span class="riga"><span data-riga>not <em>over.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Start high, so the milk dives beneath the crema and lifts the colour from below.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The leaf</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Rock the jug,</span></span>
<span class="riga"><span data-riga>pull it <em>through.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Drop close, rock side to side as you drift back, then lift and draw one line down the middle. A rosetta.</p>
</article>
<article class="passo" data-passo>
<p class="passo__etichetta" data-linea>The steam</p>
<h2 class="passo__titolo">
<span class="riga"><span data-riga>Drink it while</span></span>
<span class="riga"><span data-riga>it <em>curls.</em></span></span>
</h2>
<p class="passo__testo" data-linea>Warm enough to taste the sweetness, never scalding. Scroll back up and the cup empties again.</p>
</article>
</div>
<p class="misura">In the cup <strong><span data-ml>0</span> ml</strong></p>
</div>
<svg class="scena" data-scena viewBox="0 0 600 760" preserveAspectRatio="xMidYMax meet" aria-hidden="true">
<defs>
<clipPath id="bocca"><ellipse cx="300" cy="440" rx="145" ry="57" /></clipPath>
<linearGradient id="grad-corpo" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="stop-tazza-ombra" />
<stop offset="0.38" class="stop-tazza" />
<stop offset="0.62" class="stop-tazza" />
<stop offset="1" class="stop-tazza-ombra" />
</linearGradient>
<linearGradient id="grad-interno" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" class="stop-tazza-ombra" />
<stop offset="1" class="stop-tazza" />
</linearGradient>
<linearGradient id="grad-piattino" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="stop-tazza-ombra" />
<stop offset="0.45" class="stop-tazza" />
<stop offset="1" class="stop-tazza-ombra" />
</linearGradient>
<linearGradient id="grad-acciaio" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="stop-acciaio-scuro" />
<stop offset="0.35" class="stop-acciaio" />
<stop offset="0.55" class="stop-acciaio-chiaro" />
<stop offset="1" class="stop-acciaio-scuro" />
</linearGradient>
<filter id="sfuma" x="-50%" y="-20%" width="200%" height="140%"><feGaussianBlur stdDeviation="2.6" /></filter>
<linearGradient id="grad-macchina" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" class="stop-macchina" stop-opacity="0" />
<stop offset="0.6" class="stop-macchina" />
</linearGradient>
<radialGradient id="grad-crema" cx="0.5" cy="0.5" r="0.5">
<stop offset="0" class="stop-crema-chiara" />
<stop offset="0.7" class="stop-crema" />
<stop offset="1" class="stop-crema-bordo" />
</radialGradient>
<radialGradient id="grad-misto" cx="0.5" cy="0.5" r="0.5">
<stop offset="0" class="stop-misto" />
<stop offset="0.75" class="stop-misto" stop-opacity="0.85" />
<stop offset="1" class="stop-misto" stop-opacity="0" />
</radialGradient>
</defs>
<!-- il piattino -->
<g data-tazza>
<ellipse cx="300" cy="656" rx="238" ry="92" class="piattino-ombra" />
<ellipse cx="300" cy="646" rx="236" ry="90" fill="url(#grad-piattino)" class="piattino" />
<ellipse cx="300" cy="640" rx="156" ry="56" class="piattino-incavo" />
<ellipse cx="300" cy="638" rx="124" ry="38" class="ombra-tazza" />
<!-- il manico -->
<path d="M446 478C522 466 540 566 436 576" class="manico" />
<path d="M446 478C522 466 540 566 436 576" class="manico-luce" />
<!-- l'interno e la parete dietro -->
<ellipse cx="300" cy="440" rx="150" ry="60" fill="url(#grad-interno)" />
<!-- la superficie: tutto quello che sta dentro è disegnato visto dall'alto (raggio 100) e schiacciato -->
<g clip-path="url(#bocca)">
<g data-superficie>
<circle r="100" class="espresso" />
<circle r="100" fill="url(#grad-crema)" data-crema />
<g data-macchie></g>
<circle r="100" fill="url(#grad-misto)" data-misto />
<g data-cerchi></g>
<g data-rosetta></g>
<path class="gambo" data-gambo />
</g>
</g>
<path d="M150 440A150 60 0 0 1 450 440" class="bordo" />
<!-- il vapore -->
<g data-vapore filter="url(#sfuma)"></g>
<!-- i fili che cadono -->
<path class="filo-caffe" data-filo />
<path class="filo-caffe" data-filo />
<ellipse rx="2.6" ry="3.8" class="goccia" data-goccia />
<ellipse rx="2.6" ry="3.8" class="goccia" data-goccia />
<path class="filo-latte" data-filo-latte />
<!-- la parete davanti -->
<path d="M150 440C150 548 196 632 300 636C404 632 450 548 450 440A150 60 0 0 1 150 440Z" fill="url(#grad-corpo)" class="corpo" />
<path d="M450 440A150 60 0 0 1 150 440" class="bordo bordo--davanti" />
<path d="M174 506C184 562 210 600 246 620" class="riflesso" />
</g>
<!-- la macchina: il gruppo e il portafiltro con i due beccucci -->
<g data-macchina>
<rect x="160" y="-60" width="280" height="110" rx="22" fill="url(#grad-macchina)" />
<rect x="160" y="18" width="280" height="10" class="macchina-riga" />
<rect x="222" y="48" width="156" height="50" rx="9" fill="url(#grad-acciaio)" />
<rect x="40" y="104" width="204" height="24" rx="12" transform="rotate(-5 244 116)" class="legno" />
<path d="M228 96H372L364 134C362 142 356 146 348 146H252C244 146 238 142 236 134Z" fill="url(#grad-acciaio)" />
<path d="M279 146H293L291 160H281Z" class="beccuccio" />
<path d="M307 146H321L319 160H309Z" class="beccuccio" />
</g>
<!-- la lattiera: il becco è nell'origine, così si inclina attorno al punto da cui esce il latte -->
<g data-brocca>
<g data-brocca-corpo>
<path d="M-131 30C-178 30 -180 112 -129 114" class="manico-brocca" />
<path d="M4 0C-6 2 -11 6 -13 13L-21 132C-22 144 -31 150 -43 150H-112C-124 150 -132 144 -132 132L-130 13C-130 8 -126 4 -120 4Z" fill="url(#grad-acciaio)" class="brocca" />
<path d="M-126 7H-12" class="brocca-bordo" />
<path d="M-104 22L-108 136" class="brocca-luce" />
</g>
</g>
<!-- dove il puntatore scuote la tazza -->
<ellipse cx="300" cy="560" rx="220" ry="150" class="presa" data-presa />
</svg>
</div>
</section>
<footer class="fine" id="fine">
<p class="fine__frase">Your cup is ready. <em>Come by for the real one.</em></p>
<a class="fine__bottone" href="#tazza"><span>Order the beans</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>Cambia valori, colori e testi con le manopole e guarda l’animazione rispondere dal vivo. Oppure scrivi tu nel codice. Poi scarica la cartella con le tue modifiche.
74 valori da cambiare
Col connettore di Animorio, Claude Code la prende da qui con tutta la sua guida e la adatta al tuo progetto. Incolla questa richiesta:
Prendi «Il caffè allo scroll» da Animorio e adattala al mio sitoLa sezione è alta SCROLL_LENGTH schermi e dentro c’è un palco sticky alto 100lvh: a sinistra il racconto, a destra un SVG con viewBox fisso (600 × 760) e preserveAspectRatio xMidYMax meet, così la tazza resta appoggiata in basso a ogni misura. Il disegno è a strati: piattino, manico, interno della tazza, superficie del caffè, bordo dietro, vapore, fili, parete davanti e bordo davanti. I fili stanno fra il bordo dietro e la parete davanti: in alto passano sopra la tazza, in fondo spariscono dietro la parete.
Tutto quello che si muove è un numero da 0 a 1 in un oggetto: quanto è sceso il filo, quanto si è staccata la coda, il livello, la crema, la macchina, la lattiera, l’inclinazione, il latte, la foglia, il vapore. Una sola timeline in pausa li muove, ognuno con la sua curva (back.in per la macchina che sale, back.out per la lattiera che entra, elastic.out per ogni strato della foglia). Un tween porta la sua time da 0 alla fine con uno ScrollTrigger in scrub, da quando la sezione tocca il bordo alto a quando finisce: scorrendo su la timeline va indietro e la tazza si svuota.
Il caffè, la crema, il latte che schiarisce, i cerchi e la foglia sono disegnati in un gruppo come se li guardassimo dall’alto, in un cerchio di raggio 100. Un ticker di GSAP, a ogni fotogramma, gli dà translate, scale e rotate: il centro scende e il raggio si stringe quando il livello è basso, e lo scale verticale (0,4 del raggio) lo schiaccia nell’ellisse della bocca. Un clipPath con l’ellisse della bocca taglia quello che starebbe dietro la parete. I fili sono forme piene rifatte a ogni fotogramma: una striscia che si assottiglia, con un seno che la fa tremare, fra la coda e la punta.
Ogni strato della rosetta è una mezzaluna fatta di quattro curve quadratiche: larga e alta lontano, stretta vicino alla lattiera. Gli strati si sovrappongono, quindi si vede solo il bordo di ognuno, sottile e color crema (vector-effect: non-scaling-stroke, così non si schiaccia). Uno strato cresce da v = 0 a 1 con elastic.out, e ogni strato aperto spinge avanti quelli più lontani di poco. Nello stesso tempo il punto in cui cade il latte va da lontano a vicino oscillando con un seno, e la lattiera lo segue. Poi la linea centrale corre verso il fondo e, dove passa, sposta in avanti la punta di ogni strato.
Ogni ricciolo è un tracciato con pathLength=1: una sua timeline infinita fa scorrere un tratto lungo 0,55 con stroke-dashoffset e lo sposta di lato. Il gruppo ha un filtro di sfocatura e la sua opacità segue il vapore della timeline. Il puntatore sulla tazza porta un numero slosh a ±1 e lo riporta a 0 con elastic.out: la tazza ruota appena attorno al piattino e la superficie scivola e gira. Il testo di ogni passaggio sta nella stessa timeline: le righe escono verso l’alto con power3.in ed entrano dal basso con expo.out.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
LEAVES | script.js | 7 | Quanti strati ha la foglia di latte. |
WIGGLE | script.js | 1 | Quanto dondola la lattiera mentre disegna la foglia: 0 ferma. |
SCROLL_LENGTH | script.js | 6 | Quanti schermi di scorrimento dura tutta la tazza: di più è più lenta. |
STEAM | script.js | 3 | Quanti riccioli di vapore salgono alla fine. |
STEAM_SPEED | script.js | 1 | Quanto in fretta sale il vapore. |
SLOSH | script.js | 1 | Quanto oscilla la tazza quando il puntatore la tocca. |
CUP_ML | script.js | 180 | I millilitri della tazza piena, per il contatore; accanto c’è SHOT_ML per l’espresso. |
--crema | style.css | #b8743c | Il colore della crema; accanto ci sono quelli dell’espresso, del latte, della tazza e della lattiera. |
Per chi vende o racconta qualcosa che si prepara in passaggi: una torrefazione, un bar, una marca di macchine da caffè o di latte, una scuola di latte art, una ricetta da seguire passo passo, o qualunque prodotto da riempire scorrendo, come una bottiglia o un vasetto.
La stessa animazione con le misure adattate: il racconto sta in alto, più piccolo, con sotto il contatore dei millilitri in piccolo, e la tazza nello spazio che resta, appoggiata al fondo dello schermo. Un tocco sulla tazza la fa oscillare, uno sui chicchi li fa saltare.
Niente versamenti, niente dondolii, niente scorrimento morbido: a ogni passaggio la tazza e il testo spariscono in dissolvenza e tornano con il passaggio già compiuto (l’espresso nella tazza, la crema, il latte versato, la foglia, il vapore fermo). Anche il titolo e i chicchi dell’apertura compaiono in dissolvenza.
GSAP 3.15.0, Lenis 1.3.26, Fraunces (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 13 KB; le librerie: GSAP + ScrollTrigger 45 KB, Lenis 5,3 KB.
Provata il 10 ottobre 2026
Puoi usarla nei tuoi progetti e in quelli dei tuoi clienti. Non puoi rivenderla né ridistribuirla così com’è. GSAP resta sotto la sua licenza Standard. Licenza completa.
Con l’email e la password del tuo account.
oppure con l’email
Hai fatto l’accesso come .
Con l’account scarichi lo zip di ogni animazione e di ogni pacchetto, gratis.