Vai al contenuto
animorio
EN
Tutti i componenti

La card della tessera da forare

Card, Fisica, SVGGSAP, Solo CSSImpegnativaPeso compresso: Demo 9,5 KBGSAP 28 KBGratisScarica lo zip

La tessera fedeltà di una piccola torrefazione, di cartoncino color crema, con dieci chicchi di caffè stampati: a ogni caffè la foratrice si porta via il chicco successivo. La card si piega sotto la pressione verso quel chicco e torna su passando di un pixel; il pezzetto di carta esce dal retro, lo vedi cadere attraverso il suo stesso buco, nell’ombra della card, e uscire rigirandosi da sotto il bordo. In ogni buco si vede la pagina con l’ombra vera della card. Undo lo fa risalire e lo rimette nel buco; piena, la tessera prende il timbro Redeemed e al tocco dopo ne arriva una nuova.

Il codice

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 punch card</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the loyalty card of a small coffee roaster, on paper. Every cup bought the card is punched: the punch
         bites a coffee bean out of it, the card dips under the press and springs back, and the little paper bean
         falls out of the back of the card, seen through its hole, and tumbles out from under it. Through every hole
         you see the page, with the card's own shadow in it. Full, the card is redeemed with a stamp, and a fresh one
         takes its place. The paper, the beans and the stamp are drawn by the script and the CSS -->
    <div class="loyalty" data-loyalty>
      <div class="chads" aria-hidden="true" data-chads></div>
      <div class="deal" data-deal>
      <div class="tilt" data-tilt>
        <button class="card" type="button" data-card data-autoclic aria-describedby="loyalty-status">
          <svg class="paper" viewBox="0 0 320 420" aria-hidden="true" data-paper>
            <defs>
              <mask id="loyalty-holes" maskUnits="userSpaceOnUse" x="-10" y="-10" width="340" height="440">
                <rect x="-10" y="-10" width="340" height="440" fill="#fff" />
                <g data-holes></g>
              </mask>
            </defs>
            <g mask="url(#loyalty-holes)">
              <rect class="paper__sheet" width="320" height="420" rx="16" />
              <rect class="paper__frame" x="10.5" y="10.5" width="299" height="399" rx="9" />
              <path class="paper__rule" d="M24 238.5H296" />
              <g data-beans></g>
              <g class="stamp" data-stamp>
                <rect class="stamp__box" x="-88" y="-27" width="176" height="54" rx="6" />
                <rect class="stamp__box stamp__box--in" x="-82" y="-21" width="164" height="42" rx="3" />
                <text class="stamp__word" y="-1">Redeemed</text>
                <text class="stamp__date" y="13" data-stamp-date>19 Oct 2026</text>
              </g>
            </g>
          </svg>
          <span class="card__words">
            <span class="card__brand">Halde</span>
            <span class="card__kind">Coffee roasters &middot; Loyalty card</span>
            <span class="card__headline" data-headline>Ten cups, the eleventh is on us.</span>
            <span class="card__status" id="loyalty-status"><span class="card__num" data-num>Four</span><span data-rest> cups to go</span></span>
            <span class="card__small">Valid at both Halde counters</span>
          </span>
          <span class="sr" data-label>Punch a cup</span>
        </button>
        <button class="undo" type="button" data-undo hidden>
          <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M5.5 4.5 2.5 7.5l3 3M3 7.5h6.5a3.5 3.5 0 0 1 0 7H8" /></svg>
          <span>Undo</span>
        </button>
      </div>
      </div>
      <p class="hint" aria-hidden="true" data-hint>Press the card to punch a cup</p>
      <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>

Playground

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.

26 valori da cambiare

Oppure chiedila a Claude Code

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 della tessera da forare» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco una tessera di cartoncino crema larga 320 pixel, con gli angoli tondi, un filetto stampato tutto intorno e un’ombra morbida sulla pagina. In alto il nome della torrefazione, Halde, in Bricolage Grotesque stretto e nerissimo, sotto Coffee roasters · Loyalty card e la frase Ten cups, the eleventh is on us. Poi quanti caffè mancano, col numero scritto in lettere arancioni (Four cups to go), una riga sottile e due file di cinque chicchi di caffè stampati, inclinati, col contorno tratteggiato e la piega a S; l’ultimo, quello del premio, è stampato in arancione. Sei chicchi sono già forati: al loro posto c’è un buco a forma di chicco e dentro si vede la pagina bianca, con una mezzaluna d’ombra in alto. Col puntatore sopra la tessera si alza di qualche pixel e l’ombra si allarga anche dentro i buchi; il chicco che verrà forato si fa arancione pieno e un poco più grande. Tenendo premuto la tessera si piega in 3D verso quel chicco; lasciando, il chicco sparisce, la tessera torna su passando un poco il segno e oscilla, e il pezzetto di carta tagliato, in ombra, si vede scendere dentro il buco, allontanarsi e cadere girando su se stesso fino a uscire dal bordo di sotto, dove svanisce. Il numero sale fuori dalla riga e quello nuovo entra dal basso con un piccolo rimbalzo e più peso. In alto a destra compare Undo: il chicco risale da sotto la tessera rigirandosi e torna nel suo buco, che si chiude. Al decimo buco la riga dice This one is on us; premendo, il timbro arancione Redeemed con la data di oggi scende sui buchi con un colpo e la tessera sobbalza; premendo ancora la tessera vecchia scivola giù e ne arriva una nuova dall’alto, tutta da forare.

Come funziona

Il cartoncino tagliato da una maschera

La tessera è un SVG di 320 × 420: il cartoncino, il filetto, i chicchi stampati e il timbro stanno in un gruppo con una mask, e ogni buco è un ovale nero nella maschera. Forare vuol dire accendere quell’ovale: il taglio è netto a ogni misura, e i chicchi stampati sotto il taglio si nascondono, perché il pezzo se li porta via.

L’ombra che entra nei buchi

L’ombra non è un box-shadow ma due drop-shadow sul cartoncino già tagliato: una stretta che disegna il bordo di ogni buco e una morbida che dice quanto è alta la tessera. Siccome si calcolano sulla forma tagliata, dentro ogni buco cade da sola la mezzaluna d’ombra del cartoncino, e quando la tessera si alza la mezzaluna cresce.

Due molle per la tessera

La pressione e il sollevamento sono due molle integrate sul ticker di GSAP in quattro sotto-passi col passo limitato a 1/30 di secondo (SPRING). La pressione gira la tessera in 3D verso il chicco di turno (rotateX e rotateY in proporzione alla sua posizione, PRESS gradi) e la spinge indietro; al rilascio torna su oltre il riposo e oscilla. Un tasto o un clic dello script fanno pressione e rilascio in un colpo solo, con una spinta alla molla.

Il pezzetto che cade dal retro

Ogni pezzo tagliato è un piccolo SVG in uno strato sotto la tessera: parte esattamente dietro il suo buco, quindi si vede solo attraverso il buco, in ombra, mentre si rimpicciolisce un poco allontanandosi. Ha gravità (GRAVITY), una spinta di lato, una rotazione e un giro su se stesso fatto con scaleY = cos dell’angolo: quando il coseno è negativo mostra il retro del cartoncino. Sotto il bordo esce dall’ombra e svanisce in trenta pixel.

Undo, il timbro e la tessera nuova

Undo riprende il pezzo da dove si trova (o da sotto il bordo, se è già caduto) e con una timeline lo riporta al buco rigirandolo al dritto; quando arriva il buco si chiude e la tessera riceve un colpetto. Il timbro scende con power4.in, la tessera sobbalza all’impatto e il timbro si assesta con un elastico; la tessera nuova arriva con back.out.

Tastiera e tocco

La tessera è un button: Invio e Spazio forano, riscattano o chiedono la tessera nuova, Undo è un button suo e Ctrl o Cmd+Z fanno lo stesso. Il focus da tastiera alza la tessera e mostra il chicco di turno come il passaggio del mouse; al telefono il dito la piega dove forerà. Un aria-live dice quanti caffè mancano.

Valori da cambiare

NomeFileDi partenzaCosa cambia
CUPSscript.js10Quanti caffè riempiono la tessera, in due file (da 6 a 12). La frase in alto si scrive da sola.
PUNCHEDscript.js6Quanti caffè sono già forati quando si apre la pagina.
PRESSscript.js5Quanto si piega la tessera sotto la foratrice, in gradi.
SPRINGscript.js[260, 0.36]La molla della tessera: quanto è rigida e quanto è frenata (1 = senza rimbalzi).
GRAVITYscript.js1600Quanto in fretta cade il pezzetto forato, in pixel al secondo quadrato.
LIFTscript.js5Quanto si alza la tessera col puntatore sopra, in pixel.
SLANTscript.js-14L’inclinazione dei chicchi stampati, in gradi.

Provali nel Playground

Quando usarla

Per la tessera fedeltà di un bar, di una torrefazione, di una gelateria, di un panificio o di un parrucchiere, nell’app o nel sito dove il cliente vede i suoi punti; anche per una raccolta di bollini, un abbonamento a ingressi o un pass da dieci lezioni.

Sul telefono

La tessera è larga 320 pixel, o lo schermo meno 32, e tutte le scritte sono in unità del contenitore, così restano al loro posto a ogni misura. Col dito la tessera si piega dove forerà, al rilascio fora; Undo ha un’area di tocco di 36 pixel. Molle, caduta e tempi sono quelli del computer.

Con il movimento ridotto

Niente piega, niente sollevamento e niente pezzetti che cadono: il buco compare con una dissolvenza, Undo lo richiude allo stesso modo, il numero cambia con una dissolvenza, il timbro appare piano e la tessera nuova arriva in dissolvenza.

Trappole

  • Una sola ombra morbida rendeva i buchi grigi e sfocati, come avvallamenti: ne serve una seconda, stretta e più scura, che disegna il taglio. Tutte e due sono drop-shadow sul gruppo già tagliato dalla maschera (un box-shadow ignorerebbe i buchi).
  • Col movimento ridotto il chicco stampato restava visibile: il suo contorno tratteggiato sta proprio sul taglio e metà del tratto, fuori dal buco, faceva un anello. Il chicco forato si nasconde sempre.
  • Uno scale in CSS sul chicco di turno cancellerebbe il transform dell’attributo (translate e rotate) e lo manderebbe nell’angolo: il chicco ha due gruppi, quello esterno per la posizione e quello interno per la molla del CSS.
  • Il clic dell’anteprima e Invio arrivano senza pointerdown: la tessera non si piegava e il buco compariva su una tessera ferma. Un clic senza pressione dà una spinta alla molla e fora 70 millisecondi dopo, quando la tessera è giù.

Librerie

GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.

Compressi con gzip, i tre file della demo pesano 9,5 KB; le librerie: GSAP 28 KB.

Collaudo

Provata il 19 ottobre 2026

  • Computer: Fatto
  • Telefono: Fatto
  • Movimento ridotto: Fatto
  • Safari su iPhone: Da fare

Licenza d’uso

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.

Tutti i componenti