
Il rullo delle ore
Selettori, 3D, Fisica
NuovaGratis
Il pulsante Add to cart di una piccola bottega, con una scatola di cartone ondulato aperta nella punta tonda della pillola, fatta in vero CSS 3D: fondo, pareti e quattro alette, ognuna col suo dentro e il suo fuori. Le alette stanno su molle vere e fremono verso il puntatore. Al clic un vasetto di candela cade nella scatola, le alette si chiudono una dopo l'altra sbattendo e rimbalzando, un nastro adesivo corre sulla fessura e la scatola fa un saltello: Added, Ships tomorrow. Un altro clic taglia il nastro, le alette si riaprono di scatto e entra un'altra candela: 2 in cart.
Una cartella che funziona da sola: index.html, style.css, script.js e le librerie da CDN. Nella scheda React 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 cardboard box button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the cardboard box button: an Add to cart pill with an open corrugated box in its round right end, built in CSS 3D
with its four flaps up. A click drops a candle jar into the box, the flaps close one after the other on springs
and bounce, a strip of tape runs over the seam and the box hops: Added, Ships tomorrow. Another click cuts the
tape, the flaps spring open and one more candle goes in. The flaps shiver towards the pointer -->
<div class="pack" data-pack>
<button class="pack__btn" type="button" data-btn data-autoclic>
<span class="pack__fill" aria-hidden="true"></span>
<span class="pack__faces">
<span class="pack__face" data-face="rest">
<span class="pack__word" data-wide="Add to cart" data-rest-text>Add to cart</span>
<span class="pack__price" data-price-text>€32</span>
</span>
<span class="pack__face pack__face--busy" data-face="busy" aria-hidden="true">
<span class="pack__shine" data-busy-text>Packing…</span>
</span>
<span class="pack__face pack__face--done" data-face="done" aria-hidden="true">
<span class="pack__lines">
<span class="pack__lead">
<svg class="pack__tick" viewBox="0 0 20 20" aria-hidden="true"><path d="M4.6 10.4l3.5 3.5 7.4-8" pathLength="1" data-tick/></svg>
<span data-lead-text>Added</span>
</span>
<span class="pack__ship" data-ship-text>Ships tomorrow</span>
</span>
</span>
</span>
<!-- the box: a perspective, a layer that hops, and the box turned towards you, every wall and flap a plane with
an outside and an inside -->
<span class="crate" aria-hidden="true" data-crate>
<span class="crate__shadow" data-shadow></span>
<span class="crate__hop" data-hop>
<span class="crate__rig">
<span class="wall wall--floor"><span class="side side--in"></span></span>
<span class="wall wall--back"><span class="side side--out"></span><span class="side side--in"></span></span>
<span class="wall wall--left"><span class="side side--out"></span><span class="side side--in"></span></span>
<span class="wall wall--right"><span class="side side--out"></span><span class="side side--in"></span></span>
<span class="jars" data-jars></span>
<span class="wall wall--front"><span class="side side--out side--print"></span><span class="side side--in"></span></span>
<span class="flap flap--left" data-flap="left"><span class="side side--out"></span><span class="side side--in"></span></span>
<span class="flap flap--right" data-flap="right"><span class="side side--out"></span><span class="side side--in"></span></span>
<span class="flap flap--back" data-flap="back"><span class="side side--out"><span class="tape tape--half" data-tape></span></span><span class="side side--in"></span></span>
<span class="flap flap--front" data-flap="front"><span class="side side--out"><span class="tape tape--half" data-tape></span></span><span class="side side--in"></span></span>
<span class="tab tab--left" data-tab><span class="tape" data-tab-tape></span></span>
<span class="tab tab--right" data-tab><span class="tape" data-tab-tape></span></span>
<span class="cut" data-cut></span>
</span>
</span>
</span>
</button>
<p class="sr" aria-live="polite" data-live></p>
</div>
</main>
<!-- the candle that goes in, copied by the script for each one -->
<template data-jar>
<span class="jar">
<svg class="jar__art" viewBox="0 0 30 40" aria-hidden="true">
<defs>
<linearGradient id="jar-glass" x1="0" x2="1">
<stop offset="0" class="glass-edge"/>
<stop offset="0.18" class="glass"/>
<stop offset="0.32" class="glass-lit"/>
<stop offset="0.5" class="glass"/>
<stop offset="0.85" class="glass-deep"/>
<stop offset="1" class="glass-edge"/>
</linearGradient>
<linearGradient id="jar-wax" x1="0" x2="1">
<stop offset="0" class="wax-deep"/>
<stop offset="0.4" class="wax"/>
<stop offset="1" class="wax-deep"/>
</linearGradient>
</defs>
<path d="M5 6.5h20v27.5q0 3.5-3.5 3.5h-13q-3.5 0-3.5-3.5z" fill="url(#jar-glass)"/>
<ellipse cx="15" cy="9" rx="9.2" ry="2.3" fill="url(#jar-wax)"/>
<path class="jar__wick" d="M15 9V5.6"/>
<rect class="jar__label" x="5" y="17" width="20" height="11"/>
<path class="jar__ink" d="M9 21.2h12M10.5 24.2h9"/>
<path class="jar__gleam" d="M7.4 8.5v25"/>
<ellipse class="jar__lip" cx="15" cy="6.5" rx="10" ry="2.2"/>
</svg>
</span>
</template>
<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.
33 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 scatola di cartone» da Animorio e adattala al mio sitoLa scatola è un gruppo di span in transform-style: preserve-3d sotto una prospettiva di 360 pixel, girato di rotateX(-32deg) rotateY(-34deg). Il fondo, le quattro pareti e le quattro alette sono piani messi al loro posto con translateZ, translateX e rotateY dal centro della scatola; ogni piano ha due facce, il fuori e il dentro girato di mezzo giro, con backface-visibility: hidden, così da ogni lato si vede il cartone giusto. Le misure (--bw, --bd, --bh, --fl) stanno in :root e lo script le rilegge. Il cartone ondulato è un repeating-linear-gradient sottile sopra il colore kraft; la luce di ogni faccia è uno strato scuro con l'opacità --shade.
Ogni aletta è incernierata sul bordo alto della sua parete (transform-origin: 50% 100%) e gira con rotateX: 0 dritta in su, 90 chiusa sulla scatola, i numeri negativi aperta in fuori. Il suo angolo segue una molla smorzata calcolata a ogni fotogramma, a passi di 1/240 di secondo (SWING oscillazioni al secondo, DAMPING); per chiudere il bersaglio è un poco oltre i 90 gradi, quindi l'aletta sbatte sul fermo dei 90 e rimbalza tenendo una parte della velocità (BOUNCE), poi resta premuta. Le alette lunghe, quasi chiuse, si alzano di 0,9 pixel per stare sopra le corte. La luce del fuori è il prodotto scalare fra la sua normale (quella della parete girata verso l'alto dall'angolo) e la direzione della lampada.
Ogni aletta sa da che parte guarda sullo schermo. Col puntatore sul pulsante il suo bersaglio si alza di 6 gradi più 22 per quanto guarda verso il puntatore, e ci si aggiunge un fremito di rumore a gradiente su due frequenze (9 e 23 al secondo), più forte per l'aletta che lo guarda; tutto moltiplicato per SHIVER e per quanto il puntatore è sul pulsante, che sale e scende con GSAP. Le molle fanno il resto: le alette tremano senza scatti.
La candela è un SVG (vetro ambrato in gradiente, cera, stoppino, etichetta) su un piano dentro lo spazio 3D della scatola, girato all'opposto della scatola (rotateY(34deg) rotateX(32deg)) così guarda sempre verso di te; il browser lo ordina in profondità con le pareti, quindi entrando sparisce dietro la faccia davanti. Cade con un'accelerazione (power2.in), si schiaccia e torna su un elastico, e la scatola cede nello stesso istante: uno scaleY dal suo fondo che torna con elastic.out. Ci sono due posti nel fondo: una candela nuova prende quello della più vecchia, che sta sotto le alette chiuse e sparisce senza che si veda.
Il nastro è fatto di quattro pezzi: due metà sulle alette lunghe, lungo il loro bordo libero, e due linguette sui fianchi. Le metà si allungano insieme con scaleX dopo la linguetta di sinistra e prima di quella di destra, e sembrano un nastro solo. Stando sulle alette, quando la scatola si riapre le due metà se ne vanno ognuna con la sua aletta, come un nastro tagliato; prima una lama chiara corre sulla fessura. La scatola salta su un livello suo (y −12 e ritorno con power2), e atterrando si schiaccia dal fondo; l'ombra sotto si stringe mentre è in aria.
Tre facce sovrapposte, larghe quanto le parole: a riposo con la copia larga invisibile per l'allargamento sotto il mouse (font-stretch da 86 a 100 per cento), Packing… col riflesso che la attraversa, e la faccia finale su due righe. Il pulsante è un button vero: aria-disabled mentre impacchetta, una zona aria-live dice Packing Fig & cedar candle… e poi Added. 1 in cart. Ships tomorrow., e l'aria-label dice che il clic dopo ne aggiunge un'altra. Il primo giro dura 2,1 secondi e quelli dopo 2,6, meno dei 2,8 fra un clic e l'altro dell'anteprima.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
LABEL | script.js | Add to cart | La scritta a riposo. Se è troppo lunga per lo spazio, il carattere si rimpicciolisce. |
PRICE | script.js | €32 | Il prezzo, nella sua pillolina accanto alla scritta. |
BUSY | script.js | Packing… | La scritta mentre la candela entra e la scatola si chiude. |
ADDED | script.js | Added | La riga piccola la prima volta, dopo la spunta. |
UNIT | script.js | in cart | La riga piccola dalla seconda volta, dopo il numero. |
SHIP | script.js | Ships tomorrow | La riga grande quando la scatola è chiusa: in un sito vero la data la dice il tuo negozio. |
PRODUCT | script.js | Fig & cedar candle | Il prodotto, per la zona aria-live: in un sito vero è quello della pagina, e l'aggiunta va collegata al tuo carrello. |
SWING | script.js | 3.4 | Le oscillazioni al secondo delle alette sulle loro molle: più alto, cartone rigido e scatti svelti; più basso, alette molli e lente. |
DAMPING | script.js | 0.26 | Quanto le alette sono frenate: 0,08 sbattono e ondeggiano a lungo, 1 vanno dritte al loro posto. |
BOUNCE | script.js | 0.38 | Quanta velocità tiene un'aletta quando sbatte sulla scatola: 0 si ferma di colpo, 0,8 rimbalza più volte. |
SHIVER | script.js | 1 | Quanto le alette fremono e si alzano verso il puntatore: 0 restano ferme. |
OPEN | script.js | [-72, -34, -44, -66] | Gli angoli delle alette aperte, in gradi oltre la verticale: davanti, dietro, sinistra, destra. Oltre −60 un'aletta pende in fuori e mostra il suo dentro. |
Per il pulsante Aggiungi al carrello di una bottega che spedisce: candele, ceramiche, tè, cosmetici, libri, cose fatte a mano. La scatola che si chiude racconta la spedizione, e la riga Ships tomorrow è il posto giusto per la data di consegna vera. Va collegato al carrello e alla data del tuo negozio: qui è tutto simulato.
La pillola è larga circa 260 pixel: a 390 ci sta con margine, e se la scritta non ci sta il carattere si rimpicciolisce. Il dito sul pulsante fa fremere le alette verso di sé e il tocco aggiunge; la scatola resta della stessa misura.
Niente molle né saltelli: le alette stanno ferme aperte, non fremono, il fondo non si gonfia e la scritta non si allarga (sotto il mouse il fondo si schiarisce appena). Al clic le facce della scatola svaniscono e tornano già chiuse, col nastro e la candela dentro, mentre Packing… e poi Added, Ships tomorrow arrivano in dissolvenza. Un altro clic fa lo stesso e il numero sale.
GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 13 KB; le librerie: GSAP 28 KB.
Provata il 12 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.