
Il menu a onda di peso
Menu, Testo, Hover, Fisica
NuovaGratis
La card di un’acqua di profumo in una piccola profumeria: una boccetta di vetro sfaccettato piena a metà di profumo ambrato, col vaporizzatore d’oro, su una mensola di pietra davanti a un muro verde foglia di fico. La luce segue il puntatore: la boccetta si inclina verso di lei sullo spigolo della base, il profumo dentro resta in piano e ondeggia quando il vetro si muove, e ogni faccia del vetro piega quello che c’è dietro e prende la luce col suo angolo. Premendo il vaporizzatore, o Try a spray, parte una nuvola di goccioline che si arriccia nell’aria, e dalla nuvola le note del profumo si radunano goccia a goccia e si posano alla loro altezza: la nota di testa più in alto, quella di fondo più in basso. Poi svaniscono nell’ordine in cui svanisce un profumo sulla pelle.
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 perfume card</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/playfair@5.3.0/standard.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/playfair@5.3.0/standard-italic.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the card of a perfume in a small perfumery. In its picture a faceted glass bottle of amber perfume: the
perfume leans as the bottle moves, the facets bend what is behind them and catch the light, which follows
the pointer. A press on the atomizer, or Try a spray, throws a cloud of mist, and the notes of the perfume
gather out of it and settle at their heights: the top note highest, the base note lowest. Then they fade in
the order a perfume fades on the skin. The bottle, the mist and the light are drawn by the script -->
<article class="scent" aria-labelledby="scent-name" data-scent data-autoclic>
<div class="shot" data-shot>
<canvas class="shot__canvas" role="img" aria-label="A faceted glass bottle of amber perfume with a gold atomizer, standing on dark stone" data-canvas></canvas>
<div class="notes" aria-hidden="true">
<p class="note note--top" data-note><span class="note__tier">Top</span><span class="note__name" data-word>Bergamot</span></p>
<p class="note note--heart" data-note><span class="note__tier">Heart</span><span class="note__name" data-word>Fig leaf</span></p>
<p class="note note--base" data-note><span class="note__tier">Base</span><span class="note__name" data-word>Cedar</span></p>
</div>
<button class="shot__nozzle" type="button" aria-label="Spray the perfume" data-nozzle></button>
</div>
<div class="scent__body">
<p class="scent__kind">Atelier Ombrine · Eau de parfum</p>
<div class="scent__head">
<h2 class="scent__name" id="scent-name">Fig Hour</h2>
<p class="scent__price" aria-live="off"><span class="sr" data-price-sr>€115</span><span class="price" aria-hidden="true" data-price>€115</span></p>
</div>
<div class="sizes" role="radiogroup" aria-label="Size" data-sizes>
<span class="sizes__thumb" aria-hidden="true" data-thumb><span class="sizes__thumb-fill"></span></span>
<button class="size" type="button" role="radio" aria-checked="false" tabindex="-1" data-size>30 ml</button>
<button class="size" type="button" role="radio" aria-checked="true" tabindex="0" data-size>50 ml</button>
<button class="size" type="button" role="radio" aria-checked="false" tabindex="-1" data-size>100 ml</button>
</div>
<div class="buy">
<button class="pill pill--try" type="button" data-try>
<span class="pill__icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M5.2 11.2h7.6a1.4 1.4 0 0 1 1.4 1.4v6.8a1.4 1.4 0 0 1-1.4 1.4H5.2a1.4 1.4 0 0 1-1.4-1.4v-6.8a1.4 1.4 0 0 1 1.4-1.4z"/>
<path d="M7.6 11.2V8.4h2.8v2.8"/>
<path d="M6.8 8.4V5.6h4.4v2.8"/>
<g class="try__puff" data-puff>
<path d="M14.4 6.2h2.1"/>
<path d="M14.2 3.8l1.8-.9"/>
<path d="M14.2 8.6l1.8.9"/>
<path d="M18.6 6.2h1.6"/>
<path d="M18.1 2.5l1.3-.6"/>
<path d="M18.1 9.9l1.3.6"/>
</g>
</svg>
</span>
<span class="pill__label">Try a spray</span>
</button>
<button class="pill pill--add" type="button" data-add>
<span class="pill__icon" aria-hidden="true">
<svg class="add__glyph" viewBox="0 0 24 24" data-bag><path d="M5.4 8.4h13.2l-1 11.2a1.6 1.6 0 0 1-1.6 1.4H8a1.6 1.6 0 0 1-1.6-1.4z"/><path d="M9 10.6V7a3 3 0 0 1 6 0v3.6"/></svg>
<svg class="add__glyph add__drop" viewBox="0 0 24 24" data-drop><path d="M12 9.2c1.5 2 2.3 3.3 2.3 4.4a2.3 2.3 0 0 1-4.6 0c0-1.1.8-2.4 2.3-4.4z"/></svg>
<svg class="add__glyph add__tick" viewBox="0 0 24 24" data-tick><path d="M5.6 12.6l4.1 4.1 8.7-9.2"/></svg>
</span>
<span class="pill__label" data-label>Add to bag</span>
</button>
</div>
<p class="sr" aria-live="polite" data-live></p>
</div>
</article>
</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.
55 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 «La card del profumo» da Animorio e adattala al mio sitoLa cavità della boccetta è un ottagono e il profumo è la parte che sta sotto una retta: i punti p con m·p ≥ h, dove m è la normale della superficie. Per ogni angolo della superficie l’altezza h che lascia sotto esattamente l’area del profumo si trova per bisezione (24 passi, ritagliando l’ottagono con la retta e misurando l’area col metodo dei lacci): così il profumo, inclinandosi, si alza da una parte e si abbassa dall’altra senza crescere né calare. La superficie fra i due punti di taglio è piegata da un coseno, che ha area nulla e quindi non cambia il volume: è il secondo modo dell’onda, lo sciabordio.
La boccetta si inclina verso la luce su una molla smorzata, e ruota sullo spigolo della base dalla parte verso cui pende (il perno cambia lato quando l’angolo passa per zero, quindi senza salti). L’angolo della superficie nella stanza è un pendolo smorzato poco: l’accelerazione della boccetta lo spinge fuori dal piano, poi torna oltre e ondeggia. Nel disegno l’angolo della superficie rispetto al vetro è quello nella stanza meno l’inclinazione della boccetta. Lo spruzzo dà un colpo indietro alla boccetta e al secondo modo, il cambio di formato anche.
A ogni fotogramma si disegna in una tela nascosta quello che sta dietro e dentro il vetro: il muro e la mensola già disegnati, la base spessa che si accende del colore del profumo, la cavità, la cannuccia, il profumo con la sua luce. Poi, faccia per faccia, la tela vera si ritaglia sul poligono della faccia e ci copia quella tela: la faccia piatta ingrandita del 4,5% attorno al centro, ogni smusso spostato lungo la sua pendenza. Il profumo e il bordo della mensola si spezzano sugli spigoli come nel vetro spesso. Ogni faccia ha una normale in 3D: la luce del puntatore dà l’ombra (Lambert), il riflesso (Blinn, col vettore a metà fra luce e occhio) e sulla faccia più accesa un filo rosso e uno azzurro un capello più in là, come un prisma.
Lo spruzzo sono circa novecento goccioline in 0,22 secondi e una cinquantina di sbuffi morbidi, con velocità e direzioni sparse in un cono: frenano con l’aria (esponenziale), salgono piano e sono portate da un vento fatto col rotore di una somma di onde che scorrono nel tempo. Un vento così non ha sorgenti né pozzi: la nebbia si arriccia senza ammucchiarsi né sparire in un punto. Il vento entra piano, solo quando la goccia ha rallentato, così il getto resta dritto vicino all’ugello. Tutto è disegnato in modalità lighter, più chiaro vicino alla luce.
Ogni nota è disegnata una volta in una tela nascosta, lettera per lettera, nel suo carattere e al suo posto (presi dal DOM con offsetLeft e offsetTop, che non sentono le trasformazioni di GSAP); i pixel pieni diventano i punti d’arrivo. Allo spruzzo per ogni parola partono fino a 270 goccioline con la nebbia: volano libere, poi una curva smoothstep le porta dal loro volo al loro punto, e la parola compare fatta di brillantini. Allora le lettere vere si condensano da sopra: GSAP le porta da sfocate, trasparenti e sottili (asse wght a 320) a nitide e piene (460), con un rimbalzo, mentre le goccioline si spengono. Per svanire si fa il contrario: le lettere salgono e si sfocano e dai punti della parola parte un filo di vapore.
Il formato scelto è un radiogroup con le frecce: la pillola chiara sotto scorre col suo rimbalzo (posizione e larghezza in pixel, ricalcolate quando la card cambia misura), la boccetta cresce o cala con un elastico e il prezzo gira: le cifre vecchie salgono una dopo l’altra e le nuove arrivano da sotto. Add to bag fa cadere una goccia nella borsa, che si abbassa per prenderla, poi mostra la spunta e torna a riposo.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
TILT | script.js | 4 | Di quanti gradi la boccetta si inclina verso la luce. |
SLOSH | script.js | 1 | Quanto il profumo ondeggia dentro quando la boccetta si muove (0 = resta fermo). |
REFRACT | script.js | 8 | Di quanti pixel le facce smussate spostano quello che si vede attraverso. |
FILL | script.js | 0.64 | Quanto è piena la boccetta, da 0,2 a 0,95. |
MIST | script.js | 900 | Quante goccioline lancia uno spruzzo. |
SPRAY_SPEED | script.js | 560 | Quanto veloci escono le goccioline dall’ugello, in pixel al secondo. |
SWIRL | script.js | 1 | Quanto l’aria arriccia la nebbia (0 = va dritta). |
HOLD | script.js | 3.2 | I secondi in cui le note restano prima che cominci a svanire quella di testa. |
DRYDOWN | script.js | 1.7 | I secondi fra una nota che svanisce e la successiva: testa, cuore, poi fondo. |
PRICES | script.js | [78, 115, 168] | Il prezzo di ogni formato, 30, 50 e 100 ml. |
SCALES | script.js | [0.84, 1, 1.14] | Quanto grande è disegnata la boccetta per ogni formato. |
CURRENCY | script.js | '€' | La valuta prima del prezzo. |
WORDS | script.js | ['Adding', 'In your bag'] | Add to bag mentre lavora e quando ha finito. |
Per la scheda di un profumo, di una candela, di un olio o di un diffusore in un negozio online, dove le note sono la cosa da far capire; ovunque un prodotto in vetro debba sembrare vero (un liquore, un olio d’oliva, un siero) e una pagina di prodotto voglia un momento da provare prima del carrello.
La card è larga 340 pixel, o lo schermo meno 32, e la foto si ridisegna alla misura vera; le note sono misurate sulla larghezza della foto (unità cqw), quindi restano al loro posto a ogni misura. Un tocco sulla foto spruzza; trascinando il dito di lato la luce segue il dito e la boccetta si inclina, e lasciando torna al suo posto (la pagina scorre in verticale come sempre). Le pillole sono alte 50 pixel e i formati 34. Sotto i 360 pixel il nome e le pillole si stringono un poco. La nebbia e le parole di goccioline sono le stesse del computer.
La boccetta non si inclina e il profumo non ondeggia; la luce resta al suo posto. Lo spruzzo è una nebbia ferma che compare e se ne va in dissolvenza, senza goccioline che volano, e le note compaiono e svaniscono nello stesso ordine con una dissolvenza. La boccetta cambia misura di colpo e il prezzo nuovo compare in dissolvenza; le scritte dei pulsanti cambiano in dissolvenza e le pillole non si gonfiano.
GSAP 3.15.0, Playfair (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 20 KB; le librerie: GSAP 28 KB.
Provata il 17 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.