
La tabella con la botola
Tabelle, Fisica, SVG, Transizioni, 3D
NuovaGratis
Il modulo di contatto di una cartoleria scritto su un foglio di carta da lettere vergata, con la sua grana, a inchiostro blu nero. Gli errori si correggono sul foglio a matita, come un correttore di bozze: un cerchio intorno alla riga vuota, una riga ondulata e un segno d’inserimento dove manca la fine dell’email, una parentesi accanto a una lettera troppo corta; sistemato il campo, la matita si cancella e lascia un alone. Inviato, il foglio si piega in tre in 3D con le pieghe vere, luce e ombra su ogni faccia, scivola in una busta foderata, l’aletta si chiude, sopra si scrive il mittente, la busta si gira, prende un francobollo e il timbro postale e vola via; poi torna il foglio pulito con Sent. We’ll write back.
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 form that folds into an envelope</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bodoni-moda@5.3.0/opsz.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bodoni-moda@5.3.0/opsz-italic.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/caveat@5.3.0/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/shantell-sans@5.3.0/infm.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the contact form of a stationer, written on a sheet of laid letter paper: a mistake is corrected in pencil
on the sheet; sent, the sheet folds in three in 3D, slides into a lined envelope, the flap closes, the
envelope turns over, takes a stamp and a postmark and flies away. Sending is pretended: see post() in the
script -->
<div class="post" data-post data-autoclic>
<div class="desk" data-desk>
<span class="ground" aria-hidden="true" data-ground></span>
<form class="sheet" action="#" novalidate aria-labelledby="post-title" data-sheet>
<div class="paper" data-paper>
<header class="head">
<p class="head__from">
<svg class="head__mark" viewBox="0 0 28 28" aria-hidden="true"><path d="M14 2.5 25.5 14 14 25.5 2.5 14z"/><path d="M11 19.5V8.6h4.1c2.3 0 3.7 1.3 3.7 3.2s-1.4 3.2-3.7 3.2H11"/></svg>
<span>Quillmere Paper Co.</span>
</p>
<h2 class="head__title" id="post-title" tabindex="-1">
<span class="head__line" data-title-rest>Write to us.</span>
<span class="head__line head__line--sent" aria-hidden="true" data-title-sent>Sent. We’ll write back.</span>
</h2>
<p class="head__sub">
<span class="head__line" data-sub-rest>Wedding suites, letterheads, a box of samples: every letter is answered by hand.</span>
<span class="head__line head__line--sent" aria-hidden="true" data-sub-sent>Your letter is on its way to the letter desk. Our answer comes within two days.</span>
</p>
</header>
<div class="field" data-field="name">
<label class="field__label" for="post-name">Your name</label>
<div class="field__rule" data-rule>
<input class="ink" id="post-name" name="name" type="text" autocomplete="name" autocapitalize="words" spellcheck="false" enterkeyhint="next" aria-describedby="post-name-note" aria-invalid="false" data-input>
</div>
<p class="note" id="post-name-note" data-note></p>
</div>
<div class="field" data-field="email">
<label class="field__label" for="post-email">Where we write back</label>
<div class="field__rule" data-rule>
<input class="ink" id="post-email" name="email" type="text" inputmode="email" autocomplete="email" autocapitalize="off" autocorrect="off" spellcheck="false" enterkeyhint="next" placeholder="you@example.com" aria-describedby="post-email-note" aria-invalid="false" data-input>
</div>
<p class="note" id="post-email-note" data-note></p>
</div>
<div class="field field--letter" data-field="letter">
<label class="field__label" for="post-letter">Your letter</label>
<div class="field__rule field__rule--lines" data-rule>
<textarea class="ink ink--letter" id="post-letter" name="letter" rows="3" spellcheck="true" aria-describedby="post-letter-note" aria-invalid="false" data-input></textarea>
</div>
<p class="note" id="post-letter-note" data-note></p>
</div>
<div class="foot">
<p class="foot__sign">Yours, <span class="foot__name" data-sign></span></p>
<button class="send" type="submit" data-send>
<span class="send__bg" aria-hidden="true"></span>
<span class="send__label">Send the letter</span>
<svg class="send__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3.5 6.5h17v11h-17z"/><path d="m3.8 6.8 8.2 6.4 8.2-6.4"/></svg>
</button>
</div>
<svg class="pencil" aria-hidden="true" data-pencil>
<defs>
<filter id="post-graphite" x="-10%" y="-30%" width="120%" height="160%">
<feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="2" seed="7" result="grain"/>
<feColorMatrix in="grain" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.5 1.45" result="tooth"/>
<feComposite in="SourceGraphic" in2="tooth" operator="in"/>
</filter>
<filter id="post-smudge" x="-20%" y="-60%" width="140%" height="220%">
<feGaussianBlur stdDeviation="2.4"/>
</filter>
</defs>
</svg>
</div>
</form>
<!-- what the sheet becomes when it is sent: drawn for the eye only, the form itself stays above -->
<div class="env" aria-hidden="true" data-env>
<div class="env__turn" data-turn>
<div class="env__back" data-back>
<span class="env__wall" data-wall></span>
<div class="flap" data-flap>
<span class="flap__in" data-flap-in></span>
<span class="flap__out" data-flap-out>
<span class="flap__from" data-from><span class="flap__who" data-from-name></span><span class="flap__mail" data-from-mail></span></span>
</span>
</div>
<div class="fold" data-fold></div>
<svg class="pocket" data-pocket></svg>
<span class="env__shade" data-env-shade></span>
</div>
<div class="env__front" data-front>
<span class="env__border"></span>
<span class="airmail">By air mail</span>
<span class="env__to">
<span class="env__to-desk">The Letter Desk</span>
<span>Quillmere Paper Co.</span>
<span>4 Ropewalk Yard</span>
<span>Quillmere</span>
</span>
<span class="stamp" data-stamp>
<svg viewBox="0 0 60 72" data-stamp-art></svg>
</span>
<svg class="cancel" data-cancel></svg>
</div>
</div>
</div>
</div>
<p class="sr" role="status" 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.
48 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 modulo che si piega in busta» da Animorio e adattala al mio sitoDue input e una textarea veri con le loro label (autocomplete name ed email, inputmode email, testo a 27 pixel, oltre i 16 che servono a Safari sul telefono per non ingrandire), aria-invalid e aria-describedby verso la parola a matita sotto ogni campo, che è testo vero e si legge. Invio nel nome passa all’email, nell’email alla lettera, Ctrl o Cmd con Invio nella lettera spedisce. All’invio sbagliato il fuoco va al primo campo da sistemare e una regione aria-live dice cosa controllare; a lettera spedita legge Sent. We’ll write back. e il fuoco va al titolo. La spedizione è finta in una funzione sola, post(), quella da sostituire con la chiamata vera.
I segni sono tracciati in SVG sopra il foglio, misurando dove stanno i campi con offsetTop e offsetLeft (che non sentono le trasformazioni) e dove finiscono le parole con measureText su un canvas, col carattere vero del campo. Il cerchio è poco più di un giro con il raggio che ondeggia per due seni e cresce un poco, così l’inizio e la fine non combaciano; la riga ondulata, il segno d’inserimento, la parentesi e la spunta sono punti con un tremito casuale ma ripetibile (un generatore con il seme), uniti da curve di Catmull-Rom. Ogni tratto ha pathLength 1 e si disegna con stroke-dashoffset; la grafite è un filtro SVG che con feTurbulence buca il tratto. Cancellando, i tratti passano in un gruppo loro e svaniscono mentre una copia larga e sfocata fa l’alone; al resize i segni si ridisegnano dove sono andati i campi.
All’invio il foglio si copia sei volte così com’è (con quello che c’è scritto, senza id, name e attributi aria), e ogni copia sta dentro una faccia con overflow hidden spostata di un terzo: tre pannelli, ognuno col davanti e il retro, il retro girato con rotateX(180) e backface-visibility hidden. Il pannello di mezzo tiene gli altri due come figli in preserve-3d: quello di sotto ruota sul suo bordo alto, quello di sopra sul suo bordo basso. Ogni cerniera sta mezzo spessore di carta sopra il foglio (translateZ, rotateX, translateZ all’indietro), e il secondo un poco più su del primo: così, piegati, gli strati si impilano nell’ordine giusto senza tremolii. Il retro mostra la scrittura in trasparenza, capovolta e sfocata, al cinque per cento.
A ogni fotogramma si calcola la normale di ogni faccia: tutte le rotazioni sono attorno allo stesso asse, quindi gli angoli si sommano (l’inclinazione del foglio più quella della piega) e la normale è (0, −sin a, cos a). Il prodotto scalare con la direzione della lampada, meno quello del foglio piatto, dice quanto la faccia si schiarisce o si scurisce, e uno strato sopra la faccia prende quel colore caldo. Una piega appena fatta si riapre di RELAX gradi e la seconda la schiaccia piatta quando arriva; mentre i terzi si chiudono, sulla faccia di mezzo cresce l’ombra, il bordo della piega prende un filo di luce e alla fine una lucentezza corre lungo la piega come una stecca d’osso. Sotto, un’ombra sulla scrivania segue la sagoma del foglio piegato e si allarga e si schiarisce quando un terzo si solleva.
Il dietro della busta è un piano unico con i suoi strati in ordine di z-index: la fodera, l’aletta, la lettera, i lembi disegnati in SVG (rifatti in pixel quando cambia la misura) e l’ombra dell’aletta. La lettera sta dentro la busta fin dall’inizio, così passa davvero fra la fodera e i lembi; la sua posizione si scrive togliendo quella della busta. L’aletta è un piano piatto che ruota con rotateX: oltre i 90 gradi si vede la fodera, sotto i 90 passa sopra i lembi cambiando z-index, e si scurisce o si schiarisce con la stessa luce. Il davanti è l’altra faccia di un contenitore in preserve-3d che gira con rotateY; il francobollo ha la dentellatura fatta con una maschera di cerchi, il timbro un rullo che è un rettangolo di maschera che si allarga e un inchiostro irregolare fatto con feTurbulence e feDisplacementMap. Il volo è una curva di Bézier quadratica; tutto è una timeline di GSAP sola che a ogni fotogramma chiama render(). Un clic da script (detail 0, l’anteprima) fa il giro intero senza prendere il fuoco: scrive, sbaglia l’email, la matita corregge, la mano aggiunge la fine, spedisce, e alla fine il titolo torna a riposo.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
FOLD | script.js | 0.6 | Quanti secondi impiega ogni terzo del foglio a ripiegarsi. |
RELAX | script.js | 7 | Di quanti gradi si riapre una piega appena fatta, prima che il terzo dopo la schiacci piatta: 0 è carta che resta giù. |
TILT | script.js | 12 | Di quanti gradi il foglio si inclina all’indietro mentre si piega, per far vedere lo spessore. |
FLAP | script.js | 0.55 | Quanti secondi impiega l’aletta della busta a chiudersi. |
HOLD | script.js | 0.9 | Quanti secondi la busta timbrata resta sulla scrivania prima di volare via. |
FLIGHT | script.js | 0.85 | Quanti secondi dura il volo della busta. |
SETTLE | script.js | 0.7 | I secondi di silenzio dopo l’ultimo tasto prima che il campo si rilegga. |
SHORTEST | script.js | 12 | Quante lettere deve avere almeno il messaggio. |
TOWN | script.js | QUILLMERE | Il paese scritto in giro sul timbro postale. |
STAMP_VALUE | script.js | 1.85 | Il valore stampato sul francobollo. |
Nella pagina dei contatti di chi lavora con la carta e le parole: una cartoleria, una tipografia, uno studio di grafica, un fotografo di matrimoni, un piccolo albergo che risponde a mano. La busta che parte è la ricevuta che chi scrive si porta via: sa che il messaggio è partito e a chi. La correzione a matita va bene in qualsiasi modulo: non grida mentre si scrive, aspetta che si lasci il campo e se ne va appena è giusto. Per un altro marchio si cambiano i colori, l’indirizzo, il francobollo e il timbro.
Il foglio prende la larghezza dello schermo (358 pixel su un telefono di 390) e la busta il 94 per cento del foglio, quindi niente esce di lato; il volo va verso l’alto e la busta sparisce prima del bordo. I campi sono alti 40 pixel e la lettera 108, il pulsante 50, tutti oltre i 44 di un dito; il testo è a 27 pixel, così Safari non ingrandisce la pagina al tocco; l’email apre la tastiera con la @ e il tasto Invio dice Next. Il pulsante, che sul computer al passaggio del puntatore si gonfia e cambia il taglio delle lettere, al tocco si schiaccia. Le stesse pieghe, la stessa busta e lo stesso volo, con le misure del telefono.
Niente pieghe, niente volo e niente tratti che corrono: i segni a matita e le parole sotto i campi compaiono e se ne vanno in dissolvenza. All’invio il foglio sfuma nella busta già chiusa e girata, poi in dissolvenza arrivano il francobollo e il timbro; dopo lo stesso momento di attesa la busta sfuma via e il foglio pulito torna in dissolvenza con Sent. We’ll write back. Il titolo cambia incrociandosi senza muoversi.
GSAP 3.15.0, Bodoni Moda (font variabile) 5.3.0, Caveat (font variabile) 5.3.0, Shantell Sans (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 22 KB; le librerie: GSAP 28 KB.
Provata il 17 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.