
Il banner dei cookie
Consenso, Transizioni, SVG, Fisica
NuovaGratis
Il Sign & send di un contratto, chiuso come una lettera: premuto, un bastoncino di ceralacca rosso scuro cola nel pozzetto del pulsante e la cera si allarga viscosa in una pozza dal bordo irregolare. Un sigillo d’ottone scende dall’alto in prospettiva, preme (il pulsante cede e la cera si schiaccia più larga) e si rialza: nella cera resta una & in rilievo, illuminata da filtri di luce SVG veri, con la luce che segue il puntatore. La scritta diventa Sent.
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 wax seal button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/opsz.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/opsz-italic.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the wax seal button: pressed, a stick of sealing wax drips into the round well and stirs a pool with a ragged
edge, a brass seal comes down from above, presses, lifts, and leaves an ampersand raised in the wax that
catches the light. The pool and the relief are an SVG path redrawn every frame under a lighting filter -->
<div class="seal" data-seal>
<button class="seal__btn" type="button" aria-describedby="seal-live" data-btn data-autoclic>
<span class="seal__well" aria-hidden="true" data-well>
<svg class="seal__nib" viewBox="0 0 24 24" data-nib>
<path d="M12 2.8l5.2 7.6c.3.5.3 1.1 0 1.6L12 21.2 6.8 12c-.3-.5-.3-1.1 0-1.6z"/>
<path d="M12 21.2v-7"/>
<circle cx="12" cy="12.4" r="1.6"/>
</svg>
</span>
<!-- the pool of wax, its shadow and the relief: drawn round the middle of the well -->
<svg class="seal__wax" viewBox="-100 -100 200 200" aria-hidden="true" data-wax>
<defs>
<filter id="wax-relief" filterUnits="userSpaceOnUse" x="-100" y="-100" width="200" height="200" color-interpolation-filters="sRGB">
<!-- the grey of each shape is its height: the pool, the lip pushed up round the die, the pressed field,
the ring and the ampersand -->
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.333 0.333 0.334 0 0" result="steps"/>
<feGaussianBlur in="steps" stdDeviation="0.9" result="fine"/>
<!-- and the whole pool is a soft dome at its edge -->
<feGaussianBlur in="SourceAlpha" stdDeviation="3.4" result="dome"/>
<feComposite in="fine" in2="dome" operator="arithmetic" k2="0.62" k3="0.55" result="height"/>
<feDiffuseLighting in="height" surfaceScale="5.5" diffuseConstant="1.18" lighting-color="#ffffff" result="diffuse">
<feDistantLight azimuth="225" elevation="46" data-light/>
</feDiffuseLighting>
<feSpecularLighting in="height" surfaceScale="5.5" specularConstant="0.8" specularExponent="26" lighting-color="#ffe7d2" result="gloss">
<feDistantLight azimuth="225" elevation="46" data-light/>
</feSpecularLighting>
<feFlood flood-color="#8e1a22" result="tint" data-tint/>
<feComposite in="tint" in2="diffuse" operator="arithmetic" k1="1.02" k2="0.16" result="lit"/>
<feComposite in="lit" in2="SourceAlpha" operator="in" result="body"/>
<feComposite in="gloss" in2="SourceAlpha" operator="in" result="shine"/>
<feComposite in="shine" in2="body" operator="arithmetic" k2="0.75" k3="1"/>
</filter>
<filter id="wax-shadow" filterUnits="userSpaceOnUse" x="-100" y="-100" width="200" height="200">
<feGaussianBlur stdDeviation="2.4"/>
</filter>
</defs>
<path class="seal__shadow" transform="translate(1.5 3.5)" data-shadow d=""/>
<g filter="url(#wax-relief)" data-relief>
<path data-pool fill="rgb(150,150,150)" d=""/>
<g data-print opacity="0" transform="scale(1.1)">
<circle r="27" fill="none" stroke="rgb(196,196,196)" stroke-width="4.6"/>
<circle r="25" fill="rgb(104,104,104)"/>
<circle r="21.4" fill="none" stroke="rgb(150,150,150)" stroke-width="1.3"/>
<text class="seal__mono" y="10.6" text-anchor="middle" fill="rgb(176,176,176)">&</text>
</g>
</g>
<g data-drops></g>
</svg>
<span class="seal__words" aria-hidden="true">
<span class="seal__word is-on" data-word="rest">Sign & send</span>
<span class="seal__word" data-word="busy">Sealing</span>
<span class="seal__word" data-word="done">Sent</span>
</span>
<span class="sr" data-name>Sign and send the contract</span>
</button>
<!-- the stick of sealing wax, and the brass seal seen from above, drawn in perspective every frame -->
<div class="seal__stick" aria-hidden="true" data-stick>
<svg viewBox="-12 -150 24 156">
<defs>
<linearGradient id="wax-stick" x1="0" x2="1" y1="0" y2="0">
<stop offset="0" stop-color="#4c070d"/>
<stop offset="0.3" stop-color="#a1222b"/>
<stop offset="0.48" stop-color="#d04a4d"/>
<stop offset="0.62" stop-color="#9a1d26"/>
<stop offset="1" stop-color="#3d050a"/>
</linearGradient>
<linearGradient id="wax-tip" x1="0" x2="0" y1="0" y2="1">
<stop offset="0" stop-color="#9a1d26"/>
<stop offset="1" stop-color="#6a0d15"/>
</linearGradient>
</defs>
<rect x="-8" y="-148" width="16" height="136" rx="3" fill="url(#wax-stick)"/>
<path d="M-8 -14c0 6 3 12 8 14 5-2 8-8 8-14z" fill="url(#wax-tip)"/>
<path d="M-4.5 -140v120" stroke="#ffd0c4" stroke-opacity="0.35" stroke-width="1.6" stroke-linecap="round"/>
</svg>
</div>
<svg class="seal__stamp" aria-hidden="true" data-stamp>
<defs>
<radialGradient id="brass-top" cx="0.36" cy="0.32" r="0.8">
<stop offset="0" stop-color="#fff3cf"/>
<stop offset="0.25" stop-color="#e9c779"/>
<stop offset="0.7" stop-color="#a77a2c"/>
<stop offset="1" stop-color="#5e3f12"/>
</radialGradient>
<linearGradient id="brass-side" x1="0" x2="1" y1="0" y2="1">
<stop offset="0" stop-color="#d2a656"/>
<stop offset="0.55" stop-color="#7c561b"/>
<stop offset="1" stop-color="#3f2a0b"/>
</linearGradient>
<radialGradient id="ebony" cx="0.38" cy="0.34" r="0.8">
<stop offset="0" stop-color="#6c5a50"/>
<stop offset="0.5" stop-color="#2a1f1b"/>
<stop offset="1" stop-color="#0d0908"/>
</radialGradient>
<filter id="stamp-blur" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="4" data-blur/>
</filter>
</defs>
<ellipse class="seal__stamp-shadow" filter="url(#stamp-blur)" data-cast/>
<g data-parts></g>
</svg>
<p class="sr" id="seal-live" aria-live="polite" data-live></p>
</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>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.
21 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 pulsante della ceralacca» da Animorio e adattala al mio sitoOgni goccia è una sfera di un campo: in un punto il campo vale la somma di r² / d² di tutte le gocce, e il bordo della pozza è dove vale 1. Lontano dalle gocce le aree si sommano: quattro gocce di raggio r fanno una pozza di raggio 2r, quindi POOL / √DROPS è il raggio di ognuna. A ogni fotogramma il bordo si ritrova lungo 64 raggi dal centro: si scende da fuori a passi di 3 pixel finché il campo arriva a 1, poi nove bisezioni. I 64 punti diventano una curva chiusa di Catmull-Rom scritta come Bézier cubiche nel d del tracciato.
Ogni goccia atterra piccola e veloce e il suo raggio va verso quello giusto su una molla smorzata (rigidezza 150, smorzamento THICK): la cera si spande, supera un poco la misura e torna, densa. Il bordo è irregolare per sei armoniche (3, 4, 5, 7, 9 e 12 lobi) di ampiezze e fasi a caso, pesate da RAGGED; finché la cera è liquida le fasi girano piano e il bordo si muove, quando il sigillo preme metà armoniche cambiano (nuovi lobi schiacciati) e la liquidità scende a zero in 1,6 secondi: la forma si fissa.
Dentro il gruppo filtrato il grigio di ogni forma è un’altezza: la pozza, il labbro spinto in su intorno al sigillo, il campo premuto più basso, l’anello e la &. Un feColorMatrix porta la luminosità nell’alfa, un feGaussianBlur leggero la smussa e un secondo blur ampio dell’alfa fa la cupola del bordo; le due cose sommate con un feComposite aritmetico sono la mappa d’altezza. feDiffuseLighting e feSpecularLighting con una luce lontana la illuminano, il colore della cera è moltiplicato per la diffusa (più un po’ di luce d’ambiente) e il lucido è sommato sopra, tutto ritagliato sulla forma.
Il sigillo visto dall’alto è una pila di dischi alle loro altezze: il conio d’ottone, il collare, il collo d’ebano e il pomello. Ogni disco è proiettato da una camera appesa poco sopra e a destra del pozzetto, k = 900 / (900 − z): più è in alto più è grande e spostato verso l’esterno, così il cilindro mostra il fianco e si legge in 3D. Mentre scende i dischi si stringono e l’ombra sfocata sul pulsante si avvicina, si fa più netta e più scura.
Una timeline GSAP fa entrare il bastoncino, lo fa girare in cerchi mentre lascia cadere le gocce (ogni goccia è un’ellisse che cade con un’accelerazione e, toccando, diventa una sfera del campo), lo porta via, fa scendere il sigillo e al contatto schiaccia il pulsante (scaleY con un ritorno elastico) e allarga le sfere di SPREAD. Al rialzo compare l’impronta e la luce passa radente da −80 gradi e 24 di elevazione al suo posto. Il ciclo di disegno dorme quando niente si muove.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
DROPS | script.js | 4 | Quante gocce di cera cadono dal bastoncino. |
POOL | script.js | 35 | Il raggio della pozza prima che il sigillo prema, in pixel. |
SPREAD | script.js | 1.17 | Di quanto il sigillo schiaccia la pozza più larga. |
RAGGED | script.js | 0.075 | Quanto è irregolare il bordo della pozza (0 = un cerchio perfetto). |
THICK | script.js | 0.42 | Come si assesta la cera: basso, trema come gelatina; vicino a 1, scivola come miele. |
PRESS | script.js | 0.07 | Quanto cede il pulsante sotto il sigillo. |
LIGHT | script.js | 1 | Quanto la luce sul rilievo segue il puntatore (0 = resta in alto a sinistra). |
MARK | script.js | & | Che cosa lascia in rilievo il sigillo nella cera: un carattere o due iniziali. |
Per l’azione che chiude qualcosa di importante: firmare e mandare un contratto, confermare un invito di nozze, spedire una lettera, accettare un’offerta. Sta bene in un prodotto di firma elettronica, nel sito di un matrimonio o di uno studio legale, in una newsletter scritta a mano. Il sigillo chiede qualche secondo: non va su un’azione che si ripete spesso.
Il pulsante resta della stessa misura (circa 290 pixel a 390) con meno spazio ai lati; il bastoncino e il sigillo entrano da sopra e da sinistra, mai sopra la scritta, e niente sfora. Il tocco fa partire la sequenza; la luce del rilievo, senza un puntatore, resta in alto a sinistra.
Niente bastoncino, niente gocce, niente sigillo che scende né pulsante che si schiaccia: il pennino svanisce e il sigillo già impresso compare in dissolvenza nel pozzetto, con la scritta che cambia senza scorrere. La luce non segue il puntatore. Un altro clic lo fa svanire.
GSAP 3.15.0, Fraunces (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 10 KB; le librerie: GSAP 28 KB.
Provata il 5 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.