
Il pulsante di vetro liquido
Pulsanti, WebGL, Hover, Fisica
NuovaGratis
La fermezza di un materasso scelta su un lungo cuscino di velluto blu notte imbottito di memory foam: l'opzione scelta è quella premuta nel cuscino. Scegliendone un'altra la pressione scivola fin lì, e dove è passata la schiuma si riempie piano, come il memory foam vero: per un attimo il percorso resta stampato nel velluto. La scelta cambia il cuscino stesso: morbido affonda di più e ci mette tanto a tornare, rigido cede appena e torna su con un piccolo rimbalzo.
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 memory foam picker</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the firmness picker of a mattress shop, made as a long velvet cushion of memory foam. The chosen firmness is
where the cushion is pressed in; choosing another, the press slides across the cover to it and the foam it
leaves fills back in slowly, as memory foam does. The choice changes the cushion itself: soft, it sinks deep
and takes its time to recover; firm, it barely gives and springs back. The cushion is drawn by a WebGL shader
under four real radio buttons, and the letters soften with the foam -->
<div class="firm" data-firmness>
<div class="firm__head">
<span class="firm__title" id="firm-title">Firmness</span>
<span class="firm__hint" aria-live="polite" data-hint>For most sleepers</span>
</div>
<div class="firm__bed" role="radiogroup" aria-labelledby="firm-title" data-bed>
<canvas class="firm__canvas" aria-hidden="true" data-canvas></canvas>
<span class="firm__dent" aria-hidden="true" data-dent></span>
<label class="firm__opt" data-opt data-say="For side sleepers">
<input class="firm__radio" type="radio" name="firmness" value="soft">
<span class="firm__name">Soft</span>
</label>
<label class="firm__opt" data-opt data-say="For most sleepers">
<input class="firm__radio" type="radio" name="firmness" value="medium" checked>
<span class="firm__name">Medium</span>
</label>
<label class="firm__opt" data-opt data-say="For back sleepers">
<input class="firm__radio" type="radio" name="firmness" value="firm">
<span class="firm__name">Firm</span>
</label>
<label class="firm__opt" data-opt data-say="For stomach sleepers">
<input class="firm__radio" type="radio" name="firmness" value="extra-firm">
<span class="firm__name">Extra firm</span>
</label>
</div>
</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.
32 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 cuscino che ricorda» da Animorio e adattala al mio sitoIl cuscino è un role radiogroup con aria-labelledby sulla parola Firmness, e dentro quattro label con il loro input radio, nascosto ma presente: prende il fuoco, le frecce lo muovono come in ogni gruppo di radio (anche da un capo all'altro) e lo screen reader legge il nome. La riga in alto è aria-live polite, così dopo la scelta si sente anche per chi è. L'anello del fuoco gira intorno all'opzione, dentro il cuscino, solo con la tastiera. Sotto le label c'è un canvas più grande del cuscino, per la sua ombra sulla pagina.
Uno shader disegna un campo di altezze: una capsula (la distanza dal bordo, negativa dentro) con un profilo gonfio, ripido alla cucitura e tondo in alto, e un cordoncino di 2,4 pixel di raggio lungo il bordo. Dall'altezza meno la schiuma premuta si prende la pendenza con le differenze centrali, e da lì la normale. La luce viene dall'alto a sinistra e avvolge come su una stoffa; il velluto si scurisce visto di fronte e si accende dove la superficie gira via, più dalla parte della luce; il pelo schiacciato nel fondo della buca è più chiaro, e due rumori morbidi danno al pelo un verso diverso qua e là.
La schiuma è una fila di 256 profondità lungo il cuscino, calcolata a ogni fotogramma: ogni punto si riempie moltiplicando per exp(−dt/memoria), e la pressione e la mano lo spingono di nuovo giù col massimo. La memoria va da MEMORY secondi (morbido) a circa un settimo di secondo (rigido), ma segue la fermezza con un ritardo di 0,9 secondi: il solco lasciato da una pressione morbida resta morbido. Prima di disegnarla la fila si sfuma su nove punti e va allo shader come una texture di 256 per 1 pixel, due byte per punto (LUMINANCE_ALPHA): la pendenza viene liscia anche nelle buche poco profonde.
La pressione corre verso l'opzione scelta su una molla (65 per GLIDE al quadrato, smorzamento 0,72: va un poco oltre e torna), e mentre corre si alza fino al 28%. La sua profondità è una seconda molla che morbida è smorzata del tutto e rigida rimbalza (frequenza da 10 a 24, smorzamento da 1 a 0,32). Davanti a lei la stoffa si raccoglie in un rilievo che cresce con la velocità (PLOW). Anche la fermezza del cuscino è una molla: da lei dipendono profondità, larghezza e durezza dei bordi della buca, quanto è gonfio il cuscino e la memoria. Il conto si fa sul ticker di GSAP a passi di 1/240 di secondo, col fotogramma limitato a 1/30.
Le pendenze vere di una buca di pochi pixel si vedono appena: nello shader la buca conta 1,7 volte e le normali 1,35. Poi da ogni punto si cammina verso la luce in sette passi di 2,2 pixel sopra il campo delle altezze: se il bordo della buca sta sopra il raggio, il punto è in ombra, sfumata con la distanza. Così il bordo dalla parte della luce getta un'ombra morbida dentro la buca.
Ogni nome si abbassa con la schiuma sotto di lui (2,4 pixel nella buca più profonda) e si accende (opacità e peso da 470 a 640) quanto più la pressione gli è vicina e affondata, così si accende all'arrivo; col mouse vicino si schiarisce un poco. La fermezza muove l'asse SOFT di Fraunces da 100 a 0. Quando tutto è fermo e il solco è pieno, il ciclo esce dal ticker e non disegna più. Senza WebGL il cuscino è una pillola di velluto in CSS con una buca che scivola; se il browser toglie il contesto WebGL, al ritorno si ricostruisce. L'anteprima della libreria clicca l'opzione dopo quella scelta, che ha data-autoclic.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
START | script.js | 1 | L'opzione scelta all'apertura della pagina (0 è la prima). |
FIRM | script.js | [0, 0.38, 0.7, 1] | Quanto è rigida ogni opzione, da 0 (la schiuma più morbida) a 1 (la più dura). |
DEPTH | script.js | 9 | Quanto affonda la pressione dell'opzione più morbida, in pixel (la più rigida la metà). |
MEMORY | script.js | 1.6 | I secondi che la schiuma più morbida ci mette a riempirsi dove è passata la pressione (le più rigide fanno prima). |
GLIDE | script.js | 1 | Quanto in fretta la pressione scivola all'opzione nuova (di più, più svelta). |
PLOW | script.js | 0.6 | Quanto si raccoglie la stoffa davanti alla pressione che scivola. |
TOUCH | script.js | 0.3 | Quanto affonda il mouse, o un dito, rispetto alla pressione dell'opzione scelta. |
SHEEN | script.js | 0.85 | Quanto si accende il velluto dove la superficie gira via dalla luce. |
SOFTEN | script.js | true | Le lettere si ammorbidiscono con la schiuma, sull'asse SOFT del carattere. |
data-say | index.html | For side sleepers, For most sleepers… | La frase per chi è ogni opzione, che compare in alto a destra quando la si sceglie. |
Per una scelta che parla di morbidezza o di comodità: la fermezza di un materasso, di un cuscino o di un topper, l'imbottitura di un divano, l'ammortizzazione di una scarpa da corsa. La buca dice subito che cosa è scelto, e il cuscino che cambia dice che cosa cambia scegliendo. Sta bene in una pagina prodotto calma, con tre, quattro o cinque opzioni dai nomi brevi.
Il cuscino resta alto 56 pixel e si stringe allo schermo: a 390 pixel è largo 358, le opzioni 89 e i nomi scendono a 15 pixel; il canvas col cuscino e la sua ombra non esce mai dallo schermo. Il dito che tocca il cuscino ci affonda dove tocca, come il mouse premuto, e al tocco la pressione scivola all'opzione nuova; niente scia del mouse, che col dito non c'è.
Niente pressione che scivola e niente solco: la buca vecchia si riempie in un decimo di secondo mentre la nuova affonda nel suo posto in 0,3 secondi, così l'ombra passa da un'opzione all'altra in dissolvenza; il nome nuovo si accende con lei. La fermezza cambia subito, i nomi non si abbassano, il mouse non affonda e la riga in alto cambia in dissolvenza. All'apertura il cuscino compare in dissolvenza già premuto.
GSAP 3.15.0, Fraunces (font variabile, con l'asse SOFT) 5.3.0.
Compressi con gzip, i tre file della demo pesano 11 KB; le librerie: GSAP 28 KB.
Provata il 6 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.