
Il menu che si apre dal pulsante
Menu, Transizioni, Testo
Gratis
Nello stile minimal: la richiesta di preventivo di uno studio di design scritta come una frase sola, Hello, I’m … and I’d like … Ogni spazio vuoto è un campo vero che si allarga mentre scrivi, e le parole dopo di lui si fanno da parte su una molla loro; una parola spinta alla riga dopo aspetta che la riga le faccia posto e ci cade dentro dall’alto. Inviata, le righe sotto gli spazi si chiudono, quello che hai scritto prende peso e una riga blu firma la frase.
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 written as a sentence</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full-italic.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the enquiry form of a design studio written as one sentence: every blank is a real field that grows with
what you write, and the words after it make room on a spring. Sending is pretended: see post() in the script -->
<form class="frase" action="#" novalidate aria-labelledby="frase-title" data-frase data-autoclic>
<h2 class="frase__eyebrow" id="frase-title">Start a project</h2>
<p class="frase__text" data-text>Hello, I’m <span class="tok" data-tok><span class="blank" data-blank="name"><label class="sr" for="frase-name">Your name</label><input class="blank__input" id="frase-name" name="name" type="text" autocomplete="name" autocapitalize="words" spellcheck="false" enterkeyhint="next" placeholder="your name" maxlength="40" aria-describedby="frase-name-err" aria-invalid="false" data-input><span class="blank__mirror" aria-hidden="true" data-mirror></span><span class="blank__caret" aria-hidden="true" data-caret></span><span class="blank__line" aria-hidden="true" data-line></span><span class="sr" id="frase-name-err" data-err></span></span>,</span> and I’d like <span class="tok" data-tok><span class="blank blank--choice" data-blank="kind"><label class="sr" for="frase-kind">What you need</label><select class="blank__select" id="frase-kind" name="kind" data-select>
<option>a new website</option>
<option>a brand identity</option>
<option>an online shop</option>
<option>a book design</option>
</select><span class="blank__face" aria-hidden="true" data-face><span class="face__word" data-word></span><svg class="face__chev" viewBox="0 0 12 12" aria-hidden="true"><path d="M2.5 4.5 6 8l3.5-3.5"/></svg></span><span class="blank__line" aria-hidden="true" data-line></span></span></span> for <span class="tok" data-tok><span class="blank" data-blank="work"><label class="sr" for="frase-work">What you do</label><input class="blank__input" id="frase-work" name="work" type="text" autocomplete="organization" spellcheck="true" enterkeyhint="next" placeholder="what you do" maxlength="48" aria-describedby="frase-work-err" aria-invalid="false" data-input><span class="blank__mirror" aria-hidden="true" data-mirror></span><span class="blank__caret" aria-hidden="true" data-caret></span><span class="blank__line" aria-hidden="true" data-line></span><span class="sr" id="frase-work-err" data-err></span></span>.</span> My budget is <span class="tok" data-tok><span class="blank blank--choice" data-blank="budget"><label class="sr" for="frase-budget">Your budget</label><select class="blank__select" id="frase-budget" name="budget" data-select>
<option>under €5k</option>
<option selected>€5–10k</option>
<option>€10–25k</option>
<option>over €25k</option>
</select><span class="blank__face" aria-hidden="true" data-face><span class="face__word" data-word></span><svg class="face__chev" viewBox="0 0 12 12" aria-hidden="true"><path d="M2.5 4.5 6 8l3.5-3.5"/></svg></span><span class="blank__line" aria-hidden="true" data-line></span></span>,</span> and you can write back to me at <span class="tok" data-tok><span class="blank" data-blank="email"><label class="sr" for="frase-email">Your email</label><input class="blank__input" id="frase-email" name="email" type="text" inputmode="email" autocomplete="email" autocapitalize="off" autocorrect="off" spellcheck="false" enterkeyhint="send" placeholder="your email" maxlength="80" aria-describedby="frase-email-err" aria-invalid="false" data-input><span class="blank__mirror" aria-hidden="true" data-mirror></span><span class="blank__caret" aria-hidden="true" data-caret></span><span class="blank__line" aria-hidden="true" data-line></span><span class="sr" id="frase-email-err" data-err></span></span>.</span></p>
<span class="frase__rule" aria-hidden="true" data-rule></span>
<div class="frase__foot">
<button class="send" type="submit" data-send>
<span class="send__bg" aria-hidden="true"></span>
<span class="send__label">Send enquiry</span>
</button>
<div class="frase__note" data-note><span class="note__line">We answer every enquiry within two days.</span></div>
</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.
41 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 scritto in una frase» da Animorio e adattala al mio sitoLe parole della frase vengono divise dallo script in span inline-block (i gettoni), con gli spazi fra loro: la frase va a capo come un testo normale. Ogni spazio da riempire è un input vero (o un select vero sotto le parole che mostra), con la sua label per i lettori di schermo, aria-invalid e aria-describedby al suo errore, chiuso in un gettone insieme alla virgola o al punto che lo segue, così la punteggiatura non va mai a capo da sola.
Ogni cambio di misura passa da relayout(): legge offsetLeft e offsetTop di tutti i gettoni (la posizione senza le trasformazioni), cambia la larghezza dello spazio, rilegge, e la differenza diventa lo spostamento iniziale di una molla per gettone, integrata a passi piccoli sul ticker di GSAP (STIFF, DAMP, appena sotto lo smorzamento critico: un pixel di troppo). Le molle si sommano, quindi scrivere in fretta non fa mai scatti. Un gettone finito su un’altra riga invece aspetta 0,2 secondi invisibile, mentre la riga gli fa posto, e cade dall’alto di DROP pixel.
La larghezza dello spazio si misura con un gemello nascosto con lo stesso carattere. Mentre ci scrivi resta ROOM em più lungo del testo e si allunga di un intero ROOM quando la scrittura ci arriva: così le parole dopo si spostano sempre lontano dalle lettere e mai sopra. Lasciato, si richiude intorno alla parola. Le scelte cambiano parola con un rullo (la vecchia sale via, la nuova sale da sotto) e la loro larghezza segue un tween, che relayout trasforma passo per passo nel movimento delle parole dopo.
All’invio ogni spazio che non va prende il blu, la sua riga si allunga e torna con elastic.out e il suo gettone riceve una spinta sulla sua molla (SHAKE). Accanto al pulsante la frase continua con l’elenco di quello che manca, ognuno un pulsante che porta il fuoco al suo spazio; l’elenco si aggiorna mentre correggi e se ne va quando è tutto a posto. Un indirizzo email sbagliato dice cosa manca: la chiocciola, gli spazi, la fine come .com.
Inviata (post() finge la richiesta per WAIT secondi), le righe sotto gli spazi si chiudono verso il centro sfalsate, gli spazi si stringono intorno al testo, il peso di Fraunces sale da WRITTEN a SIGNED e la larghezza delle frecce scende a zero, tutto in un tween che a ogni passo rimisura gli spazi dentro relayout: la frase si riassesta da sola. Una riga blu la firma da sinistra a destra; il pulsante cambia parola con un rullo e prende la nuova larghezza con un rimbalzo.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
STIFF | script.js | 520 | Quanto è rigida la molla di ogni parola: più alta, le parole arrivano prima. |
DAMP | script.js | 34 | Quanto è frenata la molla: più bassa, le parole vanno più oltre prima di posarsi. |
DROP | script.js | 14 | Da quanto in alto cade una parola che passa alla riga dopo, in pixel. |
ROOM | script.js | 1.2 | Quanto lo spazio resta avanti alla scrittura, in em (la larghezza di una M). |
SHAKE | script.js | 90 | Quanto forte scatta uno spazio che manca all’invio, in pixel al secondo. |
WRITTEN | script.js | 400 | Il peso di quello che si scrive negli spazi. |
SIGNED | script.js | 600 | Il peso che prende quello che hai scritto quando la frase è inviata. |
WAIT | script.js | 0.8 | Quanti secondi dura l’invio finto. |
SENT | script.js | Thanks, {name}: we’ll write back within two days. | La riga accanto al pulsante dopo l’invio; {name} è il nome scritto. |
Nella pagina dei contatti di uno studio, di un fotografo, di un artigiano o di un libero professionista: dove una richiesta ha poche domande e il tono conta quanto le risposte. La frase dice a chi scrive cosa serve senza un elenco di caselle, e la frase firmata è la ricevuta di quello che ha chiesto.
La frase scende a 25 pixel e va a capo su sei righe nei 358 pixel di un telefono di 390, con le stesse molle; il pulsante va sotto la frase e la riga dei messaggi sotto il pulsante. Un tocco su uno spazio apre la tastiera giusta (le email con la chiocciola, il tasto Invio che dice Send nell’ultimo), un tocco su una scelta apre il selettore del telefono. Gli input sono di almeno 16 pixel, quindi Safari non ingrandisce la pagina.
Le parole non scivolano e non cadono: la frase va a capo subito, al suo posto. Le scelte cambiano parola in dissolvenza, gli errori prendono il blu senza scatti; all’invio righe e frecce svaniscono, il testo prende peso in un colpo e la riga blu compare in dissolvenza.
GSAP 3.15.0, Fraunces (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 11 KB; le librerie: GSAP 28 KB.
Provata il 19 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.