Vai al contenuto
animorio
EN
Tutti i componenti

Il cubo che si risolve

Caricamento, 3D, TransizioniSolo CSS, GSAPImpegnativaPeso compresso: Demo 11 KBGSAP 28 KBGratisScarica lo zip

L’ottimizzazione delle immagini di un sito come un cubo da puzzle 3x3 in CSS 3D: a riposo è mescolato, e mentre le 248 immagini vengono alleggerite si risolve una mossa dopo l’altra, ogni mossa uno strato che gira di un quarto con un piccolo rimbalzo. L’ultima mossa chiude tutte le facce, gli adesivi lampeggiano e il cubo fa un saltello e una mezza giravolta soddisfatta; Run again lo rimescola con una raffica di mosse veloci.

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, viewport-fit=cover">
  <title>The solving cube</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist-mono@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the image optimizer of a website, as a 3x3 puzzle cube in CSS 3D. At rest the cube is scrambled; pressed, it
         solves itself one move at a time as the images are done, every move a layer turning a quarter with a little
         bounce, and the last one closes every face. The 27 small cubes are built by script.js -->
    <section class="opt" aria-labelledby="opt-title" data-opt>
      <div class="opt__scene" role="progressbar" aria-labelledby="opt-title" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" aria-valuetext="Not started" data-scene>
        <div class="opt__shadow" aria-hidden="true" data-shadow></div>
        <div class="opt__lift" aria-hidden="true" data-lift>
          <div class="cube" data-cube></div>
        </div>
      </div>
      <div class="opt__head">
        <div class="opt__words">
          <h2 class="opt__title" id="opt-title"><span class="opt__swap" data-title>Optimize images</span></h2>
          <p class="opt__meta"><span class="opt__swap" data-meta>248 images · 64.2 MB</span></p>
        </div>
        <p class="opt__figure" aria-hidden="true">
          <span class="opt__pct is-quiet" data-pct>0%</span>
          <svg class="opt__tick" viewBox="0 0 24 24" data-tick><path d="M5.5 12.6l4.1 4.1L18.6 7.4" pathLength="1"/></svg>
        </p>
      </div>
      <div class="opt__foot">
        <p class="opt__file" aria-hidden="true"><span class="opt__swap" data-file>To AVIF and WebP</span></p>
        <button class="opt__btn" type="button" data-action data-autoclic><span class="opt__label" data-label>Optimize</span></button>
      </div>
      <p class="sr" role="status" aria-live="polite" data-live></p>
    </section>
  </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.

30 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 «Il cubo che si risolve» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco, da solo al centro, un pannello grigio chiaro con gli angoli tondi: in alto un cubo da puzzle nero, mescolato, sospeso sopra la sua ombra morbida; sotto, Optimize images e 248 images · 64.2 MB, a destra 0%, e in basso To AVIF and WebP in un carattere a spaziatura fissa accanto al pulsante nero Optimize. Col mouse sopra il cubo si inclina verso il puntatore su una molla. Premuto, il cubo fa un saltello e gira di un quarto mentre le immagini vengono lette (Reading 248 images…), poi comincia il lavoro: la percentuale sale, la riga dice quante immagini sono fatte e quanti megabyte si sono risparmiati, in basso passano i nomi dei file col loro risparmio, e il cubo si risolve una mossa alla volta. Ogni mossa è uno strato di nove cubetti che gira di 90 gradi, va un po’ oltre e torna indietro, mentre il resto del cubo dà un piccolo contraccolpo; nella fessura si vede la plastica nera dei cubetti di dentro. Le facce prendono la luce secondo come sono girate: quelle verso la lampada in alto a sinistra sono chiare, le altre in ombra, e dove la lampada si riflette verso di te compare un riflesso sull’adesivo. Il pulsante diventa Pause, chiaro e col bordo. In pausa la mossa in corso finisce e il cubo aspetta (Optimizing paused, Resume). L’ultima mossa chiude tutte e sei le facce: gli adesivi lampeggiano, il cubo fa un saltello e una mezza giravolta che finisce con un rimbalzo, al posto della percentuale si disegna una spunta verde e il titolo diventa Images optimized, con 38.5 MB saved e 60% lighter. Run again fa fare al cubo una raffica di dodici mosse veloci che lo rimescolano, e il lavoro riparte con una mescolata nuova.

Come funziona

Un cubo vero, non un disegno

Il cubo è fatto di 27 cubetti, ognuno un div con sei facce in CSS 3D (preserve-3d e backface-visibility hidden). Ogni cubetto sa dov’è sulla griglia 3x3x3 (tre interi fra −1 e 1) e com’è girato (una matrice di rotazione 3x3 di numeri interi). Le facce che stanno fuori dal cubo grande hanno l’adesivo del colore di quella faccia; quelle di dentro sono plastica nera, e si vedono nella fessura quando uno strato gira. Anche il cubetto al centro c’è: senza, a metà mossa si vedrebbe un buco.

Una mossa è una moltiplicazione

Una mossa sceglie un asse, uno strato (−1 o 1) e un verso. Mentre suona, i nove cubetti di quello strato ricevono una rotazione in più attorno all’asse, con l’angolo animato da GSAP con back.out (il piccolo rimbalzo). Alla fine la rotazione esatta di un quarto, arrotondata a interi, moltiplica la matrice e la posizione di ognuno: niente errori che si accumulano, e dopo cento mosse il cubo è ancora perfetto. Le trasformazioni sono scritte a mano come matrix3d, così quello che vedi è proprio quello che lo script calcola.

La soluzione è la mescolata al contrario

La mescolata è un elenco di mosse a caso, mai due sullo stesso asse di fila, così nessuna annulla o ripete quella prima. La soluzione è lo stesso elenco letto dalla fine, con ogni mossa nell’altro verso: l’ultima riporta per forza ogni cubetto a casa. Le mosse sono legate alle immagini: dopo k immagini su N ne sono state fatte k ÷ N di tutte, ma l’ultima solo quando l’ultima immagine è finita, così il cubo si chiude proprio al 100%. Se il lavoro corre più delle mosse, le mosse in coda accelerano.

La luce calcolata faccia per faccia

A ogni fotogramma in cui qualcosa si muove, la normale di ogni faccia passa per la rotazione del suo cubetto, per quella dello strato che gira e per quella della vista (e per l’inclinazione verso il puntatore). Il prodotto con la direzione della lampada dà l’ombra, un velo nero sopra la faccia; il prodotto col vettore a metà fra la lampada e chi guarda, elevato alla diciottesima, dà il riflesso sull’adesivo. Lo script scrive solo i valori che cambiano, e quando niente si muove non ridisegna.

Il contraccolpo, il saltello e la mezza giravolta

Quando uno strato gira, il resto del cubo gira di un paio di gradi nel verso opposto attorno allo stesso asse e torna con una molla elastica, come in mano. All’avvio il cubo salta e gira di un quarto con back.inOut mentre le immagini vengono lette; alla fine lampeggia (una variabile CSS che schiarisce tutti gli adesivi), salta e fa mezzo giro con back.out, e ricade con bounce.out mentre la sua ombra si stringe e torna.

Per chi non vede e per chi non vuole movimento

Il cubo è un role=progressbar con aria-valuenow e aria-valuetext (quante immagini su quante), il pannello ha aria-busy mentre lavora e una riga aria-live dice quando il lavoro parte, si ferma e finisce. Il pulsante cambia parola (Optimize, Pause, Resume, Run again) e la pillola prende la larghezza nuova con un piccolo rimbalzo; un clic da script, quello dell’anteprima della libreria, non mette mai in pausa.

Valori da cambiare

NomeFileDi partenzaCosa cambia
IMAGESscript.js248Quante immagini passa l’ottimizzazione.
SECONDSscript.js7Quanto dura un giro nella demo, in secondi (uno vero segue le sue immagini).
MOVESscript.js12Quante mosse ha la mescolata, e quindi quante ne servono per risolverlo.
CUBIEscript.js34La misura di un cubetto, in pixel.
TURNscript.js0.34Quanto dura una mossa, in secondi.
BOUNCEscript.js1.8Quanto va oltre uno strato prima di fermarsi: 0 per niente.
TILTscript.js1Quanto il cubo si inclina verso il puntatore: 0 per niente.
WEIGHTscript.js64.2Quanto pesano le immagini prima, in megabyte.
SAVEDscript.js0.6Quanta parte del peso si risparmia, da 0 a 1.

Provali nel Playground

Quando usarla

Per un lavoro di qualche secondo fatto di tanti pezzi uguali che alla fine «tornano a posto»: ottimizzare o convertire delle immagini, riordinare una libreria, deduplicare dei file, ricostruire un indice. Il cubo dice bene «disordine che diventa ordine»; per un caricamento di cui non si conosce la durata è meglio un indicatore senza percentuale.

Sul telefono

Il pannello prende la larghezza dello schermo meno 32 pixel (358 a 390) e resta alto 330; il cubo ha la stessa misura, perché sta largo nel suo spazio. Senza mouse il cubo non si inclina, tutto il resto è uguale: le stesse mosse, gli stessi rimbalzi e la stessa luce. Il pulsante è una pillola alta 36: col dito si schiaccia e rimbalza, e la scritta si allarga sull’asse della larghezza solo sotto il mouse.

Con il movimento ridotto

Gli strati non girano: ogni mossa scatta già fatta, una alla volta, così si vede lo stesso il cubo che si mette in ordine. Niente saltelli, niente giravolte, niente inclinazione né contraccolpo; la rimescolata è immediata, alla fine gli adesivi lampeggiano solo in dissolvenza e la spunta e le parole nuove arrivano in dissolvenza.

Trappole

  • Con la prima luce le facce di lato diventavano color oliva e marrone (il giallo e il rosso sotto un velo nero troppo fitto), e il cubo sembrava sporco: l’ombra ora ha un tetto più basso e cresce con una curva, così le facce in ombra restano del loro colore, solo più scure.
  • Con quattordici mosse il cubo restava arruffato fino quasi alla fine, e la percentuale sembrava staccata dal cubo: con dodici le ultime mosse mettono in ordine le facce in modo che si veda.
  • Al telefono la riga finale (64.2 MB to 25.7 MB · 60% lighter) arrivava a toccare il pulsante Run again: ora dice 60% lighter · was 64.2 MB, più corta.
  • Se il lavoro finisce mentre l’ultima mossa è ancora in coda, la percentuale arrivava a 100 col cubo ancora aperto: si ferma a 99 finché l’ultima mossa non chiude le facce, e solo allora compare la spunta.
  • L’anteprima della libreria clicca il pulsante ogni pochi secondi, e a metà lavoro il clic avrebbe messo in pausa: un clic da script (detail 0, senza tastiera) non mette mai in pausa.

Librerie

GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0, Geist Mono (font variabile) 5.3.0.

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

Collaudo

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