
La valutazione a stelle
Valutazioni, SVG, Hover
NuovaGratis
Nello stile ricco: il pulsante Menu di un bar musicale è la cima di un juke-box anni Cinquanta; premuto, sotto si apre il juke-box intero, il vetro sale e i dischi stanno in piedi nel caricatore. Ogni voce è un cartellino dei titoli: scegliendola, il braccio meccanico prende il suo disco, lo posa sul piatto, il disco gira, la puntina scende e dal disco salgono le note.
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 jukebox menu</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the menu of a music bar: the Menu button is the top of a fifties jukebox; pressed, the whole jukebox opens
under it, the glass slides up and the records stand in their rack. Pointing at a title strip lifts its record;
choosing it, the mechanical arm takes the record to the turntable, the record spins, the needle drops and
notes come out of the speaker grille. -->
<nav class="juke" aria-label="Main" data-jukebox>
<button class="juke-btn" type="button" aria-expanded="false" aria-controls="juke-cabinet" data-toggle>
<svg class="juke-btn__icon" viewBox="0 0 44 44" aria-hidden="true">
<defs>
<linearGradient id="btn-chrome" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="0.45" stop-color="#9aa3ad"/>
<stop offset="0.55" stop-color="#e9edf1"/>
<stop offset="1" stop-color="#6f7882"/>
</linearGradient>
<clipPath id="btn-arch"><path d="M7 41 V 20 A 15 15 0 0 1 37 20 V 41 Z"/></clipPath>
</defs>
<path class="juke-btn__body" d="M7 41 V 20 A 15 15 0 0 1 37 20 V 41 Z"/>
<g clip-path="url(#btn-arch)">
<path class="juke-btn__band juke-btn__band--red" d="M7 41 V 20 A 15 15 0 0 1 37 20 V 41 H 33.5 V 20 A 11.5 11.5 0 0 0 10.5 20 V 41 Z"/>
<path class="juke-btn__band juke-btn__band--cream" d="M10.5 41 V 20 A 11.5 11.5 0 0 1 33.5 20 V 41 H 31 V 20 A 9 9 0 0 0 13 20 V 41 Z"/>
<path class="juke-btn__glass" d="M13 30 V 20 A 9 9 0 0 1 31 20 V 30 Z"/>
<g class="juke-btn__disc">
<circle cx="22" cy="24" r="6.4" class="juke-btn__vinyl"/>
<circle cx="22" cy="24" r="2.4" class="juke-btn__label"/>
</g>
<rect class="juke-btn__strips" x="13" y="30" width="18" height="3.4" rx="0.6"/>
<g class="juke-btn__grille">
<rect x="13" y="34.6" width="18" height="6.4" rx="1"/>
<path d="M15.5 34.6 V 41 M18.5 34.6 V 41 M21.5 34.6 V 41 M24.5 34.6 V 41 M27.5 34.6 V 41"/>
</g>
<rect class="juke-btn__sweep" x="-12" y="0" width="7" height="44" transform="skewX(-18)"/>
</g>
<path class="juke-btn__rim" d="M7 41 V 20 A 15 15 0 0 1 37 20 V 41"/>
</svg>
<span class="juke-btn__word" data-word>Menu</span>
</button>
<div class="cabinet" id="juke-cabinet" data-cabinet inert>
<div class="cabinet__body" data-body>
<!-- the arch around the window: three bands of coloured plastic with light running through them -->
<div class="arch">
<div class="arch__band arch__band--red"><span class="arch__light" data-light></span></div>
<div class="arch__band arch__band--cream"><span class="arch__light" data-light></span></div>
<div class="arch__band arch__band--mint"><span class="arch__light" data-light></span></div>
<div class="window" data-window>
<svg class="mech" viewBox="-20 0 440 200" preserveAspectRatio="xMidYMid meet" aria-hidden="true" data-mech>
<defs>
<linearGradient id="chrome-h" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#fbfdff"/>
<stop offset="0.38" stop-color="#a7b0ba"/>
<stop offset="0.52" stop-color="#eef2f6"/>
<stop offset="1" stop-color="#5d6670"/>
</linearGradient>
<linearGradient id="chrome-v" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#5d6670"/>
<stop offset="0.4" stop-color="#eef2f6"/>
<stop offset="0.6" stop-color="#a7b0ba"/>
<stop offset="1" stop-color="#fbfdff"/>
</linearGradient>
<radialGradient id="vinyl" cx="0.5" cy="0.5" r="0.5">
<stop offset="0" stop-color="#1b1a1d"/>
<stop offset="0.8" stop-color="#0c0b0d"/>
<stop offset="1" stop-color="#232127"/>
</radialGradient>
<linearGradient id="sheen" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#ffffff" stop-opacity="0"/>
<stop offset="0.5" stop-color="#ffffff" stop-opacity="0.28"/>
<stop offset="1" stop-color="#ffffff" stop-opacity="0"/>
</linearGradient>
<radialGradient id="felt" cx="0.5" cy="0.4" r="0.6">
<stop offset="0" class="stop-cherry-dark"/>
<stop offset="1" stop-color="#2a070b"/>
</radialGradient>
<linearGradient id="plinth" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#2a2427"/>
<stop offset="1" stop-color="#0d0b0c"/>
</linearGradient>
<linearGradient id="plinth-top" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#3a3236"/>
<stop offset="0.6" stop-color="#141113"/>
<stop offset="1" stop-color="#241e21"/>
</linearGradient>
<linearGradient id="tray" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" class="stop-cherry"/>
<stop offset="1" class="stop-cherry-dark"/>
</linearGradient>
<clipPath id="disc-clip"><circle r="30"/></clipPath>
</defs>
<!-- the turntable: a lacquered drum with a chrome band, the platter with its felt mat and chrome rim, the spindle -->
<g class="table" transform="translate(22 0)">
<ellipse class="table__shadow" cx="318" cy="170" rx="66" ry="12"/>
<path class="table__side" d="M258 150 V 162 A 60 15 0 0 0 378 162 V 150 Z" fill="url(#plinth)"/>
<path class="table__band" d="M258 157 A 60 15 0 0 0 378 157"/>
<ellipse class="table__top" cx="318" cy="150" rx="60" ry="15" fill="url(#plinth-top)"/>
<path class="table__edge" d="M258 150 A 60 15 0 0 0 378 150"/>
<ellipse class="table__rim" cx="318" cy="148" rx="52" ry="12.8"/>
<ellipse class="table__mat" cx="318" cy="147.4" rx="49.4" ry="11.8" fill="url(#felt)"/>
<path class="table__mat-rings" d="M276 147.4 A 42 9.8 0 0 1 360 147.4 M286 147.4 A 32 7.4 0 0 1 350 147.4"/>
<rect class="table__spindle" x="316.8" y="139" width="2.4" height="8.6" rx="1"/>
</g>
<!-- the rack: chrome dividers behind, the records standing in it, the lacquered tray in front -->
<g class="rack">
<g class="rack__comb" data-comb></g>
</g>
<g class="records" data-records></g>
<g class="tray">
<rect class="tray__front" x="4" y="126" width="266" height="22" rx="3" fill="url(#tray)"/>
<rect x="4" y="123" width="266" height="4.6" rx="2" fill="url(#chrome-h)"/>
<path class="tray__line" d="M12 139 H 262"/>
<path class="tray__shine" d="M14 130 H 120"/>
<path class="tray__shadow" d="M6 150 H 268"/>
<g data-tabs></g>
</g>
<!-- the tonearm: a chrome post, the arm hinged on it, the headshell with the needle -->
<g class="arm" data-tonearm>
<g class="arm__swing" data-swing>
<path class="arm__tube" d="M0 0 L 30 -2.4"/>
<path class="arm__tube-shine" d="M0 -1 L 30 -3.2"/>
<g class="arm__head" data-head>
<path class="arm__shell" d="M28 -6 L 40 -5 L 40 1.4 L 28 1 Z"/>
<path class="arm__needle" d="M37 1.2 L 37.6 4.6"/>
</g>
<rect class="arm__weight" x="-11" y="-4.6" width="8" height="7.4" rx="1.6" fill="url(#chrome-v)"/>
</g>
<ellipse class="arm__base" cx="0" cy="3" rx="7" ry="2.6" fill="url(#chrome-h)"/>
<rect class="arm__post" x="-3" y="-3" width="6" height="7" rx="1.4" fill="url(#chrome-v)"/>
<ellipse class="arm__cap" cx="0" cy="-3" rx="3" ry="1.2"/>
</g>
<!-- the gantry: a chrome rail across the top, a carriage that runs on it, a rod that drops, a claw -->
<g class="gantry">
<rect class="gantry__rail" x="-6" y="13" width="412" height="5.2" rx="2" fill="url(#chrome-h)"/>
<rect class="gantry__bracket" x="-8" y="6" width="5" height="16" rx="1.4" fill="url(#chrome-v)"/>
<rect class="gantry__bracket" x="403" y="6" width="5" height="16" rx="1.4" fill="url(#chrome-v)"/>
<g data-carriage>
<rect class="gantry__rod" x="-1.8" y="22" width="3.6" height="10" fill="url(#chrome-v)" data-rod/>
<g data-claw>
<path class="gantry__finger" d="M0 0 C -6 1 -9 5 -8.4 10" data-finger-l/>
<path class="gantry__finger" d="M0 0 C 6 1 9 5 8.4 10" data-finger-r/>
<rect class="gantry__knuckle" x="-4" y="-2.6" width="8" height="4.4" rx="1.4" fill="url(#chrome-h)"/>
</g>
<rect class="gantry__car" x="-13" y="10" width="26" height="12" rx="3" fill="url(#chrome-h)"/>
<rect class="gantry__lip" x="-13" y="19" width="26" height="1.6"/>
</g>
</g>
</svg>
<!-- the glass in front of the records: it slides up into the arch when the jukebox opens -->
<div class="window__glass" data-glass></div>
</div>
</div>
<!-- the title strips: the real links of the menu, one for every record -->
<ul class="strips" data-strips>
<li><a class="strip" href="#menu" data-item style="--tone: var(--cherry)"><span class="strip__band"></span><span class="strip__word">Menu</span></a></li>
<li><a class="strip" href="#drinks" data-item style="--tone: var(--mint)"><span class="strip__band"></span><span class="strip__word">Drinks</span></a></li>
<li><a class="strip" href="#live" data-item style="--tone: var(--gold)"><span class="strip__band"></span><span class="strip__word">Live music</span></a></li>
<li><a class="strip" href="#book" data-item style="--tone: var(--sky)"><span class="strip__band"></span><span class="strip__word">Book a table</span></a></li>
<li><a class="strip" href="#find" data-item style="--tone: var(--tangerine)"><span class="strip__band"></span><span class="strip__word">Find us</span></a></li>
</ul>
<!-- the speaker grille, with the chrome plate that says what is playing -->
<div class="grille" data-grille>
<span class="grille__plate"><span class="grille__brand">Jive</span><span class="grille__now" data-now aria-live="polite"></span></span>
</div>
</div>
<svg class="notes" aria-hidden="true" data-notes></svg>
</div>
</nav>
</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.
24 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 menu del juke-box» da Animorio e adattala al mio sitoTutto quello che si muove dentro il juke-box è un SVG di 400 per 200 che si ridisegna a ogni fotogramma da pochi numeri: dove sta il carrello sulla guida, quanto è lunga l’asta, quanto è chiusa la pinza, l’angolo del braccio della puntina, e per ogni disco la posizione, quanto è coricato e quanto ha girato. GSAP anima solo quei numeri; una funzione sola li trasforma in attributi transform.
Mentre un disco è nella pinza la sua posizione non si anima: si calcola dalla pinza. Il centro sta sotto la punta delle dita di un raggio, moltiplicato per quanto il disco è coricato; così, mentre l’asta scende sul piatto e il disco passa da dritto (scala verticale 1) a coricato (0,3), il bordo resta sempre stretto fra le dita e il disco si posa sul feltro esattamente dove deve.
Ogni disco ha due gruppi: quello che gira (vinile, solchi, etichetta con la stampa e il foro) e sopra, fermi, due spicchi di luce opposti ritagliati sul cerchio. Quando il disco gira la stampa dell’etichetta corre e la luce resta lì, come su un disco vero. Coricato, tutto il disco è schiacciato in verticale e la rotazione diventa un giro su un’ellisse.
L’arco sono tre bande di plastica una dentro l’altra con la stessa curva; in ognuna corre una striscia di luce, una sfumatura che si ripete spostata con background-position di esattamente un periodo, così il giro non ha scatti. Il vetro è un foglio di riflessi che all’apertura sale e sparisce dentro l’arco; il juke-box si srotola dall’alto con un clip-path e si assesta con un elastico.
Le voci sono link veri, i cartellini dei titoli, raggiungibili col tasto Tab e con le frecce; il pulsante ha aria-expanded, il juke-box chiuso è inert, Esc chiude e ridà il fuoco al pulsante, e la targhetta della griglia dice il titolo in una regione aria-live. Mentre il disco suona, ogni tanto nasce una nota (una croma o due legate) disegnata in un SVG sopra il juke-box: parte dal disco sul piatto (il punto si converte dalle coordinate del meccanismo a quelle della pagina con getScreenCTM), sale ondeggiando nel buio del vetro, dove non copre nessuna scritta, si gira e si spegne.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
SPEED | script.js | 1 | Quanto in fretta si muove il meccanismo (1 è normale). |
RPM | script.js | 45 | I giri al minuto del disco sul piatto. |
NOTES | script.js | 2.2 | Le note al secondo che salgono dal disco. |
LIGHTS | script.js | 1 | Quanto in fretta corre la luce nell’arco. |
LIFT | script.js | 9 | Quanto si solleva un disco quando si punta il suo cartellino. |
BOUNCE | script.js | 1.6 | Il rimbalzo dei dischi quando cadono nel caricatore. |
Per il menu del sito di un bar musicale, di un diner, di un locale con musica dal vivo, di un negozio di dischi o di una radio: le voci della serata (menu, bevande, concerti, prenotazioni, dove siamo). Da tre a sei voci, con titoli corti come sui cartellini veri.
Il juke-box è largo quanto lo schermo e alto al massimo quanto resta sotto il pulsante; il meccanismo è un SVG che si adatta da solo e i cartellini si fanno più bassi. Toccare un cartellino lo sceglie subito: il disco si solleva solo col mouse o con la tastiera.
Il juke-box compare in dissolvenza già aperto, senza luci che corrono; scegliendo una voce il disco compare in dissolvenza già sul piatto con la puntina giù, fermo, e la targhetta dice il titolo. Niente pinza in movimento, niente giri né note.
GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 13 KB; le librerie: GSAP 28 KB.
Provata il 22 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.