
Il pulsante d’invio
Pulsanti, Transizioni, SVG
NuovaGratis
Gli avvisi di un negozio, consegnati come posta, nello stile ricco: una cassetta delle lettere di metallo verniciato sul suo palo di legno. Quando arriva un avviso la bandierina rossa scatta su, il coperchio si apre sul cardine, una busta col francobollo e il timbro esce dalla cassetta, vola al suo posto, si gira e si apre, e la lettera dentro è l’avviso. Quattro tipi, ognuno con la sua busta: spedito, pagamento rifiutato (la cassetta trema e la busta arriva strappata), nuovo messaggio, salvato.
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 mailbox alert</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/caveat@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the alerts of a small shop, delivered like post: a painted metal mailbox on its wooden post. When an alert
arrives the red flag springs up, the lid swings open on its hinge, an envelope (paper grain, a perforated
stamp, a postmark) rises out of the box, flies to its place and opens, and the letter inside is the alert.
A failed payment shakes the box and the envelope arrives with a torn corner. The alert closes by itself after
a few seconds, or with its cross or Esc, and the letter goes back into the envelope and the box -->
<section class="post" aria-label="Shop alerts" data-post>
<div class="post__scene" data-scene>
<svg class="box" viewBox="0 0 200 240" aria-hidden="true" data-box>
<defs>
<linearGradient id="mb-paint" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="stop-paint-dark"/>
<stop offset="0.18" class="stop-paint-light"/>
<stop offset="0.55" class="stop-paint"/>
<stop offset="1" class="stop-paint-dark"/>
</linearGradient>
<linearGradient id="mb-lid" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" class="stop-paint-light"/>
<stop offset="1" class="stop-paint-dark"/>
</linearGradient>
<linearGradient id="mb-wood" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="stop-wood-dark"/>
<stop offset="0.35" class="stop-wood-light"/>
<stop offset="1" class="stop-wood-dark"/>
</linearGradient>
<linearGradient id="mb-brass" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" class="stop-brass-light"/>
<stop offset="0.5" class="stop-brass"/>
<stop offset="1" class="stop-brass-dark"/>
</linearGradient>
<linearGradient id="mb-flag" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" class="stop-flag-light"/>
<stop offset="1" class="stop-flag"/>
</linearGradient>
<linearGradient id="mb-steel" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="stop-steel-dark"/>
<stop offset="0.5" class="stop-steel-light"/>
<stop offset="1" class="stop-steel-dark"/>
</linearGradient>
<radialGradient id="mb-rivet" cx="0.35" cy="0.3" r="0.8">
<stop offset="0" class="stop-steel-light"/>
<stop offset="1" class="stop-steel-dark"/>
</radialGradient>
<filter id="mb-soft" x="-30%" y="-200%" width="160%" height="500%">
<feGaussianBlur stdDeviation="4"/>
</filter>
</defs>
<!-- the shadow on the ground -->
<ellipse class="box__ground" cx="100" cy="232" rx="66" ry="6" filter="url(#mb-soft)"/>
<!-- the wooden post, its grain and the bracket the box sits on -->
<g class="box__post">
<rect x="89" y="148" width="22" height="88" rx="2" fill="url(#mb-wood)"/>
<path class="box__grain" d="M95 152 C 94 172, 97 190, 95 212 S 96 228, 95 236"/>
<path class="box__grain" d="M103 150 C 104 168, 101 186, 104 204 S 103 224, 105 236"/>
<path class="box__grain box__grain--knot" d="M99 196 c 3 -3 5 1 2 4 c -3 2 -5 -1 -2 -4 z"/>
<rect x="62" y="146" width="76" height="9" rx="2" fill="url(#mb-wood)"/>
<rect x="62" y="153" width="76" height="2" class="box__bracket-shade"/>
<circle cx="70" cy="150.5" r="1.6" fill="url(#mb-rivet)"/>
<circle cx="130" cy="150.5" r="1.6" fill="url(#mb-rivet)"/>
</g>
<!-- the box: the shake of a failed payment turns it about the foot of the post -->
<g class="box__body" data-body>
<!-- the dark slot under the lid, seen when it opens -->
<rect class="box__mouth" x="48" y="56" width="104" height="9" rx="3"/>
<rect x="40" y="60" width="120" height="90" rx="12" fill="url(#mb-paint)"/>
<rect class="box__bevel" x="44.5" y="64.5" width="111" height="81" rx="9"/>
<path class="box__band" d="M40 132 h120 v6 a12 12 0 0 1 -12 12 h-96 a12 12 0 0 1 -12 -12 z"/>
<path class="box__shine" d="M50 70 C 49 92, 49 118, 52 140" />
<path class="box__shine box__shine--thin" d="M57 72 C 56 92, 56 112, 58 128" />
<!-- two soft dents, a light rim and a shadow each -->
<ellipse class="box__dent-shade" cx="132" cy="98" rx="7" ry="4.5" transform="rotate(-18 132 98)"/>
<ellipse class="box__dent-light" cx="130.5" cy="96" rx="5.5" ry="3" transform="rotate(-18 130.5 96)"/>
<ellipse class="box__dent-shade" cx="62" cy="128" rx="5" ry="3" transform="rotate(12 62 128)"/>
<ellipse class="box__dent-light" cx="61" cy="126.6" rx="4" ry="2" transform="rotate(12 61 126.6)"/>
<!-- the brass plate -->
<rect x="70" y="102" width="60" height="18" rx="3" fill="url(#mb-brass)"/>
<rect class="box__plate-edge" x="71.5" y="103.5" width="57" height="15" rx="2"/>
<text class="box__plate-word" x="100" y="114.6" text-anchor="middle">LETTERS</text>
<circle cx="74.5" cy="111" r="1.4" fill="url(#mb-rivet)"/>
<circle cx="125.5" cy="111" r="1.4" fill="url(#mb-rivet)"/>
<!-- rivets on the corners of the front panel -->
<circle cx="49" cy="73" r="1.9" fill="url(#mb-rivet)"/>
<circle cx="151" cy="73" r="1.9" fill="url(#mb-rivet)"/>
<circle cx="49" cy="141" r="1.9" fill="url(#mb-rivet)"/>
<circle cx="151" cy="141" r="1.9" fill="url(#mb-rivet)"/>
<!-- the lid, hinged on its left pin -->
<g class="box__lid" data-lid>
<rect x="35" y="50" width="130" height="14" rx="5" fill="url(#mb-lid)"/>
<rect class="box__lid-lip" x="35" y="60" width="130" height="4" rx="2"/>
<path class="box__lid-shine" d="M44 53.5 H 150"/>
<rect x="150" y="56" width="10" height="5" rx="1.5" fill="url(#mb-steel)"/>
</g>
<rect x="31" y="53" width="9" height="9" rx="2" fill="url(#mb-steel)"/>
<circle cx="35.5" cy="57.5" r="1.7" fill="url(#mb-rivet)"/>
<!-- the flag, pivoting on a pin on the right side of the box -->
<g class="box__flag" data-flag>
<rect x="164.5" y="54" width="5" height="70" rx="2.5" fill="url(#mb-steel)"/>
<path d="M169 54 C 180 51, 188 57, 197 54 L 197 74 C 188 77, 180 71, 169 74 Z" fill="url(#mb-flag)"/>
<path class="box__flag-fold" d="M180 53.5 C 181 60, 181 66, 180 72.5"/>
<path class="box__flag-shine" d="M172 58 C 180 56, 186 60, 193 58"/>
</g>
<circle class="box__pin" cx="167" cy="120" r="3.6" fill="url(#mb-rivet)"/>
<circle class="box__pin-dot" cx="167" cy="120" r="1.1"/>
<!-- the point the envelope comes out of -->
<rect class="box__mark" x="99" y="60" width="2" height="2" data-mouth/>
</g>
</svg>
<!-- the envelope is two layers with the letter between them: the far sheet (and the flap once it is open)
behind the alert, the near side (the address side while it flies, the back with its seams and closed
flap once it has turned) in front of it -->
<div class="env env--far" aria-hidden="true" data-env-far>
<div class="env__sheet"></div>
<div class="env__flap-open" data-flap-open></div>
</div>
<!-- the alert itself: the letter. Its role and words change with each kind -->
<div class="toast" data-toast>
<div class="toast__sheet">
<span class="toast__icon" data-icon aria-hidden="true"></span>
<span class="toast__text">
<span class="toast__title" data-title>Order shipped</span>
<span class="toast__body" data-body-text>Two linen shirts are on their way.</span>
</span>
<button class="toast__close" type="button" aria-label="Dismiss alert" data-close>
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 7l10 10M17 7L7 17"/></svg>
</button>
</div>
</div>
<div class="env env--near" aria-hidden="true" data-env-near>
<div class="env__face env__face--front" data-face-front>
<span class="env__from">Larkspur Goods<br>Mill Lane</span>
<span class="env__to" data-to>Ada Moreau</span>
<span class="env__lines"></span>
<svg class="env__stamp" viewBox="0 0 36 42">
<defs>
<mask id="mb-perf" maskUnits="userSpaceOnUse" x="0" y="0" width="36" height="42">
<rect x="0" y="0" width="36" height="42" fill="#fff"/>
<g fill="#000">
<circle cx="3" cy="0" r="1.7"/><circle cx="9" cy="0" r="1.7"/><circle cx="15" cy="0" r="1.7"/><circle cx="21" cy="0" r="1.7"/><circle cx="27" cy="0" r="1.7"/><circle cx="33" cy="0" r="1.7"/>
<circle cx="3" cy="42" r="1.7"/><circle cx="9" cy="42" r="1.7"/><circle cx="15" cy="42" r="1.7"/><circle cx="21" cy="42" r="1.7"/><circle cx="27" cy="42" r="1.7"/><circle cx="33" cy="42" r="1.7"/>
<circle cx="0" cy="3" r="1.7"/><circle cx="0" cy="9" r="1.7"/><circle cx="0" cy="15" r="1.7"/><circle cx="0" cy="21" r="1.7"/><circle cx="0" cy="27" r="1.7"/><circle cx="0" cy="33" r="1.7"/><circle cx="0" cy="39" r="1.7"/>
<circle cx="36" cy="3" r="1.7"/><circle cx="36" cy="9" r="1.7"/><circle cx="36" cy="15" r="1.7"/><circle cx="36" cy="21" r="1.7"/><circle cx="36" cy="27" r="1.7"/><circle cx="36" cy="33" r="1.7"/><circle cx="36" cy="39" r="1.7"/>
</g>
</mask>
</defs>
<g mask="url(#mb-perf)">
<rect class="stamp__paper" x="0" y="0" width="36" height="42"/>
<rect class="stamp__field" x="4" y="4" width="28" height="34" rx="1"/>
<!-- a larkspur: a stem with its little spurred flowers and two leaves -->
<path class="stamp__stem" d="M18 35 C 18 27, 17.5 20, 18.5 10"/>
<path class="stamp__leaf" d="M18 30 C 13 28, 11 25, 11 23 C 14 24, 17 26, 18 30 Z"/>
<path class="stamp__leaf" d="M18.2 27 C 23 25, 25 22, 25.5 20 C 22 21, 19 23.5, 18.2 27 Z"/>
<path class="stamp__bloom" d="M18.5 10 c -3 -1 -3 -4 0 -4 c 3 0 3 3 0 4 z M17 15 c -3 0 -4 -3 -1 -4 c 2 0 3 2 1 4 z M20 19 c 3 0 4 -3 1 -4 c -2 0 -3 2 -1 4 z M17 23 c -3 0 -4 -3 -1 -3.5 c 2 0 2.5 2 1 3.5 z"/>
</g>
</svg>
<svg class="env__postmark" viewBox="0 0 64 40">
<circle cx="20" cy="20" r="15"/>
<circle cx="20" cy="20" r="11"/>
<path d="M38 12 c 4 -3 8 3 12 0 s 8 3 12 0 M38 20 c 4 -3 8 3 12 0 s 8 3 12 0 M38 28 c 4 -3 8 3 12 0 s 8 3 12 0"/>
<text x="20" y="22.6" text-anchor="middle">LARK</text>
</svg>
</div>
<div class="env__face env__face--back" data-face-back>
<svg class="env__seams" viewBox="0 0 100 50" preserveAspectRatio="none">
<path d="M0 50 L 42 27 M100 50 L 58 27"/>
</svg>
<div class="env__flap-shut" data-flap-shut></div>
</div>
<div class="env__scrap" data-scrap></div>
</div>
</div>
<!-- the buttons that send each kind of alert -->
<div class="post__send" role="group" aria-label="Send an alert">
<button class="chip" type="button" data-send="shipped">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 8.5 12 4l8 4.5v7L12 20l-8-4.5z M4 8.5 12 13l8-4.5 M12 13v7"/></svg>
<span>Shipped</span>
</button>
<button class="chip" type="button" data-send="failed">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3.5 7h17v10h-17z M3.5 10.5h17 M7 14.5h4 M15 13l4 4 M19 13l-4 4"/></svg>
<span>Failed</span>
</button>
<button class="chip" type="button" data-send="message">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4.5 6.5h15v9h-8l-4 3.5v-3.5h-3z"/></svg>
<span>Message</span>
</button>
<button class="chip" type="button" data-send="saved">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 4.5h10v15l-5-3.6-5 3.6z"/></svg>
<span>Saved</span>
</button>
</div>
<!-- what screen readers hear: the calm kinds politely, the failed payment at once -->
<p class="sr" role="status" aria-live="polite" data-live-status></p>
<p class="sr" role="alert" aria-live="assertive" data-live-alert></p>
</section>
</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.
58 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 «L’avviso della cassetta delle lettere» da Animorio e adattala al mio sitoLa cassetta è un SVG: la bandierina, il coperchio e la cassetta intera sono gruppi che GSAP ruota con svgOrigin, cioè attorno a un punto nelle coordinate del disegno: la bandierina attorno al perno sul fianco, il coperchio attorno al cardine, la cassetta attorno al piede del palo quando trema. Così ogni pezzo resta attaccato dove è fissato, a qualsiasi misura.
La busta è fatta di due livelli che si muovono insieme: dietro il foglio lontano (e la patta quando è aperta), davanti il lato vicino (l’indirizzo mentre vola, il retro con le cuciture e la patta chiusa dopo che si è girata). L’avviso sta in mezzo, quindi esce davvero dalla tasca: il lato vicino lo copre finché sale sopra il bordo.
Dalla bocca della cassetta al suo posto la busta segue una curva: una sola variabile da 0 a 1 animata da GSAP, e a ogni passo x lineare, y con un seno che la solleva, la scala con un ease che la fa crescere presto e una rotazione che si inclina in mezzo al volo e si raddrizza all’arrivo.
La busta si gira stringendosi a zero sull’asse x e riallargandosi con un back.out: nel momento in cui è sottile come un filo si scambiano le facce. La patta chiusa si accorcia verso il bordo (scaleY dall’alto), e quando è sparita cresce quella aperta, dietro la lettera, dal bordo in su.
Ogni tipo cambia il colore della busta e della lettera (una variabile CSS presa da :root), l’icona SVG e le parole; il pagamento rifiutato aggiunge il tremito, l’angolo strappato (un clip-path a zig-zag) e il pezzo che cade. Le parole vanno a una riga role="status" educata, o a una role="alert" che interrompe se il pagamento è rifiutato.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
FLAG_SPRING | script.js | 0.42 | Quanto è molleggiata la bandierina quando scatta su: 0.2 rigida, 0.8 ballerina. |
FLIGHT | script.js | 0.75 | I secondi del volo della busta dalla cassetta al suo posto. |
OPEN | script.js | 0.5 | I secondi in cui la busta si gira e si apre. |
HOLD | script.js | 2.8 | I secondi in cui l’avviso resta prima di tornare da solo nella cassetta. |
GAP | script.js | 0.7 | I secondi fra un avviso e l’altro quando la demo va da sola. |
SHAKE | script.js | 3.5 | Quanto trema la cassetta per un pagamento rifiutato, in gradi. |
FIRST | script.js | 0.6 | I secondi prima che arrivi il primo avviso. |
MESSAGES | script.js | quattro avvisi: Order shipped, New message, Payment failed, Saved | Gli avvisi, a turno: il tipo, il titolo, la riga e il nome sulla busta. |
Per gli avvisi di un negozio online, di un’app di spedizioni o di posta, di un servizio con un tocco artigianale: ordine spedito, pagamento rifiutato, messaggio nuovo, salvataggio riuscito. Un avviso alla volta, con un titolo e una riga; la consegna dura circa tre secondi, quindi sta meglio dove gli avvisi non arrivano a raffica.
Sul telefono l’avviso va in alto, largo quasi quanto la casella, e la cassetta più piccola sta sotto a sinistra; la busta, la patta e i pulsanti si stringono, così tutto sta in una casella di 341 per 410. Le animazioni sono le stesse.
Col movimento ridotto non volano buste: la bandierina è già su e l’avviso compare in dissolvenza al suo posto, e sparisce allo stesso modo.
GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0, Caveat (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 13 KB; le librerie: GSAP 28 KB.
Provata il 22 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.