Vai al contenuto
animorio
EN
Tutti i componenti

La ricerca nella cassa dei dischi

Ricerca, 3D, Fisica, TransizioniSolo CSS, GSAPImpegnativaPeso compresso: Demo 16 KBGSAP 28 KBGratisScarica lo zip

La ricerca di un negozio di dischi: la lente è un piccolo giradischi che gira a ogni lettera, e i risultati sono le buste in una cassa di legno. Quelle che non c’entrano affondano, le altre si stringono, e la mano le sfoglia in avanti una dopo l’altra, ognuna che rimbalza quando cade. Il disco scelto esce dalla busta e vola sul giradischi; se non c’è niente il disco si graffia e nella cassa si alza un divisorio.

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 record crate search</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 search of a record shop. The lens is a small turntable: typing nudges the record round and the arm
         comes over it. The results are the sleeves in a crate: the ones that do not match sink, the others close up,
         and the hand flips through them; the record picked slides out of its sleeve and lands on the turntable.
         The sleeves are made by the script from the list at the top of script.js -->
    <div class="dig" data-dig data-autoclic>
      <form class="dig__form" role="search" action="#" novalidate data-form>
        <div class="dig__field" data-field>
          <svg class="deck" viewBox="0 0 44 44" aria-hidden="true" data-deck>
            <rect class="deck__plinth" x="1.5" y="4.5" width="41" height="35" rx="6"/>
            <g data-platter>
              <circle class="deck__vinyl" cx="18" cy="22" r="14"/>
              <circle class="deck__groove" cx="18" cy="22" r="12.4"/>
              <circle class="deck__groove" cx="18" cy="22" r="10.6"/>
              <circle class="deck__groove" cx="18" cy="22" r="8.8"/>
              <circle class="deck__label" cx="18" cy="22" r="5" data-label/>
              <path class="deck__half" d="M18 17a5 5 0 0 1 0 10z" data-half/>
            </g>
            <path class="deck__shine" d="M18 8a14 14 0 0 1 12.1 7l-3.4 2A10 10 0 0 0 18 12z"/>
            <circle class="deck__spindle" cx="18" cy="22" r="0.9"/>
            <g data-arm>
              <circle class="deck__pivot" cx="36" cy="10" r="2.6"/>
              <path class="deck__arm" d="M36 10 L36.5 26 L32.6 31.4"/>
              <rect class="deck__head" x="30.4" y="30.2" width="4.2" height="2.6" rx="0.6" transform="rotate(-36 32.5 31.5)"/>
            </g>
          </svg>
          <input class="dig__input" id="dig-input" type="text" inputmode="search" enterkeyhint="search" role="combobox" aria-label="Search the records" aria-autocomplete="list" aria-expanded="true" aria-controls="dig-crate" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" placeholder="Search the crates" data-input>
          <span class="dig__caret" aria-hidden="true" data-caret></span>
          <button class="dig__clear" type="button" aria-label="Clear the search" tabindex="-1" data-clear>
            <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7.5 7.5l9 9M16.5 7.5l-9 9"/></svg>
          </button>
        </div>
      </form>

      <div class="dig__shop">
        <div class="crate" data-crate>
          <div class="crate__bin" id="dig-crate" role="listbox" aria-label="Records" data-bin>
            <span class="crate__side crate__side--l" aria-hidden="true"></span>
            <span class="crate__side crate__side--r" aria-hidden="true"></span>
            <div class="divider" aria-hidden="true" data-divider>
              <span class="divider__tab" data-divider-tab></span>
              <span class="divider__card">
                <span class="divider__small">Nothing under</span>
                <span class="divider__word" data-divider-word></span>
              </span>
            </div>
          </div>
          <div class="crate__front" aria-hidden="true">
            <span class="crate__holder"><span class="crate__tag" data-tag>New in</span></span>
          </div>
        </div>

        <div class="info" data-info>
          <div class="info__record" data-record>
            <p class="info__meta" data-meta></p>
            <p class="info__title" data-title></p>
            <p class="info__artist" data-artist></p>
            <p class="info__price" data-price></p>
          </div>
          <div class="info__none" data-none hidden>
            <p class="info__try">Try</p>
            <div class="info__tries" data-tries></div>
          </div>
          <button class="listen" type="button" data-listen>
            <span class="listen__icon" aria-hidden="true">
              <svg class="listen__play" viewBox="0 0 20 20"><path d="M6.5 4.6v10.8a.8.8 0 0 0 1.2.7l8.6-5.4a.8.8 0 0 0 0-1.4L7.7 3.9a.8.8 0 0 0-1.2.7z"/></svg>
              <span class="listen__bars" data-bars><i></i><i></i><i></i></span>
            </span>
            <span class="listen__words" data-listen-words>Listen</span>
          </button>
        </div>
      </div>

      <div class="dig__flight" aria-hidden="true" data-flight></div>
      <p class="sr" role="status" aria-live="polite" data-said></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>

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.

207 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 ricerca nella cassa dei dischi» da Animorio e adattala al mio sito

Cosa fa

Su un fondo nero un campo scuro dagli angoli tondi: a sinistra, al posto della lente, un giradischi visto dall’alto, col disco nero, l’etichetta grigia e il braccio a riposo, e accanto la scritta Search the crates. Sotto, una cassa di legno con le buste dei dischi in piedi, appoggiate un po’ all’indietro: quella davanti mostra tutta la copertina, disegnata (anelli, strisce, un sole, onde, una lettera enorme), e di quelle dietro si vede la parte alta, col titolo, sempre più in ombra. Sul davanti della cassa, in un portaetichette di metallo, un cartellino dice New in. A destra della cassa il disco davanti è descritto: genere e anno, il titolo grande, l’artista, il prezzo, e un pulsante Listen. Scrivendo, ogni lettera dà una spinta al disco del giradischi, che gira e rallenta da solo, e il braccio va sopra il bordo del disco. Le buste che non c’entrano affondano nella cassa, quelle che restano si stringono scivolando al loro posto e quelle che tornano risalgono dal fondo una dopo l’altra con un piccolo rimbalzo; il cartellino gira e dice quanti dischi ci sono, per esempio 5 records. Vengono prima i titoli che cominciano così, poi quelli con una parola che comincia così, poi l’artista e il genere. Le frecce in giù e in su, la rotella, un trascinamento in giù sulla cassa o un tocco su una busta più indietro sfogliano le buste: quella davanti cade in avanti e oltre il bordo, e quella dopo resta davanti; sfogliandone tante in fretta cadono a cascata, ognuna che rimbalza un poco quando atterra, e il trascinamento lasciato andare continua con lo slancio del dito. Col puntatore sopra, la busta davanti si inclina verso la mano e quelle dietro escono dall’ombra. Listen, Invio o un tocco sulla busta davanti prendono il disco: esce di lato dalla busta, vola verso il giradischi rimpicciolendo e girando, e ci si posa; l’etichetta prende il suo colore, il braccio scende nei solchi, il disco prende velocità e il pulsante diventa arancione e dice Playing, con tre barrette che si muovono. Se nulla corrisponde il disco sul giradischi viene graffiato avanti e indietro, il braccio salta, il campo trema, tutte le buste affondano e nella cassa si alza un divisorio di cartoncino con la linguetta che porta l’iniziale e la scritta Nothing under con le parole scritte; il cartellino dice Not filed e accanto alla cassa compaiono tre parole da provare: soul, dub e jazz. Esc ferma il disco o svuota il campo.

Come funziona

Una cassa in 3D col CSS

Ogni busta è un div con transform-style preserve-3d e il perno in basso (transform-origin 50% 100%), dentro un contenitore con perspective 900px e il punto di vista sopra la cassa (perspective-origin 50% -40%). Ha tre facce: la copertina un pixel davanti (translateZ), il retro girato con rotateX(180deg) un pixel dietro, e il disco in mezzo, così il disco sta dentro la busta per davvero e ne esce senza passarle sopra. Le copertine sono SVG disegnati dallo script coi colori di RECORDS; il davanti della cassa e il portaetichette stanno sopra a tutto, e il contenitore taglia solo il fondo, dove le buste affondano.

Un solo numero per tutta la cassa

c dice quanto ha sfogliato la mano: la busta davanti, con le cadute in mezzo. Ogni busta conosce la sua distanza d da c: dietro (d maggiore di zero) si inclina di LEAN gradi, sale di STEP pixel per posto e va indietro di GAP; fra 0 e -1 cade in avanti fino a FLIP gradi, con una curva smoothstep. c segue il suo bersaglio su una molla (DIG), e ogni busta segue l’inclinazione che le spetta su una molla sua (BOUNCE), poco smorzata: sfogliando di colpo le buste cadono a cascata e ognuna rimbalza quando atterra. Lo z-index si ricalcola da d a ogni fotogramma, perché le buste cadute stanno davanti a quelle in piedi.

Affondare e risalire

search() confronta le parole senza maiuscole né accenti: prima i titoli che cominciano così, poi quelli con una parola che comincia così, poi artista e genere. Le buste che non c’entrano affondano (sink da 0 a 1, cioè giù della loro altezza dietro il davanti della cassa), quelle che restano prendono il posto nuovo e ci scivolano su una molla, e quelle che tornano risalgono dal fondo già al loro posto, una dopo l’altra con back.out. Il bersaglio di c torna a zero: il risultato migliore sta davanti.

Le mani nella cassa

Un trascinamento sulla cassa (pointer capture, touch-action none) muove c direttamente, un posto ogni 44 pixel, con un po’ di elastico oltre i bordi; lasciato, la velocità del dito, misurata e smussata, decide fin dove sfoglia ancora. Un tocco senza spostarsi prende la busta toccata: quella davanti si ascolta, una più indietro viene portata davanti. Anche frecce e rotella spostano il bersaglio di c di un posto. Il giradischi è un SVG: il disco gira con una velocità che ogni lettera aumenta e l’attrito riporta a zero, il braccio gira attorno al suo perno con l’attributo transform.

Dalla busta al giradischi

Il disco esce di lato dalla busta in 0,42 secondi, mentre la busta si inclina verso la mano. Poi se ne misura il riquadro sullo schermo (getBoundingClientRect, già in prospettiva) e al suo posto parte una copia in un livello che sta sopra il campo ma sotto la cassa, così all’inizio è ancora coperta dalla copertina come quello vero. La copia va a sinistra in fretta (power3.out) e sale piano (power2.in), rimpicciolendo subito: gira attorno alla cassa e non passa mai sopra le parole scritte. Arrivata, l’etichetta del giradischi prende il suo colore e il disco accelera fino a RPM giri al minuto.

Un ticker solo, che si ferma

Tutto quello che si muove, molle, buste, giradischi, si integra a passi di 1/240 di secondo in una sola funzione aggiunta al ticker di GSAP, con il passo limitato a 1/30. Quando le molle sono ferme, non c’è un tween in programma (contando anche quelli che aspettano il loro ritardo) e il disco non suona, la funzione si toglie dal ticker. Un clic da script (detail 0, l’anteprima della libreria) fa un passo alla volta, senza prendere il fuoco e con un cursore disegnato: soul e una busta sfogliata, il disco davanti sul giradischi, polka che non c’è, dub proposto, e tutta la cassa sfogliata avanti e indietro.

Valori da cambiare

NomeFileDi partenzaCosa cambia
SLEEVEscript.js200Il lato di una busta, in pixel (su un telefono si rimpicciolisce per starci).
GAPscript.js22Quanto stanno lontane le buste nella cassa, in profondità, in pixel.
STEPscript.js22Quanto si vede di ogni busta più indietro sopra quella davanti, in pixel: lo spazio per il titolo.
LEANscript.js12Quanto sono inclinate all’indietro le buste in piedi, in gradi.
FLIPscript.js72Quanto cade in avanti una busta sfogliata, in gradi.
DIGscript.js[240, 27]La molla della mano che sfoglia: rigidità e smorzamento.
BOUNCEscript.js[520, 16]La molla su cui atterra ogni busta che cade: rigidità e smorzamento (meno smorzamento, più rimbalzo).
RPMscript.js33Quanto gira il disco sul giradischi, in giri al minuto.
TRIESscript.js['soul', 'dub', 'jazz']Le parole proposte quando nella cassa non c’è niente.
RECORDSscript.js[['Night Ferry', 'The Calloway Five', 'Jazz', 1961, '£28', 'rings', …], …]I dischi della cassa, dai più nuovi: titolo, artista, genere, anno, prezzo, la copertina (stile fra rings, sun, waves, bands, letter, arch, blocks e split, carta, inchiostro, accento) e il colore dell’etichetta.

Provali nel Playground

Quando usarla

Per la ricerca di un negozio di dischi, di un’etichetta, di una radio, di una libreria o di un negozio di giochi da tavolo: ovunque i risultati hanno una copertina e cercarli deve somigliare a frugare fra le cose vere. La funzione search() è la sola da cambiare per chiedere i risultati a un server, e play() è il punto dove far partire l’anteprima audio vera.

Sul telefono

Il campo prende la larghezza dello schermo meno 32 pixel e resta alto 60, con le parole di 17 pixel (da 16 in su iPhone non ingrandisce la pagina toccando il campo). La cassa sta sotto il campo, con le buste rimpicciolite a 180 pixel perché ci stiano cassa e titoli, e la descrizione diventa una riga sotto la cassa: titolo e artista a sinistra, Listen a destra. Si sfoglia trascinando il dito in giù sulla cassa, con lo slancio, e si tocca una busta per portarla davanti o per ascoltarla.

Con il movimento ridotto

Niente cadute, voli né rimbalzi: le buste sono già al loro posto, in piedi o cadute, e quelle che non c’entrano svaniscono in dissolvenza invece di affondare. Il disco non vola: l’etichetta del giradischi cambia colore in dissolvenza e il braccio è già nei solchi, ma il disco non gira e le barrette del pulsante stanno ferme. Niente graffio né tremolio quando nulla corrisponde: il divisorio compare in dissolvenza. La ricerca, la tastiera e il tocco funzionano uguali.

Trappole

  • Le buste comparivano solo dopo un clic: il ticker si fermava appena tutto era fermo, e i tween dell’entrata, ancora nel loro ritardo, per gsap.isTweening non sono attivi. Ora conta anche i tween in programma (getTweensOf con progress minore di 1).
  • Scrivendo in fretta polka, le buste che corrispondevano a po restavano in piedi anche se nulla corrispondeva: la loro risalita, ancora nel ritardo, non viene fermata da overwrite: 'auto' del tween che le fa affondare, e partiva dopo. Ora prima di ogni tween di sink si fermano tutti quelli vecchi con killTweensOf.
  • Delle buste dietro si vedevano solo i bordi, sottili come un filo: la prospettiva da sola non bastava. Ogni busta dietro sale ora di STEP pixel per posto, quanto basta per il titolo, e l’artista sta più in basso sulla copertina perché non spunti a metà.
  • Il disco che esce dalla busta passava sopra la copertina: un figlio senza transform, in una busta preserve-3d, si disegnava nell’ordine della pagina. La copertina ora sta a translateZ(1px) e il retro a -1px, col disco in mezzo.
  • Uscendo dall’alto, il disco copriva i titoli delle buste dietro, e quando partiva la copia in volo la parte nascosta dalla copertina compariva di colpo. Ora esce di lato, il volo sta sotto la cassa (e sopra il campo) e la cassa è più larga del suo riquadro, così il disco non viene tagliato.
  • Con la cassa più larga, il suo spazio vuoto copriva la descrizione e il pulsante Listen non si poteva premere: ora la cassa lascia passare il puntatore (pointer-events none) e lo prendono solo le buste, mentre il trascinamento si ascolta sul riquadro della cassa.
  • Il passaggio del puntatore alzava la busta indicata, che copriva il titolo di quella dietro: ora quella davanti si inclina verso la mano e quelle dietro escono solo dall’ombra, senza muoversi.
  • La lettera enorme della copertina finiva sotto il davanti della cassa e la B sembrava una D: ora sta più in alto e più piccola.

Librerie

GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.

Compressi con gzip, i tre file della demo pesano 16 KB; le librerie: GSAP 28 KB.

Collaudo

Provata il 13 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