
La chat sottovuoto
Chat, Fisica, SVG, Transizioni, Testo
NuovaGratis
Il modulo d’iscrizione al corso di tornio di una bottega di ceramica, fatto d’argilla: un campo giusto prende una mano di smalto crudo data col pennello, uno sbagliato diventa rosso ferro e traballa come un vaso fuori centro. Inviato, va in forno: in poco più di due secondi si accende da solo di rosso scuro, ciliegia, arancio e giallo, coi colori veri di un corpo così caldo calcolati con la legge di Planck, si ritira del dodici per cento come l’argilla ed esce una piastrella smaltata nello smalto scelto, con la prenotazione impressa.
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 goes in the kiln</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/soft.css">
<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 booking form of a pottery's wheel class, made of clay: a field that is right gets a coat of raw glaze
brushed over it, one that is wrong turns iron red; sent, the slab goes in the kiln, glows from dull red to
yellow white, shrinks like clay and comes out a glazed tile in the glaze chosen. The booking is pretended:
see book() in the script -->
<form class="kiln" action="#" novalidate aria-labelledby="kiln-title" data-kiln data-autoclic>
<div class="slab" data-slab>
<div class="face" data-face>
<div class="head">
<h2 class="head__title" id="kiln-title">Thursday wheel class</h2>
<p class="head__sub">Six evenings on the wheel, 7 to 9 pm. Clay, tools and two firings included.</p>
</div>
<div class="field" data-field="name">
<label class="field__label" for="kiln-name">Your name</label>
<div class="well" data-well>
<svg class="coat" aria-hidden="true" data-coat></svg>
<input class="well__input" id="kiln-name" name="name" type="text" autocomplete="name" autocapitalize="words" spellcheck="false" enterkeyhint="next" aria-describedby="kiln-name-msg" aria-invalid="false" data-input>
<span class="well__caret" aria-hidden="true" data-caret></span>
<svg class="tick" viewBox="0 0 20 20" aria-hidden="true" data-tick><path d="M4.8 10.6l3.4 3.4 7-7.6"/></svg>
</div>
<div class="field__msg" id="kiln-name-msg" data-msg></div>
</div>
<div class="field" data-field="email">
<label class="field__label" for="kiln-email">Email</label>
<div class="well" data-well>
<svg class="coat" aria-hidden="true" data-coat></svg>
<input class="well__input" id="kiln-email" name="email" type="text" inputmode="email" autocomplete="email" autocapitalize="off" autocorrect="off" spellcheck="false" enterkeyhint="send" placeholder="you@example.com" aria-describedby="kiln-email-msg" aria-invalid="false" data-input>
<span class="well__caret" aria-hidden="true" data-caret></span>
<svg class="tick" viewBox="0 0 20 20" aria-hidden="true" data-tick><path d="M4.8 10.6l3.4 3.4 7-7.6"/></svg>
</div>
<div class="field__msg" id="kiln-email-msg" data-msg></div>
</div>
<fieldset class="field field--picks" role="radiogroup" aria-labelledby="kiln-date-legend" aria-describedby="kiln-date-msg" aria-required="true" aria-invalid="false" data-field="date">
<legend class="field__label" id="kiln-date-legend">First Thursday</legend>
<div class="picks">
<label class="pick">
<input type="radio" name="date" value="Thursday 15 October" data-input>
<span class="pick__body"><svg class="coat" aria-hidden="true" data-coat></svg><span class="pick__main">15 Oct</span><span class="pick__sub">4 seats left</span><svg class="tick tick--pick" viewBox="0 0 20 20" aria-hidden="true" data-tick><path d="M4.8 10.6l3.4 3.4 7-7.6"/></svg></span>
</label>
<label class="pick">
<input type="radio" name="date" value="Thursday 5 November" disabled data-input>
<span class="pick__body"><span class="pick__main">5 Nov</span><span class="pick__sub">Full</span></span>
</label>
<label class="pick">
<input type="radio" name="date" value="Thursday 26 November" data-input>
<span class="pick__body"><svg class="coat" aria-hidden="true" data-coat></svg><span class="pick__main">26 Nov</span><span class="pick__sub">9 seats left</span><svg class="tick tick--pick" viewBox="0 0 20 20" aria-hidden="true" data-tick><path d="M4.8 10.6l3.4 3.4 7-7.6"/></svg></span>
</label>
</div>
<div class="field__msg" id="kiln-date-msg" data-msg></div>
</fieldset>
<fieldset class="field field--picks" role="radiogroup" aria-labelledby="kiln-glaze-legend" aria-describedby="kiln-glaze-msg" aria-required="true" aria-invalid="false" data-field="glaze">
<legend class="field__label" id="kiln-glaze-legend">Glaze for your first bowl</legend>
<div class="picks">
<label class="pick">
<input type="radio" name="glaze" value="celadon" data-input>
<span class="pick__body"><svg class="coat" aria-hidden="true" data-coat></svg><svg class="bowl" viewBox="0 0 40 20" aria-hidden="true"><path class="bowl__glaze bowl--celadon" d="M2 3.5h36c0 8.6-7.4 14-18 14S2 12.1 2 3.5z"/><path class="bowl__shine" d="M7.5 7.2c2.2 3.6 6 5.4 10.4 5.8"/></svg><span class="pick__main">Celadon</span><svg class="tick tick--pick" viewBox="0 0 20 20" aria-hidden="true" data-tick><path d="M4.8 10.6l3.4 3.4 7-7.6"/></svg></span>
</label>
<label class="pick">
<input type="radio" name="glaze" value="tenmoku" data-input>
<span class="pick__body"><svg class="coat" aria-hidden="true" data-coat></svg><svg class="bowl" viewBox="0 0 40 20" aria-hidden="true"><path class="bowl__glaze bowl--tenmoku" d="M2 3.5h36c0 8.6-7.4 14-18 14S2 12.1 2 3.5z"/><path class="bowl__shine" d="M7.5 7.2c2.2 3.6 6 5.4 10.4 5.8"/></svg><span class="pick__main">Tenmoku</span><svg class="tick tick--pick" viewBox="0 0 20 20" aria-hidden="true" data-tick><path d="M4.8 10.6l3.4 3.4 7-7.6"/></svg></span>
</label>
<label class="pick">
<input type="radio" name="glaze" value="shino" data-input>
<span class="pick__body"><svg class="coat" aria-hidden="true" data-coat></svg><svg class="bowl" viewBox="0 0 40 20" aria-hidden="true"><path class="bowl__glaze bowl--shino" d="M2 3.5h36c0 8.6-7.4 14-18 14S2 12.1 2 3.5z"/><path class="bowl__shine" d="M7.5 7.2c2.2 3.6 6 5.4 10.4 5.8"/></svg><span class="pick__main">Shino</span><svg class="tick tick--pick" viewBox="0 0 20 20" aria-hidden="true" data-tick><path d="M4.8 10.6l3.4 3.4 7-7.6"/></svg></span>
</label>
</div>
<div class="field__msg" id="kiln-glaze-msg" data-msg></div>
</fieldset>
<button class="fire" type="submit" data-fire>
<span class="fire__bg" aria-hidden="true"></span>
<span class="fire__label" data-fire-label>Book my seat · €240</span>
<span class="fire__heat" aria-hidden="true" data-heat></span>
</button>
</div>
<!-- what comes out of the kiln -->
<section class="tile" aria-labelledby="kiln-tile-title" hidden data-tile>
<span class="tile__shine" aria-hidden="true" data-shine></span>
<div class="tile__top">
<p class="tile__kicker"><svg viewBox="0 0 20 20" aria-hidden="true"><path d="M4.8 10.6l3.4 3.4 7-7.6"/></svg>Seat booked</p>
<h2 class="tile__title" id="kiln-tile-title" tabindex="-1" data-tile-title>See you at the wheel.</h2>
</div>
<dl class="tile__facts">
<div><dt>First class</dt><dd data-out="date"></dd></div>
<div><dt>Your bowl’s glaze</dt><dd data-out="glaze"></dd></div>
<div><dt>Details sent to</dt><dd data-out="email"></dd></div>
</dl>
<p class="tile__note">Bring an apron and short nails. Your bowl comes out of its last firing three weeks later.</p>
<button class="again" type="button" data-again><span class="again__bg" aria-hidden="true"></span><span class="again__label">Book another seat</span></button>
</section>
<span class="slab__dark" aria-hidden="true" data-dark></span>
<span class="slab__glow" aria-hidden="true" data-glow></span>
<span class="slab__veil" aria-hidden="true" data-veil></span>
<span class="slab__flame" aria-hidden="true" data-flame></span>
</div>
<p class="sr" role="status" aria-live="polite" data-live></p>
</form>
</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.
49 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 va in forno» da Animorio e adattala al mio sitoDue input veri con le loro label (autocomplete name ed email, inputmode email, testo a 16 pixel perché Safari sul telefono non ingrandisca) e due gruppi di radio veri in un fieldset con role radiogroup: le tessere sono i radio stessi, invisibili sopra il loro disegno, così frecce, spazio, tocco e lettori di schermo funzionano da soli e la tessera Full è disabilitata davvero. Ogni campo ha aria-invalid e aria-describedby verso la sua riga di sotto; all’invio il fuoco va al primo campo sbagliato e una regione aria-live dice cosa controllare, poi legge la prenotazione.
Ogni campo ha tre stati: a riposo, giusto, sbagliato. Scrivendo, SETTLE secondi dopo l’ultimo tasto (un delayedCall di GSAP che riparte a ogni tasto) un campo diventato giusto prende lo smalto; uno non ancora giusto viene lasciato in pace finché non lo si lascia, e solo allora diventa rosso. Un campo rosso si rilegge a ogni tasto: torna giusto appena lo è, mentre le parole del suo errore cambiano solo dopo una pausa, così non lampeggiano fra un tasto e l’altro. La riga sotto entra con l’altezza animata fino ad auto.
Lo smalto è un SVG grande quanto il pozzetto, rifatto quando cambia misura: una striscia ogni cinque o sei pixel, con le punte tonde come setole. A ogni fotogramma ogni striscia arriva a p·(larghezza + 40) meno il suo ritardo, preso da due seni sfasati: il bordo dello smalto bagnato è sfrangiato mentre corre e dritto quando è arrivato. Ogni striscia ha un’opacità sua, che lascia le righe del pennello. La spunta si disegna con stroke-dashoffset quando il pennello è a metà.
All’avvio si calcola una tabella ogni 10 gradi: la legge di Planck da 380 a 780 nanometri, pesata con le curve CIE 1931 (l’approssimazione analitica di Wyman, Sloan e Shirley), portata in sRGB lineare e normalizzata. Poi la si guarda come da uno spioncino: un’esposizione che cresce con la luminanza, e ogni canale che si satura per conto suo (1 − e^(−c·E)), più un poco di abbagliamento al massimo; così sotto i 525 gradi non si vede niente, a 700 è ciliegia e in cima il rosso saturo lascia salire il verde fino a un giallo chiaro. Il bagliore è uno strato in mix-blend-mode screen sopra la lastra già scurita, cioè luce che si somma, con un gradiente radiale fra il bordo e un centro che ha una temperatura sua e la insegue in ritardo. Vicino alla cima uno strato di chiazze chiare in screen si sposta piano e respira con due seni, perché la luce del forno non è mai una tinta piatta.
Una timeline di GSAP sola, in poco più di due secondi: l’ambiente si spegne, la temperatura sale in HEAT secondi (il tratto buio in fretta, poi rosso, arancio e giallo un poco più svelti verso la cima) e intanto la lastra si ritira di SHRINK con un scale su tutta lei, come l’argilla: la piastrella è impaginata larga e alta come il modulo, quindi niente si riordina. Per questo in cima basta un velo del colore dell’argilla accesa per un decimo di secondo, sotto cui il modulo diventa la piastrella; dopo SOAK secondi la temperatura scende in COOL secondi, svelta all’inizio come qualsiasi cosa calda, e la porta si riapre all’ultimo rosso: la piastrella si legge. Il riflesso e gli ultimi gradi vengono dopo. In movimento ridotto la lastra non cambia misura e restano solo i colori che si dissolvono. Un clic da script (detail 0, l’anteprima) fa una mossa alla volta senza prendere il fuoco, con un cursore disegnato: il primo riempie il modulo giusto (la locandina), il secondo lo manda in forno; nei giri dopo un nome nuovo, l’email sbagliata, la correzione e le scelte, con un altro smalto.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
PEAK | script.js | 1240 | La temperatura in cima alla cottura, in gradi: 1240 è il gres; una cottura più bassa resta più rossa. |
HEAT | script.js | 1.1 | Quanti secondi impiega il forno a salire fino in cima. |
SOAK | script.js | 0.2 | Quanti secondi il forno resta in cima: il modulo diventa la piastrella nel primo decimo. |
COOL | script.js | 1.4 | Quanti secondi impiega a raffreddarsi: la piastrella si legge già dopo un terzo. |
SHRINK | script.js | 0.12 | Quanto si ritira la lastra in forno, come l’argilla: 0.12 è il dodici per cento. |
BRUSH | script.js | 0.6 | Quanti secondi impiega il pennello a dare lo smalto su un campo giusto. |
SETTLE | script.js | 0.6 | I secondi di silenzio dopo l’ultimo tasto prima che il campo si rilegga. |
Nella prenotazione di un corso, di un laboratorio o di una visita, dove il modulo è corto e la conferma deve restare in mente: la trasformazione all’invio è il momento in cui chi si iscrive capisce che è fatta. La convalida va bene per qualsiasi modulo: aspetta che si smetta di scrivere, non grida mentre si scrive e se ne va appena il campo è giusto. Il forno e lo smalto sono il tema di una bottega di ceramica; per un altro prodotto si tengono il pennello e la trasformazione sotto il velo e si cambiano i colori.
La lastra prende la larghezza dello schermo (358 pixel su un telefono di 390) ed è alta come lo schermo o poco meno; i campi sono alti 48, le tessere 56 e 64, il pulsante 52, tutti oltre i 44 di un dito. Il testo dei campi è a 16 pixel, così Safari non ingrandisce la pagina al tocco; l’email apre la tastiera con la @; il tasto Invio dice Next nel nome e porta all’email, e Send nell’email. Le tessere si scelgono col tocco e l’hover vale solo dove c’è un puntatore. La piastrella nasce larga 315 e le sue righe vanno a capo da sole.
Il pennello non corre: lo smalto e la spunta compaiono in dissolvenza. I campi sbagliati non traballano, le righe di sotto si scambiano in dissolvenza e le scritte del pulsante si incrociano senza muoversi. In forno restano solo i colori, con gli stessi tempi: il buio, il bagliore e il velo si dissolvono uno nell’altro, la lastra non si ritira, le chiazze di luce stanno ferme e il riflesso sulla piastrella non corre. Book another seat dissolve la piastrella nel modulo nuovo.
GSAP 3.15.0, Fraunces (font variabile) 5.3.0, Bricolage Grotesque (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 17 KB; le librerie: GSAP 28 KB.
Provata il 7 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.