
La valutazione a stelle
Valutazioni, SVG, Hover
NuovaGratis
Il pulsante Book my trip di un'agenzia di viaggi, con un passaporto di pelle blu in piedi nella sua punta tonda: al clic il passaporto si apre, un timbro di legno scende dall'alto e batte un visto d'arrivo in inchiostro rosso sulla pagina, poi vola via mentre un aeroplanino attraversa la pillola e la scritta diventa Trip booked. Ogni prenotazione lascia un timbro nuovo, con un'altra città.
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 stamped passport button</title>
<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 stamped passport button: the booking button of a travel agency. A navy leather passport with gold foil,
stitching and an e-passport chip stands in the round left end of the pill. A click opens it: the cover swings
round its spine, a loose page flutters, a wooden rubber stamp drops from above and thumps an arrival stamp on
the visa page, then flies off while a little plane crosses the pill and the words turn to Trip booked. Every
new booking leaves another stamp, with another city; a second click closes the passport -->
<div class="pp" data-pp>
<button class="pp__btn" type="button" data-btn data-autoclic>
<span class="pp__fill" aria-hidden="true"><span class="pp__timer" data-timer></span></span>
<span class="pp__sky" aria-hidden="true">
<svg class="pp__trail" data-trail preserveAspectRatio="none"><path data-trail-path fill="none" stroke-width="1.2" stroke-linecap="round" stroke-dasharray="2 4"/></svg>
<svg class="pp__plane" data-plane viewBox="-8 -8 16 16" width="16" height="16"><path d="M7 0 C7 -0.9 6.2 -1.2 5.2 -1.2 L1.8 -1.2 L-1.6 -6.6 L-3.2 -6.6 L-1.4 -1.2 L-4.4 -1.2 L-5.6 -3 L-6.8 -3 L-6 0 L-6.8 3 L-5.6 3 L-4.4 1.2 L-1.4 1.2 L-3.2 6.6 L-1.6 6.6 L1.8 1.2 L5.2 1.2 C6.2 1.2 7 0.9 7 0 Z"/></svg>
</span>
<span class="pp__faces">
<span class="pp__face" data-face="rest">
<span class="pp__word" data-label-text>Book my trip</span>
<span class="pp__note" data-note-text>Lisbon · 3 nights</span>
</span>
<span class="pp__face pp__face--busy" data-face="busy" aria-hidden="true">
<span class="pp__shine" data-busy-text>Checking passport…</span>
</span>
<span class="pp__face pp__face--done" data-face="done" aria-hidden="true">
<svg class="pp__tick" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path data-tick d="M3 8.6 L6.6 12 L13 4.4" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span class="pp__done" data-done-text>Trip booked</span>
</span>
</span>
</button>
<svg class="pp__art" viewBox="0 0 112 156" width="129" height="179" aria-hidden="true" data-art>
<defs>
<linearGradient id="pp-leather" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" style="stop-color:var(--leather-light)"/>
<stop offset="0.45" style="stop-color:var(--leather)"/>
<stop offset="1" style="stop-color:var(--leather-deep)"/>
</linearGradient>
<pattern id="pp-pebble" width="2.6" height="2.6" patternUnits="userSpaceOnUse">
<circle cx="0.7" cy="0.8" r="0.42" fill="#fff" fill-opacity="0.09"/>
<circle cx="2" cy="2" r="0.36" fill="#000" fill-opacity="0.18"/>
</pattern>
<linearGradient id="pp-gold" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" style="stop-color:var(--gold-light)"/>
<stop offset="0.5" style="stop-color:var(--gold)"/>
<stop offset="1" style="stop-color:var(--gold-deep)"/>
</linearGradient>
<linearGradient id="pp-paper" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" style="stop-color:var(--paper-shade)"/>
<stop offset="0.14" style="stop-color:var(--paper)"/>
<stop offset="1" style="stop-color:var(--paper-light)"/>
</linearGradient>
<linearGradient id="pp-paper-left" x1="1" y1="0" x2="0" y2="0">
<stop offset="0" style="stop-color:var(--paper-shade)"/>
<stop offset="0.14" style="stop-color:var(--endpaper)"/>
<stop offset="1" style="stop-color:var(--paper-light)"/>
</linearGradient>
<linearGradient id="pp-sheen" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#fff" stop-opacity="0"/>
<stop offset="0.5" stop-color="#fff" stop-opacity="0.32"/>
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
</linearGradient>
<radialGradient id="pp-knob" cx="0.36" cy="0.3" r="0.75">
<stop offset="0" style="stop-color:var(--wood-light)"/>
<stop offset="0.6" style="stop-color:var(--wood)"/>
<stop offset="1" style="stop-color:var(--wood-deep)"/>
</radialGradient>
<linearGradient id="pp-wood" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" style="stop-color:var(--wood-deep)"/>
<stop offset="0.35" style="stop-color:var(--wood-light)"/>
<stop offset="0.7" style="stop-color:var(--wood)"/>
<stop offset="1" style="stop-color:var(--wood-deep)"/>
</linearGradient>
<linearGradient id="pp-metal" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#f4f6f7"/>
<stop offset="0.45" stop-color="#c4ccd1"/>
<stop offset="0.55" stop-color="#8e989f"/>
<stop offset="1" stop-color="#dfe4e7"/>
</linearGradient>
<!-- rubber-stamp ink: the edges wobble a little and the ink misses the paper here and there -->
<filter id="pp-ink" x="-30%" y="-30%" width="160%" height="160%">
<feTurbulence type="fractalNoise" baseFrequency="1.4" numOctaves="2" seed="5" result="noise"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="0.9" xChannelSelector="R" yChannelSelector="G" result="wobble"/>
<feColorMatrix in="noise" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2.4 1.86" result="holes"/>
<feComposite in="wobble" in2="holes" operator="in"/>
</filter>
<clipPath id="pp-cover-clip"><rect x="52" y="84" width="44" height="62" rx="3"/></clipPath>
<clipPath id="pp-page-clip"><rect x="52.4" y="84.8" width="42.8" height="60.4" rx="2"/></clipPath>
</defs>
<!-- the soft shadow the passport throws on the pill -->
<ellipse data-shadow cx="74" cy="148.4" rx="25" ry="2.4" fill="#062a2c" fill-opacity="0.26"/>
<g data-book>
<!-- the back cover, peeking out behind the pages -->
<rect x="52" y="84" width="44" height="62" rx="3" fill="url(#pp-leather)"/>
<!-- the silk bookmark ribbon, hanging out between the pages -->
<g data-ribbon>
<path d="M85.6 138 L85.6 155 L87.1 153.2 L88.6 155 L88.6 138 Z" style="fill:var(--ribbon)"/>
<path d="M86.3 140 L86.3 153.4" stroke="#fff" stroke-opacity="0.35" stroke-width="0.4" stroke-linecap="round"/>
</g>
<!-- the edges of the pages, a little block of paper -->
<g fill="none" stroke-width="0.35" style="stroke:var(--paper-shade)">
<path d="M95.7 86 L95.7 144"/><path d="M95.1 85.6 L95.1 144.4"/>
</g>
<!-- the next page, seen only while the visa page lifts -->
<rect x="52.4" y="85.2" width="42.4" height="59.6" rx="2" fill="url(#pp-paper)" stroke="#d9cdb2" stroke-width="0.25"/>
<g clip-path="url(#pp-page-clip)" data-leaf-lines fill="none" stroke-width="0.25" style="stroke:var(--guilloche)" stroke-opacity="0.45"></g>
<!-- the visa page, where the stamps land: it lifts after the cover and falls back -->
<g data-page data-leaf>
<rect x="52.4" y="84.8" width="42.8" height="60.4" rx="2" fill="url(#pp-paper)"/>
<g clip-path="url(#pp-page-clip)">
<g data-guilloche fill="none" stroke-width="0.25" style="stroke:var(--guilloche)" stroke-opacity="0.75"></g>
<text class="pp__tiny" x="74" y="90.2" text-anchor="middle">VISAS</text>
<g fill="none" stroke-width="0.25" style="stroke:var(--guilloche)" stroke-opacity="0.6">
<rect x="55.6" y="92.4" width="36.4" height="24.6" rx="0.8"/>
<rect x="55.6" y="118.2" width="36.4" height="24.6" rx="0.8"/>
</g>
<g data-marks></g>
<ellipse data-stamp-shadow cx="74" cy="104.6" rx="12" ry="5" fill="#2a1a12" fill-opacity="0"/>
</g>
<!-- the gutter: the paper curves into the spine -->
<rect x="52.4" y="84.8" width="3.6" height="60.4" fill="#5b4a2e" fill-opacity="0.12"/>
<rect data-shade x="52.4" y="84.8" width="42.8" height="60.4" rx="2" fill="#0b1626" fill-opacity="0"/>
</g>
<!-- the front cover: leather outside, endpaper inside; it turns round the spine -->
<g data-cover>
<g data-cover-out>
<rect x="52" y="84" width="44" height="62" rx="3" fill="url(#pp-leather)"/>
<rect x="52" y="84" width="44" height="62" rx="3" fill="url(#pp-pebble)"/>
<path d="M53 86.6 Q53 84.6 55 84.6 L93.6 84.6" fill="none" stroke="#fff" stroke-opacity="0.18" stroke-width="0.6" stroke-linecap="round"/>
<rect x="52" y="84" width="3.2" height="62" fill="#000" fill-opacity="0.24"/>
<path d="M55.4 84 L55.4 146" stroke="#fff" stroke-opacity="0.07" stroke-width="0.5"/>
<rect x="56.6" y="86.6" width="37" height="56.8" rx="1.8" fill="none" stroke="url(#pp-gold)" stroke-opacity="0.65" stroke-width="0.42" stroke-dasharray="1.3 0.9"/>
<g data-foil>
<text class="pp__foil" x="75" y="95.6" text-anchor="middle" data-cover-title>PASSPORT</text>
<!-- the crest: a globe between two branches of laurel -->
<g fill="none" stroke="url(#pp-gold)" stroke-width="0.6">
<circle cx="75" cy="113" r="7.6"/>
<ellipse cx="75" cy="113" rx="3.6" ry="7.6"/>
<path d="M75 105.4 L75 120.6"/>
<path d="M68 109.6 Q75 111.4 82 109.6"/><path d="M67.4 113 L82.6 113"/><path d="M68 116.4 Q75 114.6 82 116.4"/>
<path d="M65 106.4 Q62.6 113.6 67.4 120.2"/><path d="M85 106.4 Q87.4 113.6 82.6 120.2"/>
</g>
<g fill="url(#pp-gold)">
<ellipse cx="64.6" cy="109.4" rx="0.9" ry="1.8" transform="rotate(-24 64.6 109.4)"/>
<ellipse cx="64" cy="113.4" rx="0.9" ry="1.8" transform="rotate(-6 64 113.4)"/>
<ellipse cx="64.8" cy="117.4" rx="0.9" ry="1.8" transform="rotate(18 64.8 117.4)"/>
<ellipse cx="85.4" cy="109.4" rx="0.9" ry="1.8" transform="rotate(24 85.4 109.4)"/>
<ellipse cx="86" cy="113.4" rx="0.9" ry="1.8" transform="rotate(6 86 113.4)"/>
<ellipse cx="85.2" cy="117.4" rx="0.9" ry="1.8" transform="rotate(-18 85.2 117.4)"/>
</g>
<text class="pp__foil-small" x="75" y="129" text-anchor="middle">TRAVEL DOCUMENT</text>
<!-- the e-passport chip mark -->
<g fill="none" stroke="url(#pp-gold)" stroke-width="0.5">
<rect x="70.6" y="133.2" width="8.8" height="5.6" rx="1.4"/>
<path d="M73.6 133.2 L73.6 138.8 M76.4 133.2 L76.4 138.8 M70.6 136 L79.4 136"/>
</g>
</g>
<!-- worn corners -->
<path d="M93.4 84.4 Q95.6 84.4 95.6 86.6" fill="none" stroke="#fff" stroke-opacity="0.3" stroke-width="0.7" stroke-linecap="round"/>
<path d="M95.6 143.4 Q95.6 145.6 93.4 145.6" fill="none" stroke="#fff" stroke-opacity="0.16" stroke-width="0.7" stroke-linecap="round"/>
<g clip-path="url(#pp-cover-clip)">
<rect data-sheen x="30" y="80" width="14" height="70" fill="url(#pp-sheen)" transform="skewX(-18)"/>
</g>
</g>
<!-- the inside of the cover, drawn mirrored: once the cover has turned it reads the right way -->
<g data-cover-in visibility="hidden">
<g transform="matrix(-1 0 0 1 148 0)">
<rect x="52" y="84" width="44" height="62" rx="3" fill="url(#pp-leather)"/>
<rect x="52.4" y="84.8" width="42.8" height="60.4" rx="2" fill="url(#pp-paper-left)"/>
<g data-rosette fill="none" stroke-width="0.22" style="stroke:var(--guilloche)" stroke-opacity="0.7"></g>
<text class="pp__tiny" x="74" y="90.2" text-anchor="middle">TRAVEL DOCUMENT</text>
<g style="fill:var(--ink-print)" fill-opacity="0.5">
<rect x="57" y="114" width="16" height="1" rx="0.5"/><rect x="57" y="117" width="22" height="1" rx="0.5"/>
<rect x="57" y="120" width="12" height="1" rx="0.5"/><rect x="76" y="114" width="14" height="1" rx="0.5"/>
</g>
<!-- the holder's signature on its line -->
<path d="M57 127.6 L91 127.6" stroke-width="0.25" style="stroke:var(--ink-print)" stroke-opacity="0.5"/>
<path d="M58.6 126.6 C60 122.6 61.4 122.4 61.2 125 C61 127 62.6 124 64 123.8 C65.6 123.6 64.4 126.4 66 126 C67.6 125.6 68.6 123.4 70.4 124.2 C72 125 71 126.6 73.4 125.8 C75.4 125.2 77 124.4 79 125.2" fill="none" stroke-width="0.4" style="stroke:var(--ink-pen)" stroke-linecap="round"/>
<!-- the machine-readable lines at the bottom -->
<text class="pp__mrz" x="56.4" y="137.4" data-mrz-1>P<WYF<TRAVELLER<<<<<</text>
<text class="pp__mrz" x="56.4" y="141.6" data-mrz-2>X4821905<7WYF9605<<<</text>
</g>
</g>
</g>
</g>
<!-- the rubber stamp: a wooden knob, a brass collar, the block with its city label and the red rubber -->
<g data-stamp opacity="0">
<g data-stamp-tilt>
<g data-stamp-body>
<ellipse cx="0" cy="-37" rx="6.6" ry="5.8" fill="url(#pp-knob)"/>
<ellipse cx="-2.2" cy="-39.2" rx="2" ry="1.3" fill="#fff" fill-opacity="0.35"/>
<path d="M-2.6 -31.6 L2.6 -31.6 L3.6 -19 L-3.6 -19 Z" fill="url(#pp-wood)"/>
<path d="M-1.2 -30 L-1.6 -20.4" stroke="#fff" stroke-opacity="0.25" stroke-width="0.6" stroke-linecap="round"/>
<rect x="-5.6" y="-20.2" width="11.2" height="2.8" rx="0.9" fill="url(#pp-metal)"/>
<rect x="-11" y="-17.6" width="22" height="11.4" rx="1.6" fill="url(#pp-wood)"/>
<g fill="none" stroke="#3a2210" stroke-opacity="0.28" stroke-width="0.35" stroke-linecap="round">
<path d="M-10 -15.4 Q-3 -14.6 4 -15.6 T10 -15"/><path d="M-10 -9 Q-2 -8.2 3 -9.4 T10 -8.6"/>
</g>
<rect x="-6.4" y="-15" width="12.8" height="5.6" rx="0.6" fill="#fbf4e4"/>
<text class="pp__stamp-label" x="0" y="-10.9" text-anchor="middle" data-stamp-label>LIS</text>
<rect x="-11.6" y="-6.4" width="23.2" height="2.6" rx="0.6" fill="url(#pp-metal)"/>
<rect x="-10.6" y="-3.8" width="21.2" height="3.8" rx="0.8" style="fill:var(--rubber)"/>
<rect x="-10.6" y="-1" width="21.2" height="1" rx="0.5" style="fill:var(--ink)" fill-opacity="0.85"/>
</g>
</g>
</g>
</svg>
<p class="sr" 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.
44 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 del passaporto timbrato» da Animorio e adattala al mio sitoUn solo SVG sopra la punta sinistra della pillola, che non prende il puntatore: il clic va al vero <button> sotto. Dentro, a strati: la copertina dietro, il bordo delle pagine, la pagina dei visti, una pagina sciolta e la copertina davanti. La pelle è un gradiente con sopra un motivo di puntini chiari e scuri per la grana; la lamina e la cucitura usano un gradiente d'oro.
Un numero da 0 a 1 diventa scaleX = cos(πp) e skewY = -7·sin(πp) attorno al dorso (svgOrigin): la copertina si stringe, passa di taglio e si riapre dall'altra parte con un po' di prospettiva. Quando scaleX diventa negativo si spegne la faccia di pelle e si accende quella interna, disegnata già specchiata con una matrice, così dopo il giro si legge dritta. Un'ombra sulla pagina segue sin(πp).
Il timbro scende con back.out, prende la rincorsa e batte con power3.in in circa un decimo di secondo; al contatto tre tween in andata e ritorno schiacciano il timbro, il passaporto (attorno ai suoi piedi) e la pillola. L'ombra del timbro sulla pagina si allarga e si scurisce mentre si avvicina.
Il visto è testo e rettangoli SVG con un filtro: feTurbulence fa il rumore, feDisplacementMap muove appena i bordi, e lo stesso rumore, passato da una feColorMatrix, buca l'inchiostro dove la gomma non ha preso. All'impatto è pieno e lucido, poi in un secondo e mezzo si fa più opaco; sei schizzi intorno saltano fuori con back.out.
Un SVG con l'aeroplanino percorre un arco sopra le parole: a ogni fotogramma posizione e angolo vengono dalla curva, e i puntini della scia, già messi lungo l'arco, si accendono man mano che l'aereo li passa.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
LABEL | script.js | Book my trip | Le parole a riposo. |
NOTE | script.js | Lisbon · 3 nights | Le parole piccole sotto. |
BUSY | script.js | Checking passport… | Le parole mentre il passaporto viene controllato. |
DONE | script.js | Trip booked | Le parole quando il timbro è dato. |
CITIES | script.js | LIS,KYO,OSL,CUZ,MRK | Le sigle delle città dei timbri, una per prenotazione, a turno. |
DATE | script.js | 24 OCT 2026 | La data stampata sotto la città. |
THUMP | script.js | 1 | Quanto forte scende il timbro: 0,4 piano, 1,6 pesante. |
SPEED | script.js | 1 | Quanto corre tutto: 0,6 lento, 1,6 svelto. |
Per il pulsante di prenotazione di un'agenzia di viaggi, di una compagnia aerea, di un albergo o di un'app di viaggi, o per un pulsante che conferma un documento, un permesso o un'iscrizione.
Il componente è largo 330 pixel o lo schermo meno 32, e alto 156 con la pillola di 60; a riposo la scritta piccola sta sotto quella grande. Senza hover, il dito che si appoggia socchiude la copertina come il mouse.
Niente saltelli, niente copertina che gira, niente timbro che scende né aereo: al clic il passaporto si mostra aperto in una dissolvenza, il visto compare svanendo e le parole cambiano svanendo.
GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 12 KB; le librerie: GSAP 28 KB.
Provata il 23 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.