
Il pulsante di vetro liquido
Pulsanti, WebGL, Hover, Fisica
NuovaGratis
Il pulsante Add to bag di una boutique, rivestito di velluto bordeaux vero: il pelo ha un verso, e dove passa il puntatore si piega e lascia una scia più chiara o più scura, come la mano su un divano di velluto, che resta un momento e poi si rialza piano. Il pelo è un campo di direzioni spazzolato dal puntatore e illuminato in WebGL fibra per fibra, con una lucentezza che cambia con l’angolo del pelo. Al clic un’onda pettina tutto il velluto in un verso e la scritta diventa Added.
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 velvet button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bodoni-moda@5.3.0/opsz.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the velvet button: the Add to bag button of a boutique, covered in real velvet. The pile has a direction: where
the pointer passes it bends and leaves a lighter or darker trail that slowly relaxes. A click sends a wave
that combs the whole pile one way, the words say Added, then the velvet is smoothed back. The pile is a field
of directions brushed by the pointer and lit by a WebGL shader; the words stay in HTML, on top -->
<div class="velvet" data-velvet>
<button class="velvet__btn" type="button" data-btn data-autoclic>
<canvas class="velvet__cloth" aria-hidden="true" data-cloth></canvas>
<span class="velvet__face" data-face="rest">
<svg class="velvet__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M5.2 8.6h13.6l-1.1 11.1a1.2 1.2 0 0 1-1.2 1.1H7.5a1.2 1.2 0 0 1-1.2-1.1z"/>
<path d="M9 10.8V7.2a3 3 0 0 1 6 0v3.6"/>
</svg>
<span>Add to bag</span>
</span>
<span class="velvet__face" data-face="done" aria-hidden="true">
<svg class="velvet__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M5.2 8.6h13.6l-1.1 11.1a1.2 1.2 0 0 1-1.2 1.1H7.5a1.2 1.2 0 0 1-1.2-1.1z"/>
<path d="M9 8.6V7.2a3 3 0 0 1 6 0v1.4"/>
<path d="M9.4 14.6l1.9 1.9 3.5-3.7" pathLength="1" data-check/>
</svg>
<span>Added</span>
</span>
</button>
<p class="sr" 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.
18 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 pulsante di velluto» da Animorio e adattala al mio sitoLo script tiene, ogni 2 pixel del pulsante, un vettore: il verso in cui pende la fibra, e quanto è lungo dice quanto è stesa (0 dritta, 1 piatta). A riposo tutti pendono in giù di NAP, com’è tessuto il velluto. Il campo vive in due Float32Array e a ogni fotogramma in cui cambia sale sulla GPU come una texture piccolissima, due byte per cella, che la scheda video sfuma da una cella all’altra.
Ogni movimento del puntatore (con getCoalescedEvents, così una mano veloce non salta) è un segmento: le celle vicine vengono tirate verso il verso del segmento, lunghe LAY, con una campana piatta della distanza dal segmento (e alla meno q alla quarta), così la scia ha un bordo netto. La presa è 1 meno e alla meno lunghezza/5: una passata lunga stende il pelo del tutto, un tremolio lo piega appena. Il mouse sfiora (0,85), il mouse premuto e il dito schiacciano e sono più larghi; la pressione apre il pelo a raggiera intorno al punto.
A ogni fotogramma ogni cella torna verso il verso del velluto (tessuto in giù, o pettinato dall’onda) con un’esponenziale. Una cella appena spazzolata però tiene il segno: ha un valore di presa che si svuota in un terzo di RELAX e frena il ritorno finché c’è, così la scia resta ferma un momento e poi se ne va. Quando tutte le celle sono ferme e niente si muove, non si ridisegna niente.
Lo shader disegna l’imbottitura dalla distanza da un rettangolo arrotondato (una pendenza negli ultimi 12 pixel e una bombatura leggera dall’alto in basso) e ne ricava la normale. La fibra è la normale inclinata secondo il campo. La lucentezza è quella anisotropa dei capelli (Kajiya e Kay): il seno dell’angolo fra la fibra e il vettore a metà fra luce e occhio, alla decima. Il tono viene da dove pende la fibra: lontano dalla lampada mostra il fianco illuminato, verso la lampada la punta scura, dritta lascia vedere il fondo del pelo. Sui bordi, dove il velluto si vede di taglio, una luce radente; ogni fibra è storta di un pelo diverso, pixel per pixel, e fa il luccichio del velluto.
Le righe fini lungo il pelo sono un rumore allungato lungo una di otto direzioni fisse, mescolando le due più vicine al verso del pelo. Il campo si legge con un piccolo spostamento di rumore, così i bordi della scia sono sfilacciati, e un rumore lento fa pendere il pelo un po’ diverso da un punto all’altro: il velluto vero non è mai uniforme.
Al clic GSAP allarga un anello dal punto premuto (dal centro con la tastiera e nell’anteprima) in WAVE secondi. Nello shader la cresta è un rilievo con una piccola increspatura dietro (un coseno sotto una campana) che piega la normale e getta le fibre in fuori; nello script, dietro la cresta, ogni cella viene pettinata nel verso COMB. Quando la cresta passa il centro la scritta cambia; DONE secondi dopo un’onda più morbida dal bordo destro rimette il velluto a riposo. Il pulsante è un button vero con aria-live e aria-busy, Invio e Spazio lo premono dal centro, l’anello del fuoco si vede solo con la tastiera. Senza WebGL resta un velluto dipinto coi gradienti del CSS.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
BRUSH | script.js | 11 | Quanto è larga la mano che spazzola il pelo, in pixel dal centro. |
LAY | script.js | 0.85 | Quanto la mano stende il pelo: 0 niente, 1 piatto. |
RELAX | script.js | 6 | I secondi che una scia ci mette a rialzarsi nel velluto. |
NAP | script.js | 0.4 | Quanto pende in giù il pelo a riposo, com’è tessuto il velluto. |
SHEEN | script.js | 1 | Quanto è forte la lucentezza delle fibre. |
GRAIN | script.js | 1 | Quanta grana ha il tessuto: 0 liscio, 2 grosso. |
COMB | script.js | 25 | Il verso in cui l’onda del clic pettina il pelo, in gradi: 0 verso destra, 90 verso il basso. |
WAVE | script.js | 0.9 | I secondi che l’onda ci mette ad attraversare tutto il pulsante. |
DONE | script.js | 2.2 | I secondi in cui il pulsante dice Added prima che il velluto venga lisciato com’era. |
Per il pulsante principale della scheda prodotto di un negozio di moda, gioielli, profumi o arredamento, o di qualunque marchio che vende la sensazione di un materiale: un pulsante solo, su un fondo scuro e calmo, dove si ha voglia di toccarlo. Il colore del velluto si cambia nel CSS (verde bottiglia, blu notte, nero). Non per una griglia di prodotti con un pulsante per ognuno.
Largo 320 pixel, o lo schermo meno 48, e alto 60. Il dito trascinato di traverso spazzola il pelo come il mouse premuto (touch-action: pan-y, così in su e in giù la pagina scorre ancora); se il dito si è spostato di più di 10 pixel non è un clic. Il tocco breve è il clic, con l’onda che parte da dove ha toccato il dito. La densità dei pixel è limitata a 2.
Il velluto resta fermo: il puntatore non lascia scie, la pressione non affonda e non c’è la mano dell’arrivo. Al clic il velluto passa al tono pettinato in una dissolvenza di mezzo secondo, senza onda, e torna allo stesso modo; le scritte cambiano in dissolvenza, senza scivolare, e la spunta compare già disegnata.
GSAP 3.15.0, Bodoni Moda (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 12 KB; le librerie: GSAP 28 KB.
Provata il 12 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.