Vai al contenuto
animorio
EN
Tutti i componenti

La nav a cremagliera

Navigazione, Hover, Fisica, SVGGSAPImpegnativaPeso compresso: Demo 12 KBGSAP 28 KBGratisScarica lo zip

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.

Il codice

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>

Playground

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

Oppure chiedila a Claude Code

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 sito

Cosa fa

Su un fondo bianco una barra bianca alta 64 pixel, con l'ombra morbida: a sinistra il nome Halvard in maiuscolo largo e spaziato, al centro cinque voci piccole in maiuscolo (Watches, Calibres, Atelier, Service, Journal), a destra il pulsante Book a visit con il bordo sottile. Sotto le voci corre una cremagliera d'acciaio, una barra con i denti trapezoidali, e sotto la voce corrente, scura, sta un pignone d'ottone di 28 pixel coi denti nei suoi: un anello dentato lucido, una finestra scura nel mozzo e dentro un ingranaggio d'acciaio più piccolo. La luce viene dall'alto a sinistra e resta lì: i fianchi dei denti che la guardano brillano, gli altri sono in ombra, e il pignone fa ombra sulla barra. All'arrivo la cremagliera sale nella barra e il pignone entra rotolando dal capo sinistro fino alla voce corrente. Scegliendo un'altra voce il pignone ci rotola sopra: parte di slancio, gira tanto veloce che i denti si allungano in scie, passa un poco oltre la parola, torna indietro e rallenta, i denti tornano nitidi e l'ultimo cade nel suo vano della cremagliera, ci dondola un istante e si ferma. Mentre rotola, l'ingranaggio nel mozzo gira al contrario e più svelto, e ogni parola che il pignone attraversa si scurisce e torna grigia, fino a quella scelta, che resta scura. Col mouse su un'altra voce, o arrivandoci con Tab o con le frecce, il pignone avanza di due denti verso di lei e aspetta lì, in tensione, senza partire; togliendo il mouse torna al suo posto. Cliccando la voce in cui si è già, il pignone dondola nel suo vano. Al telefono le voci scorrono di lato dentro la barra con la cremagliera, la voce scelta viene al centro e il pignone ci rotola.

Come funziona

Denti a evolvente generati dal codice

Il 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.

Rotolare senza strisciare

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.

La luce che resta ferma

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.

La molla e il fermo

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.

Le scie dei denti e le parole che si accendono

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.

Mano, tasti e telefono

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.

Valori da cambiare

NomeFileDi partenzaCosa cambia
TEETHscript.js14Quanti denti ha il pignone (14 o più): resta grande uguale, quindi con più denti sono più fini, anche sulla cremagliera.
STIFFNESSscript.js190Quanto tira la molla verso la voce scelta: più alta, più svelto.
BOUNCEscript.js0.06Quanto va oltre la parola prima di tornare, come frazione della strada (0, per niente).
DETENTscript.js4Quanto i vani della cremagliera trattengono i denti quando il pignone rallenta: l'ultimo dente ci dondola prima di fermarsi (da 0 a 4,5).
NUDGEscript.js2Di quanti denti il pignone avanza verso una voce puntata, senza partire.
REVERSEscript.js1.7Quante volte più svelto gira al contrario l'ingranaggio piccolo nel mozzo.
BLURscript.jstrueI denti che girano veloci si allungano in scie e tornano nitidi rallentando.

Provali nel Playground

Quando usarla

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.

Sul telefono

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.

Con il movimento ridotto

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.

Trappole

  • Coi denti normali e un angolo di pressione di 25 gradi i denti del pignone venivano a punta e a riposo sembrava un piccolo sole: i denti ribassati a 20 gradi (0,8 e 1 modulo) hanno la testa piatta e si leggono come un ingranaggio, e da 14 denti la cremagliera non li sottotaglia.
  • Ruotando il pignone con un transform, i gradienti e i riflessi giravano con lui, come se la lampada fosse incollata all'ottone: il gruppo si sposta soltanto, e il contorno si ricalcola girato a ogni fotogramma.
  • La prima sfocatura (copie uguali e trasparenti lungo tutto l'angolo del fotogramma) trasformava il pignone in corsa in un disco dorato sfumato, un pallino luminoso: ora le copie coprono al massimo mezzo dente, si affievoliscono all'indietro e quella del momento sta sopra, quindi si vedono denti che lasciano scie.
  • Con la sfumatura dell'acciaio che partiva dal bianco, i denti della cremagliera sparivano sulla barra bianca e restavano solo i fianchi in ombra, come una fila di spine: ora l'acciaio è più scuro, con un filo di contorno e la luce solo sui fianchi che la guardano.
  • Un fermo abbastanza forte da vedersi in ogni posizione teneva il pignone un dente prima della meta: ora vale solo da piano (si spegne con la velocità) e si ferma a 4,5 volte la molla, il massimo per cui la simulazione da ogni distanza arriva sempre al vano giusto.
  • Al telefono la colonna della griglia della pagina si allargava quanto tutte le voci e la barra usciva dallo schermo: la colonna è minmax(0, 1fr), così è la striscia a scorrere.
  • Il contorno del fuoco attorno alla parola toccava i denti del pignone sotto: ora è un ::after stretto attorno alle maiuscole, che lascia due pixel d'aria.

Librerie

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.

Collaudo

Provata il 6 ottobre 2026

  • Computer: Fatto
  • Telefono: Fatto
  • Movimento ridotto: Fatto
  • Safari su iPhone: Da fare

Licenza d’uso

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.

Tutti i componenti