
Il pulsante d'acqua
Pulsanti, SVG, Fisica, Hover
NuovaGratis
Le voci di un menu sono etichette di lino appese a un filo da bucato con le mollette di legno: il filo è una corda vera calcolata a ogni fotogramma, e le etichette ci pendono come pendoli. Puntandone una il filo cede sotto di lei e le vicine scivolano e dondolano; cliccandola viene tirata giù, il filo rimbalza e l'etichetta si tinge d'indaco dal basso.
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="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The clothesline menu</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- a menu hung on a washing line: the line is a rope of points worked out by hand (verlet), each link is a linen
care label held by a wooden peg, and the labels swing from the line like pendulums. Pointing at a label pulls
it down, a click tugs it and dyes it indigo -->
<nav class="line" aria-label="Main" data-line>
<svg class="line__rope" aria-hidden="true" data-rope></svg>
<ul class="line__tags">
<li><a class="tag" href="#shop" aria-current="page" data-tag>
<span class="tag__cloth">
<span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 8l2.2 10.5h13.6L21 8"/><path d="M3.6 10.5c1.5-1.2 3-1.2 4.4 0s2.9 1.2 4 0 2.9-1.2 4 0 2.9 1.2 4.4 0"/></svg>
<span class="tag__name">Shop</span>
</span>
<span class="tag__dye" aria-hidden="true" data-dye><span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24"><path d="M3 8l2.2 10.5h13.6L21 8"/><path d="M3.6 10.5c1.5-1.2 3-1.2 4.4 0s2.9 1.2 4 0 2.9-1.2 4 0 2.9 1.2 4.4 0"/></svg>
<span class="tag__name">Shop</span>
</span></span>
</span>
<svg class="tag__peg" viewBox="0 0 18 44" aria-hidden="true"><rect class="peg__shade" x="1.6" y="3.6" width="16" height="41.4" rx="3"/><path class="peg__wood" d="M2.4 1h5.2a1.4 1.4 0 0 1 1.4 1.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 2.4 1z"/><path class="peg__wood peg__wood--back" d="M10.4 1h5.2A1.4 1.4 0 0 1 17 2.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 10.4 1z"/><path class="peg__grain" d="M4.3 5v8M13.7 6v6M4.6 26v11M13.4 27v10"/><rect class="peg__spring" x="0.4" y="16" width="17.2" height="5.4" rx="2.7"/><path class="peg__coil" d="M4 16.4v4.6M7 16.4v4.6M10 16.4v4.6M13 16.4v4.6"/></svg>
</a></li>
<li><a class="tag" href="#bedding" data-tag data-autoclic>
<span class="tag__cloth">
<span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="3.5" width="17" height="17" rx="1"/><circle cx="12" cy="12" r="5.6"/></svg>
<span class="tag__name">Bedding</span>
</span>
<span class="tag__dye" aria-hidden="true" data-dye><span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24"><rect x="3.5" y="3.5" width="17" height="17" rx="1"/><circle cx="12" cy="12" r="5.6"/></svg>
<span class="tag__name">Bedding</span>
</span></span>
</span>
<svg class="tag__peg" viewBox="0 0 18 44" aria-hidden="true"><rect class="peg__shade" x="1.6" y="3.6" width="16" height="41.4" rx="3"/><path class="peg__wood" d="M2.4 1h5.2a1.4 1.4 0 0 1 1.4 1.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 2.4 1z"/><path class="peg__wood peg__wood--back" d="M10.4 1h5.2A1.4 1.4 0 0 1 17 2.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 10.4 1z"/><path class="peg__grain" d="M4.3 5v8M13.7 6v6M4.6 26v11M13.4 27v10"/><rect class="peg__spring" x="0.4" y="16" width="17.2" height="5.4" rx="2.7"/><path class="peg__coil" d="M4 16.4v4.6M7 16.4v4.6M10 16.4v4.6M13 16.4v4.6"/></svg>
</a></li>
<li><a class="tag" href="#kitchen" data-tag>
<span class="tag__cloth">
<span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 17.5h18c0-4.6-2.6-8.5-8-8.5H8.5"/><path d="M8.5 9V6.5h7"/><circle cx="12" cy="14" r="0.9"/></svg>
<span class="tag__name">Kitchen</span>
</span>
<span class="tag__dye" aria-hidden="true" data-dye><span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24"><path d="M3 17.5h18c0-4.6-2.6-8.5-8-8.5H8.5"/><path d="M8.5 9V6.5h7"/><circle cx="12" cy="14" r="0.9"/></svg>
<span class="tag__name">Kitchen</span>
</span></span>
</span>
<svg class="tag__peg" viewBox="0 0 18 44" aria-hidden="true"><rect class="peg__shade" x="1.6" y="3.6" width="16" height="41.4" rx="3"/><path class="peg__wood" d="M2.4 1h5.2a1.4 1.4 0 0 1 1.4 1.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 2.4 1z"/><path class="peg__wood peg__wood--back" d="M10.4 1h5.2A1.4 1.4 0 0 1 17 2.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 10.4 1z"/><path class="peg__grain" d="M4.3 5v8M13.7 6v6M4.6 26v11M13.4 27v10"/><rect class="peg__spring" x="0.4" y="16" width="17.2" height="5.4" rx="2.7"/><path class="peg__coil" d="M4 16.4v4.6M7 16.4v4.6M10 16.4v4.6M13 16.4v4.6"/></svg>
</a></li>
<li><a class="tag" href="#journal" data-tag>
<span class="tag__cloth">
<span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3.8l9 15.7H3z"/></svg>
<span class="tag__name">Journal</span>
</span>
<span class="tag__dye" aria-hidden="true" data-dye><span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24"><path d="M12 3.8l9 15.7H3z"/></svg>
<span class="tag__name">Journal</span>
</span></span>
</span>
<svg class="tag__peg" viewBox="0 0 18 44" aria-hidden="true"><rect class="peg__shade" x="1.6" y="3.6" width="16" height="41.4" rx="3"/><path class="peg__wood" d="M2.4 1h5.2a1.4 1.4 0 0 1 1.4 1.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 2.4 1z"/><path class="peg__wood peg__wood--back" d="M10.4 1h5.2A1.4 1.4 0 0 1 17 2.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 10.4 1z"/><path class="peg__grain" d="M4.3 5v8M13.7 6v6M4.6 26v11M13.4 27v10"/><rect class="peg__spring" x="0.4" y="16" width="17.2" height="5.4" rx="2.7"/><path class="peg__coil" d="M4 16.4v4.6M7 16.4v4.6M10 16.4v4.6M13 16.4v4.6"/></svg>
</a></li>
<li><a class="tag" href="#visit" data-tag>
<span class="tag__cloth">
<span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="3.5" width="17" height="17" rx="1"/><path d="M6 5.5c3.6 3 8.4 3 12 0"/></svg>
<span class="tag__name">Visit</span>
</span>
<span class="tag__dye" aria-hidden="true" data-dye><span class="tag__face">
<svg class="tag__care" viewBox="0 0 24 24"><rect x="3.5" y="3.5" width="17" height="17" rx="1"/><path d="M6 5.5c3.6 3 8.4 3 12 0"/></svg>
<span class="tag__name">Visit</span>
</span></span>
</span>
<svg class="tag__peg" viewBox="0 0 18 44" aria-hidden="true"><rect class="peg__shade" x="1.6" y="3.6" width="16" height="41.4" rx="3"/><path class="peg__wood" d="M2.4 1h5.2a1.4 1.4 0 0 1 1.4 1.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 2.4 1z"/><path class="peg__wood peg__wood--back" d="M10.4 1h5.2A1.4 1.4 0 0 1 17 2.4V40a3 3 0 0 1-3 3h-1.4a3 3 0 0 1-3-3V2.4A1.4 1.4 0 0 1 10.4 1z"/><path class="peg__grain" d="M4.3 5v8M13.7 6v6M4.6 26v11M13.4 27v10"/><rect class="peg__spring" x="0.4" y="16" width="17.2" height="5.4" rx="2.7"/><path class="peg__coil" d="M4 16.4v4.6M7 16.4v4.6M10 16.4v4.6M13 16.4v4.6"/></svg>
</a></li>
</ul>
</nav>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.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.
29 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 menu sul filo» da Animorio e adattala al mio sitoIl filo è una catena di 41 punti fra due anelli fissi, otto per ogni etichetta. A ogni fotogramma si fanno 16 passi piccoli: ogni punto va avanti con la sua velocità (Verlet, frenata dall'aria) e la gravità, poi ogni tratto riporta i suoi due punti alla lunghezza di riposo. Con tanti passi piccoli e un solo giro di vincoli per passo la corda resta quasi inestensibile e non trema mai, anche a 390 pixel.
I vincoli sono quelli di XPBD: ognuno ha una cedevolezza, GIVE · 1e-9 · lunghezza del filo, divisa per il passo al quadrato, che lascia allungare il filo sotto un peso. Scalata con la lunghezza, il filo pende e cede allo stesso modo al computer e al telefono. I punti delle etichette pesano WEIGHT volte gli altri e l'aria li frena di più: sono stoffa.
Puntare un'etichetta aggiunge un vincolo morbido che porta il suo punto DIP pixel sotto l'altezza a riposo, misurata dopo che il filo si è assestato. Il clic sposta quell'altezza di TUG pixel con un tween di GSAP (sine.inOut, 0,16 secondi) e poi toglie il vincolo: il filo teso riparte da solo, e il rimbalzo e il dondolio delle vicine non sono animati, vengono dalla fisica.
Ogni etichetta ruota attorno alla sua molletta come un pendolo: l'accelerazione di lato del suo punto la spinge, una molla la riporta giù con frequenza SWAY[0] e SWAY[1] la ferma. Una brezza fatta di due onde lente spinge il filo di lato, così niente è mai del tutto fermo. Il filo si disegna in SVG come una curva liscia (Catmull-Rom in Bézier) con l'ombra, la ritorcitura tratteggiata e un filo di luce.
Ogni etichetta ha sopra una copia di sé tinta d'indaco, tagliata da un clip-path a poligono con un bordo che ondeggia e sale in DYE secondi. Le voci sono link veri in un nav, con aria-current="page"; le frecce, Home e Fine scorrono lungo il filo, e la messa a fuoco da tastiera tira l'etichetta come il puntatore.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
SAG | script.js | 0.05 | Quanto pende il filo, come parte della sua lunghezza. |
GIVE | script.js | 2 | Quanto cede il filo sotto un tiro: più alto, un filo più elastico. |
DIP | script.js | 14 | Di quanti pixel scende un'etichetta sotto il puntatore. |
TUG | script.js | 46 | Di quanti pixel il clic tira giù l'etichetta (al telefono meno, in proporzione al filo). |
SWAY | script.js | [5.5, 2.6] | Il dondolio delle etichette: quanto è svelto (la lunghezza del pendolo) e quanto presto si ferma. |
BREEZE | script.js | 0.35 | Una brezza leggera che tiene il filo in movimento, da 0 (fermo) a 1. |
DYE | script.js | 0.75 | I secondi che l'indaco impiega a salire sull'etichetta scelta. |
Per la navigazione di un sito con un carattere artigianale (tessuti, abbigliamento, una lavanderia, una casa vacanze, un laboratorio) con quattro o cinque voci brevi, in testa alla pagina dove c'è spazio per il filo.
Il filo prende tutta la larghezza e le etichette si stringono a 58 pixel, così cinque stanno in 390 pixel; il filo pende e cede in proporzione alla sua lunghezza e il tiro del clic si accorcia. Al tocco il dito che preme tira giù l'etichetta come il puntatore, e alzandolo la sceglie.
Il filo resta fermo nella sua curva a riposo, senza brezza né dondolio, e le etichette sono già appese all'arrivo; scegliendone una l'indaco compare in dissolvenza.
GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 8,1 KB; le librerie: GSAP 28 KB.
Provata il 4 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.