
Il dock che si ingrandisce
Menu, Hover, Immagini
Gratis
La barra in alto di un museo del vetro fatta come una vetrata: ogni voce è una lancetta di vetro colorato a sesto acuto, chiusa nel suo piombo, con le venature, le bollicine e il bordo dipinto più scuro del vetro soffiato. Una luce calda dietro la barra passa attraverso la tessera della pagina in cui si è e getta il suo colore sul pavimento sotto la barra, rovesciato e allargato come la luce delle vetrate in una chiesa; puntando un'altra voce la luce le scivola dietro su una molla. Vetro, piombo e riflesso sono calcolati pixel per pixel.
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 stained glass nav</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/cinzel@5.3.0/index.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 top bar of a glass museum, made as a leaded window: every link is a lancet of coloured glass in its dark
lead, with the grain, the cords and the seeds of hand-made glass. A warm light behind the bar shines through
the tile of the page you are on and throws its colour on the floor under the bar, like the light on the floor
of a church; pointing at another tile the light slides behind it. On a phone the links open in a second
window, one row of glass each, and the light drops into it -->
<div class="vitrail" data-vitrail data-autoclic>
<header class="bar" data-bar>
<canvas class="glass" aria-hidden="true" data-glass></canvas>
<a class="brand" href="#" aria-label="Aldgrave Glass Museum, home" data-brand>
<span class="brand__rondel" aria-hidden="true" data-rondel></span>
<span class="brand__name">Aldgrave</span>
</a>
<nav class="nav" id="aldgrave-links" aria-label="Main" data-nav>
<canvas class="nav__glass" aria-hidden="true" data-panel-glass></canvas>
<ul class="list" data-list>
<li class="item" data-glass-color="ruby"><a class="link" href="#" data-link><span class="link__word" data-text="Collection">Collection</span></a></li>
<li class="item" data-glass-color="cobalt"><a class="link" href="#" aria-current="page" data-link><span class="link__word" data-text="Exhibitions">Exhibitions</span></a></li>
<li class="item" data-glass-color="amber"><a class="link" href="#" data-link><span class="link__word" data-text="Studio">Studio</span></a></li>
<li class="item" data-glass-color="emerald"><a class="link" href="#" data-link><span class="link__word" data-text="Learn">Learn</span></a></li>
<li class="item" data-glass-color="violet"><a class="link" href="#" data-link><span class="link__word" data-text="Shop">Shop</span></a></li>
</ul>
</nav>
<div class="end" data-end>
<a class="cta" href="#" data-cta><span class="cta__bg" aria-hidden="true" data-cta-bg></span><span class="cta__label">Tickets</span></a>
</div>
<button class="toggle" type="button" aria-expanded="false" aria-controls="aldgrave-links" data-toggle>
<span class="toggle__label" data-toggle-label>Menu</span>
<svg class="toggle__icon" viewBox="0 0 20 20" aria-hidden="true">
<path class="toggle__line" d="M3.5 7.5L16.5 7.5" data-line/>
<path class="toggle__line" d="M3.5 12.5L16.5 12.5" data-line/>
</svg>
</button>
</header>
<!-- the light that comes through the glass, on the floor under the bar (and under the window of the phone) -->
<canvas class="floor" aria-hidden="true" data-floor></canvas>
<canvas class="floor floor--panel" aria-hidden="true" data-panel-floor></canvas>
</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.
38 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 di vetro colorato» da Animorio e adattala al mio sitoLo script misura le voci nel DOM e ne ricava un piano: le zone una accanto all'altra (il nome, le cinque tessere, il pulsante), l'arco di ogni lancetta (y = F + RISE·(0,4u + 0,6(1 − √(1 − u))), con u la distanza dal centro sulla mezza larghezza: punta in mezzo, quasi dritto dove nasce), i due tagli obliqui di ogni tessera tenuti lontani dalla parola, il tondo accanto al nome. Per ogni pixel del canvas (fino a 300 000) una funzione pieceAt(x, y) dice a quale pezzo appartiene. Al telefono il piano è un'altra vetrata: righe colorate in una cornice di vetro chiaro con i quadretti d'oro.
Ogni pixel che confina con un pezzo diverso è un seme; la trasformata di distanza esatta di Felzenszwalb e Huttenlocher (due passate di parabole, prima le colonne poi le righe) dà a ogni pixel la distanza dal bordo più vicino, ammorbidita con due passate di sfocatura perché sui tagli obliqui la scaletta dei pixel non lasci il piombo attorcigliato come una corda. Dove la distanza è sotto 1,6 pixel c'è piombo; il gradiente del campo dà la normale del suo profilo tondo, illuminato dall'alto con una luce diffusa e un riflesso. Le gocce di stagno sono cerchi uniti al piombo con un minimo morbido, la cornice viene dalla distanza con segno di un rettangolo arrotondato.
Per ogni pezzo un rumore frattale allungato lungo un angolo tutto suo (scale di 30 e 6,5 pixel) fa le venature, un rumore fine fa la martellatura; il loro valore è lo spessore, cioè quanta luce passa, e la loro pendenza diventa uno spostamento (RIPPLE): ogni pixel cerca la luce in un punto un po' spostato, così la luce dietro trema attraverso le venature. Le tessere hanno qualche ciuffo opalino e il bordo dipinto più scuro lungo il piombo; le bollicine, una ogni 230 pixel quadrati circa, sono ellissi chiare al centro, dove concentrano la luce, e scure sul bordo. Tutto questo si calcola una volta per ogni misura.
Ogni pixel di vetro somma la luce del giorno, un po' più forte in alto, e la luce calda: una gaussiana ellittica centrata dietro la tessera (letta da una tabella di 1024 valori), più un secondo lume più debole dietro la pagina corrente quando la luce va altrove. Il colore del vetro per lo spessore per la luce passa da una curva di tono (1 − e^(−1,6x), poi la gamma) che arrotonda le parti forti invece di tagliarle; il piombo si mescola sopra con la sua copertura. Le lettere vere, nel DOM, ricevono --lit, quanto sono illuminate, per il colore e l'alone.
Il pavimento è un canvas a metà risoluzione sotto la barra. Ogni suo punto, per ogni luce, guarda indietro attraverso la vetrata: la riga t del pavimento corrisponde alla riga bottom − t·altezza della vetrata (il fondo cade vicino, l'alto lontano: l'immagine è rovesciata), e la x si avvicina alla luce di 1 + SPREAD·t, così la macchia si allarga. Il punto prende il colore del vetro che attraversa, la sua trasparenza e la luce che c'è dietro; il piombo lascia una riga d'ombra. Le luci si sommano come vetri sovrapposti.
La luce non vive in pixel ma nello spazio delle voci (1,5 è a metà fra la seconda e la terza): una molla con la rigidità GLIDE e lo smorzamento ricavato da BOUNCE la porta alla voce puntata, a passi di 1/120 di secondo con il tempo limitato a 1/30. Così se la finestra cambia misura a metà corsa la vetrata si ricostruisce e la luce resta al suo posto relativo. In corsa la macchia si allunga con la velocità. Quando la molla è ferma e nessuna animazione è in corso il ciclo si spegne e non si disegna niente.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
GLIDE | script.js | 150 | Quanto tira la molla che porta la luce dietro la voce puntata: più alto, più svelta. |
BOUNCE | script.js | 0.1 | Quanto la luce passa oltre la voce e torna indietro, in parte della strada (0, per niente). |
LIGHT | script.js | 2.2 | Quanto è forte la luce calda dietro la barra. |
DAYLIGHT | script.js | 0.3 | La luce del giorno, fioca, che passa da tutti i vetri: più alta, vetri più chiari anche al buio. |
FLARE | script.js | 0.45 | Quanto si accende di più la luce quando si sceglie una pagina (0, per niente). |
FLOOR | script.js | 0.7 | Quanto è forte la luce colorata gettata sul pavimento (0, niente). |
SPREAD | script.js | 0.8 | Quanto si allarga la luce sul pavimento allontanandosi dalla barra. |
SEEDS | script.js | 1 | Quante bollicine ci sono nel vetro (0, nessuna). |
RIPPLE | script.js | 1 | Quanto il vetro irregolare piega la luce che ha dietro (0, vetro piatto). |
Per la testata di chi ha a che fare col vetro, con la luce o con l'arte sacra: un museo del vetro, una galleria, una vetreria o una bottega di vetrate, un laboratorio di soffiatura, una chiesa o un'abbazia aperta alle visite, un festival di luce. Sta bene con poche voci corte, ognuna col suo colore; i colori dei vetri, del piombo e della luce si cambiano nelle variabili.
Sotto i 760 pixel la barra è alta 60 pixel, larga quanto lo schermo meno 32 (358 a 390): a sinistra il nome con il tondo, a destra il pulsante Menu su una lancetta del colore della pagina in cui si è, con la luce dietro e la sua pozza sul pavimento. Toccato, sotto la barra scende una seconda vetrata con le cinque voci in righe di vetro colorato, in una cornice di vetro chiaro con i quadretti d'oro: la luce cala dall'alto dentro la riga della pagina corrente e la sua pozza si apre sotto la vetrata. Facendo scivolare il dito sulle righe la luce lo segue, e la riga su cui lo si alza viene scelta; il vetro del pulsante prende il suo colore e la vetrata si richiude. Sotto i 980 pixel il pulsante Tickets sparisce.
La luce non viaggia: puntando o scegliendo un'altra voce si spegne in una breve dissolvenza dove era e si riaccende dietro la tessera nuova, con la sua pozza sul pavimento. Niente bagliore, niente scritte che si schiacciano, il pulsante non si allarga. Al telefono la vetrata compare e sparisce con una dissolvenza, con la luce già al suo posto.
GSAP 3.15.0, Cinzel (font variabile, con l'asse del peso) 5.3.0, Mona Sans (font variabile, con l'asse della larghezza, per il pulsante) 5.3.0.
Compressi con gzip, i tre file della demo pesano 20 KB; le librerie: GSAP 28 KB.
Provata il 17 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.