Vai al contenuto
animorio
EN
Tutti i componenti

Il modulo che si piega in busta

Moduli, 3D, Transizioni, SVGGSAP, Solo CSS, CanvasImpegnativaPeso compresso: Demo 22 KBGSAP 28 KBGratisScarica lo zip

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.

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 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>

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.

48 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 «Il modulo che si piega in busta» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco un foglio di carta da lettere color crema, con le righe fitte della vergatura, le linee più rade dei filoni, una grana di puntini e fibre e un’ombra morbida. In cima il marchio Quillmere Paper Co. impresso a secco, senza inchiostro, poi il titolo in corsivo Write to us. e la riga Wedding suites, letterheads, a box of samples: every letter is answered by hand. Sotto, tre campi stampati come righe su cui scrivere: Your name, Where we write back e Your letter su tre righe; quello che si scrive esce in una calligrafia a inchiostro blu nero. In fondo Yours, seguito dal nome che si sta scrivendo, come una firma, e il pulsante blu Send the letter con una busta disegnata. Un campo giusto prende una spunta a matita in fondo alla sua riga. Lasciando un campo sbagliato, o premendo Send the letter, la matita corregge il foglio: un cerchio fatto a mano intorno alla riga vuota, una riga ondulata sotto un’email sbagliata con un segno d’inserimento dove manca la fine, una parentesi nel margine accanto a una lettera troppo corta, e sotto ogni campo una parola scritta a matita da sinistra a destra (add the ending, like .com; your name, please; a few words, please). Premendo di nuovo con lo stesso errore la matita ripassa il segno. Appena il campo è giusto il segno si cancella, resta un alone grigio per un attimo e arriva la spunta. Se tutto è giusto il foglio si inclina un poco all’indietro e si piega in tre: il terzo di sotto sale verso chi guarda e si ripiega sul centro, si riapre un poco come la carta vera, e il terzo di sopra scende e lo schiaccia piatto; ogni faccia si schiarisce o si scurisce secondo come guarda la luce, il retro lascia trasparire la scrittura al contrario e una lucentezza corre lungo la piega. Da sotto sale una busta aperta foderata di verde con un rametto d’oro, la lettera piegata si alza, entra nella busta passando dietro i lembi, l’aletta si chiude, la busta accusa il colpo e sull’aletta si scrivono il nome e l’email di chi scrive. La busta si gira sollevandosi: davanti ha il bordo a strisce rosse e blu della posta aerea, l’etichetta By air mail e l’indirizzo The Letter Desk, Quillmere Paper Co., 4 Ropewalk Yard, Quillmere. Un francobollo con un faro al tramonto scende dall’alto, si attacca con un piccolo schiacciamento e un rimbalzo, e il rullo del timbro passa da sinistra a destra: un timbro tondo con QUILLMERE e la data di oggi e cinque righe ondulate sopra il francobollo, con l’inchiostro irregolare. Dopo un momento la busta si abbassa, si stacca e vola via in alto a destra, girandosi e rimpicciolendo, mentre un foglio pulito si posa sulla scrivania con il titolo Sent. We’ll write back. e la riga Your letter is on its way to the letter desk. Our answer comes within two days. Appena si torna a scrivere il titolo ridiventa Write to us.

Come funziona

Un modulo vero sotto la carta

Due 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.

La matita del correttore

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.

Il foglio tagliato in tre, in 3D

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.

La luce sulle facce

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.

La busta, a strati

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.

Valori da cambiare

NomeFileDi partenzaCosa cambia
FOLDscript.js0.6Quanti secondi impiega ogni terzo del foglio a ripiegarsi.
RELAXscript.js7Di quanti gradi si riapre una piega appena fatta, prima che il terzo dopo la schiacci piatta: 0 è carta che resta giù.
TILTscript.js12Di quanti gradi il foglio si inclina all’indietro mentre si piega, per far vedere lo spessore.
FLAPscript.js0.55Quanti secondi impiega l’aletta della busta a chiudersi.
HOLDscript.js0.9Quanti secondi la busta timbrata resta sulla scrivania prima di volare via.
FLIGHTscript.js0.85Quanti secondi dura il volo della busta.
SETTLEscript.js0.7I secondi di silenzio dopo l’ultimo tasto prima che il campo si rilegga.
SHORTESTscript.js12Quante lettere deve avere almeno il messaggio.
TOWNscript.jsQUILLMEREIl paese scritto in giro sul timbro postale.
STAMP_VALUEscript.js1.85Il valore stampato sul francobollo.

Provali nel Playground

Quando usarla

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.

Sul telefono

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.

Con il movimento ridotto

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.

Trappole

  • L’aletta della busta era un contenitore in preserve-3d con le due facce girate, dentro il dietro della busta, che è piatto per tenere gli strati in ordine di z-index: in Chrome l’aletta aperta spariva del tutto e compariva intera proprio quando era di taglio. Ora l’aletta è un piano solo e lo script decide quale faccia mostrare: oltre i 90 gradi la fodera, sotto il fuori della busta.
  • Il retro del terzo di sotto, sollevato verso chi guarda, guarda in giù e con la luce calcolata diventava quasi marrone: la carta così non è mai. Lo scurimento ora ha un tetto basso e un colore caldo, e il foglio resta carta anche contro luce.
  • Due pannelli piegati a 180 gradi stanno sullo stesso piano del pannello di mezzo e tremolavano uno sull’altro. Le cerniere stanno mezzo spessore di carta sopra il foglio, la seconda più su della prima, così piegati si impilano davvero.
  • La busta saliva da sotto mentre si accendeva: per un attimo i lembi mezzo trasparenti lasciavano vedere la lettera dietro. Ora diventa piena in un decimo di secondo, quando è ancora lontana dalla lettera.
  • L’ombra sulla scrivania era una scatola trasparente con un box-shadow: quando la busta volava via restava sulla scrivania come un cartoncino pallido. Ora appena la busta si stacca l’ombra si ammorbidisce e se ne va.
  • I segni a matita cancellati sparivano di colpo quando subito dopo se ne disegnava uno nuovo, perché il disegno nuovo svuotava il gruppo del campo. I tratti da cancellare ora passano in un gruppo loro e svaniscono lì.
  • La spunta di un campo giusto, in fondo alla riga, finiva sopra la fine di una lettera lunga: ora sta nella riga della matita, sotto il campo, dove non copre mai la scrittura.
  • Il filtro della grafite e quello dell’inchiostro del timbro bucavano troppo e i tratti sembravano file di puntini: il rumore è più largo e i buchi più rari, e il nome del paese sul timbro, prima illeggibile, è più grande.
  • Nella prima versione il giro dell’anteprima durava più di diciotto secondi: la lettera di prova è più corta, la pausa sull’errore più breve e l’attesa della busta timbrata è di poco meno di un secondo.

Librerie

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.

Collaudo

Provata il 17 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