
Il pulsante d'acqua
Pulsanti, SVG, Fisica, Hover
NuovaGratis
La barra in alto di un orologiaio: sotto le voci corre una cremagliera d'acciaio, e la pagina in cui si è la segna un pignone d'ottone appoggiato sopra. Scegliendo un'altra voce il pignone ci rotola su una molla, girando esattamente quanto avanza, così i denti ingranano sempre; nel mozzo un ingranaggio più piccolo gira al contrario, e ogni parola si accende quando il pignone le passa sotto.
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 rack and pinion nav</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the top bar of a watchmaker. Under the links runs a steel rack, and the current page is marked by a brass
pinion standing on it: choosing another link the pinion rolls there, its teeth meshing with the rack's, and a
small gear in its hub turns the other way -->
<header class="bar" data-bar>
<a class="brand" href="#" aria-label="Halvard, home">Halvard</a>
<nav class="strip" aria-label="Main" data-strip>
<div class="track" data-track>
<!-- the rack and the pinion, drawn by the script -->
<svg class="mech" aria-hidden="true" data-mech>
<defs>
<radialGradient id="rp-brass" gradientUnits="userSpaceOnUse" cx="-4" cy="-6" r="22" fx="-5" fy="-7">
<stop offset="0" style="stop-color: var(--brass-hi)"/>
<stop offset="0.32" style="stop-color: var(--brass-light)"/>
<stop offset="0.68" style="stop-color: var(--brass)"/>
<stop offset="1" style="stop-color: var(--brass-dark)"/>
</radialGradient>
<radialGradient id="rp-steel" gradientUnits="userSpaceOnUse" cx="-1.6" cy="-2.2" r="7.5">
<stop offset="0" style="stop-color: var(--steel-hi)"/>
<stop offset="0.45" style="stop-color: var(--steel-light)"/>
<stop offset="1" style="stop-color: var(--steel-dark)"/>
</radialGradient>
<radialGradient id="rp-cavity" gradientUnits="userSpaceOnUse" cx="1" cy="1.5" r="7">
<stop offset="0" style="stop-color: var(--cavity-light)"/>
<stop offset="1" style="stop-color: var(--cavity)"/>
</radialGradient>
<!-- the chamfer round the hole in the hub: in shade where it faces away from the light, lit where it faces it -->
<linearGradient id="rp-chamfer" gradientUnits="userSpaceOnUse" x1="-5" y1="-6" x2="5" y2="6">
<stop offset="0" style="stop-color: var(--brass-deep)"/>
<stop offset="0.5" style="stop-color: var(--brass-dark)"/>
<stop offset="1" style="stop-color: var(--brass-hi)"/>
</linearGradient>
<linearGradient id="rp-rack" x1="0" y1="0" x2="0" y2="1" data-rack-paint>
<stop offset="0" style="stop-color: var(--steel-light)"/>
<stop offset="0.55" style="stop-color: var(--steel)"/>
<stop offset="1" style="stop-color: var(--steel-dark)"/>
</linearGradient>
<filter id="rp-soft" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="1.3"/>
</filter>
</defs>
<g class="rack" data-rack>
<path class="rack__shadow" filter="url(#rp-soft)" data-rack-shadow/>
<path class="rack__body" fill="url(#rp-rack)" data-rack-body/>
<path class="rack__face" data-rack-face/>
<path class="rack__lit" data-rack-lit/>
<path class="rack__shade" data-rack-shade/>
</g>
<g class="pinion" data-pinion>
<path class="pinion__shadow" filter="url(#rp-soft)" data-shadow/>
<g data-teeth></g>
<path class="pinion__line" data-line/>
<circle class="pinion__core" fill="url(#rp-brass)" data-core/>
<path class="pinion__edge pinion__edge--hi" data-edge="hi"/>
<path class="pinion__edge pinion__edge--lit" data-edge="lit"/>
<path class="pinion__edge pinion__edge--shade" data-edge="shade"/>
<path class="pinion__edge pinion__edge--dark" data-edge="dark"/>
<circle class="pinion__groove" data-groove/>
<circle class="pinion__hole" fill="url(#rp-cavity)" data-hole/>
<circle class="pinion__chamfer" stroke="url(#rp-chamfer)" data-chamfer/>
<path class="pinion__inner-shadow" filter="url(#rp-soft)" data-inner-shadow/>
<g data-inner></g>
<path class="pinion__inner-edge" data-inner-edge/>
<circle class="pinion__arbor" fill="url(#rp-steel)" r="1.55"/>
<circle class="pinion__pivot" r="0.55"/>
</g>
</svg>
<ul class="list" data-list>
<li><a class="link" href="#" data-link data-autoclic><span class="link__word">Watches</span></a></li>
<li><a class="link" href="#" data-link data-autoclic><span class="link__word">Calibres</span></a></li>
<li><a class="link" href="#" aria-current="page" data-link><span class="link__word">Atelier</span></a></li>
<li><a class="link" href="#" data-link data-autoclic><span class="link__word">Service</span></a></li>
<li><a class="link" href="#" data-link data-autoclic><span class="link__word">Journal</span></a></li>
</ul>
</div>
</nav>
<a class="cta" href="#">Book a visit</a>
</header>
</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 «La nav a cremagliera» da Animorio e adattala al mio sitoIl profilo del pignone si calcola una volta, in coordinate polari: modulo m = 28 / (TEETH + 1,6), raggio primitivo m·z/2, angolo di pressione di 20 gradi e denti ribassati (0,8 m sopra la circonferenza primitiva, 1 m sotto). Fra la circonferenza di base e la testa ogni fianco è un'evolvente: alla distanza r il mezzo dente è largo ψ(r) = π/2z + inv(20°) − inv(acos(r_b/r)), con inv(a) = tan a − a; sotto la base il fianco è radiale, in testa e nel vano ci sono due archi. La cremagliera ha i fianchi dritti inclinati dello stesso angolo: è il profilo con cui ingrana ogni ingranaggio a evolvente, e con 14 denti o più i suoi denti non scavano nei fianchi del pignone.
Il pignone sta in un gruppo SVG che si sposta e non ruota mai; a ogni fotogramma il suo contorno si ricalcola girato dell'angolo θ = π/2 + (x − x0) / r, dove x0 è l'inizio della cremagliera: un dente punta in basso in ogni vano, e spostandosi di un passo (π·m) il pignone gira di un dente. Le mete sono il centro di ogni parola arrotondato al vano più vicino, così da fermo i denti stanno sempre dentro la cremagliera.
Visto che a girare è il disegno e non il gruppo, i gradienti (userSpaceOnUse) restano dove sono: il lucido dell'ottone sta sempre in alto a sinistra. Lungo il contorno ogni segmento si confronta con la direzione della luce (il prodotto scalare fra la sua normale e la luce) e finisce in uno di quattro tracciati, chiaro, illuminato, in ombra e scuro, disegnati mezzo pixel dentro il bordo: è la smussatura lucidata, e un fianco si accende quando ruotando arriva a guardare la luce.
Il centro del pignone segue una molla con smorzamento calcolato da BOUNCE (ζ = −ln B / √(π² + ln² B), così l'oltre è proprio quella frazione della strada), integrata a passi di 1/480 di secondo nel ticker di GSAP, col passo di tempo limitato a 1/30. In più c'è un fermo: una forza −H·k·sin(k(x − x0)) che tira verso il vano più vicino, moltiplicata per exp(−v²/300²), quindi presente solo da piano. Vicino alla meta rende la molla alcune volte più rigida: l'ultimo dente cade nel vano e ci dondola. Fino a 4,5 volte la molla non può mai tenere il pignone un dente prima della meta (provato con una simulazione da ogni distanza). Ai capi della cremagliera un arresto lo rimanda indietro; da fermo il ciclo si toglie dal ticker.
Fra un fotogramma e l'altro i denti girano di un angolo che a tutta velocità supera un dente intero: si disegnano fino a dieci copie dei denti all'indietro lungo quell'angolo, al massimo per mezzo dente, sempre più deboli, con quella del momento sopra le altre; la smussatura sfuma con la velocità. L'ingranaggio nel mozzo gira di −REVERSE·θ con le sue scie. Ogni voce ha una variabile --lit fra 0 e 1, che dipende da quanto il pignone è vicino al centro della parola, e il colore è color-mix fra il grigio e il nero in quella misura.
Puntando una voce, o raggiungendola con Tab (focus-visible), la meta diventa la voce corrente più NUDGE passi verso di lei; le frecce spostano il fuoco fra le voci, Home ed End vanno ai capi, Invio e Spazio scelgono, e aria-current passa subito alla voce scelta. Al telefono le voci e la cremagliera stanno nella stessa striscia che scorre (le misure sono prese con offsetLeft, che non sente lo scorrimento), un dito giù su una voce fa la spinta e il tocco sceglie, con la voce che scivola al centro.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
TEETH | script.js | 14 | Quanti denti ha il pignone (14 o più): resta grande uguale, quindi con più denti sono più fini, anche sulla cremagliera. |
STIFFNESS | script.js | 190 | Quanto tira la molla verso la voce scelta: più alta, più svelto. |
BOUNCE | script.js | 0.06 | Quanto va oltre la parola prima di tornare, come frazione della strada (0, per niente). |
DETENT | script.js | 4 | Quanto i vani della cremagliera trattengono i denti quando il pignone rallenta: l'ultimo dente ci dondola prima di fermarsi (da 0 a 4,5). |
NUDGE | script.js | 2 | Di quanti denti il pignone avanza verso una voce puntata, senza partire. |
REVERSE | script.js | 1.7 | Quante volte più svelto gira al contrario l'ingranaggio piccolo nel mozzo. |
BLUR | script.js | true | I denti che girano veloci si allungano in scie e tornano nitidi rallentando. |
Per la testata di chi fa cose meccaniche e precise: un orologiaio, uno studio di design industriale, chi fa biciclette, macchine da caffè, strumenti, mobili con la ferramenta a vista, un museo della tecnica o una scuola di ingegneria. Sta bene dove le voci sono poche e corte; è una barra da sito, sempre in cima, su una pagina chiara.
Sotto i 960 pixel il pulsante sparisce e le voci si stringono un poco; al telefono la barra, sempre alta 64 pixel, è larga quanto lo schermo meno 32 (358 a 390), e sotto i 360 anche il nome lascia il posto alle voci. Le voci e la cremagliera scorrono di lato insieme dentro la barra, che sfuma dal lato dove ce ne sono altre nascoste; il pignone resta sulla cremagliera e scorre con lei. Un dito giù su una voce fa la spinta di due denti, il tocco la sceglie: la voce scivola al centro della striscia mentre il pignone ci rotola; se il dito invece fa scorrere la striscia, il pignone torna al suo posto.
Niente rotolamento, niente spinta e niente entrata: cremagliera e pignone compaiono in una dissolvenza già al loro posto. Scegliendo un'altra voce il pignone sparisce dove sta e ricompare sotto la parola nuova, già ingranato e girato del giusto, e i colori delle due parole si scambiano in dissolvenza; al telefono la striscia salta alla voce scelta senza scivolare. Le pressioni non rimpiccioliscono niente.
GSAP 3.15.0, Archivo (font variabile, con l'asse della larghezza) 5.3.0.
Compressi con gzip, i tre file della demo pesano 12 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.