Vai al contenuto
animorio
EN
Tutti i componenti

La foto che si divide

Caricamento, Immagini, TransizioniCanvas, GSAPImpegnativaPeso compresso: Demo 13 KBGSAP 28 KBGratisScarica lo zip

Il caricamento di un file RAW grande in un’app di fotografia: la foto parte come un solo riquadro del suo colore medio, poi il riquadro con più dettaglio si divide in quattro, ancora e ancora, ognuno con un piccolo scatto elastico, finché il paesaggio è nitido. Arrivati tutti i byte la griglia si chiude, gli angoli della messa a fuoco si stringono sull’immagine e la foto vera si mette a fuoco sotto gli ultimi riquadri.

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 dividing photo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- a photo app opening a big RAW file: the picture starts as a single tile of its average colour, then the tile
         with the most detail left in it splits into four, again and again, each split with a small elastic snap, until
         the photo is sharp. The landscape is painted by script.js on a hidden canvas: no image is loaded -->
    <section class="raw" aria-labelledby="raw-title" data-raw>
      <div class="raw__head">
        <div class="raw__words">
          <h2 class="raw__title" id="raw-title"><span class="raw__swap" data-title>DSC04182.ARW</span></h2>
          <p class="raw__meta"><span class="raw__swap" data-meta>Sony RAW · 14-bit · 62.4 MB</span></p>
        </div>
        <p class="raw__figure" aria-hidden="true">
          <span class="raw__pct" data-pct>61 MP</span>
          <svg class="raw__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="raw__frame" role="progressbar" aria-labelledby="raw-title" aria-valuemin="0" aria-valuemax="100"
           aria-valuenow="0" aria-valuetext="Not opened" data-bar>
        <canvas class="raw__paint" aria-hidden="true" data-paint></canvas>
        <!-- the four corners of the focus frame: they lock onto the picture when it is sharp -->
        <div class="raw__af" aria-hidden="true" data-af>
          <svg viewBox="0 0 16 16" class="raw__corner raw__corner--tl"><path d="M1 15V5a4 4 0 0 1 4-4h10"/></svg>
          <svg viewBox="0 0 16 16" class="raw__corner raw__corner--tr"><path d="M1 15V5a4 4 0 0 1 4-4h10"/></svg>
          <svg viewBox="0 0 16 16" class="raw__corner raw__corner--bl"><path d="M1 15V5a4 4 0 0 1 4-4h10"/></svg>
          <svg viewBox="0 0 16 16" class="raw__corner raw__corner--br"><path d="M1 15V5a4 4 0 0 1 4-4h10"/></svg>
        </div>
      </div>
      <div class="raw__foot">
        <p class="raw__info"><span class="raw__swap" data-info>Shot 14 Sep · 35 mm · f/8</span></p>
        <button class="raw__btn" type="button" data-action data-autoclic><span class="raw__label" data-label>Open</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.

26 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 foto che si divide» da Animorio e adattala al mio sito

Cosa fa

Su un fondo nero, da solo al centro, un pannello grafite con gli angoli tondi: in alto il nome del file, DSC04182.ARW, e sotto Sony RAW · 14-bit · 62.4 MB, a destra 61 MP; in mezzo una cornice 3:2 riempita da un solo rettangolo color malva, il colore medio della foto; sotto, Shot 14 Sep · 35 mm · f/8 e il pulsante chiaro Open. Premuto, il rettangolo dà un piccolo sussulto, compaiono gli angoli della messa a fuoco e la riga dice Reading header…; poi arrivano i byte e il rettangolo si divide in quattro, e ognuno dei quattro di nuovo, sempre dove l’immagine ha più dettaglio: i figli nascono nel colore del padre, stretti al suo centro, e scattano al loro posto con un rimbalzo prendendo il loro colore, con un filo di luce sul bordo. Il cielo resta a riquadri grandi, mentre l’orizzonte, il sole, i cipressi e la scia di luce sull’acqua si riempiono di riquadri sempre più piccoli, separati da una griglia scura che si assottiglia sui più piccoli. In alto la percentuale sale, la riga dice Loading RAW e quanti megabyte sono arrivati, sotto Refining e quanti riquadri ci sono; il pulsante diventa Cancel, trasparente col bordo. Alla fine la griglia si chiude, gli angoli diventano ambra e si stringono sull’immagine con uno scatto, come l’autofocus quando aggancia, la foto vera, con la sua grana, sale sopra i riquadri con un piccolo respiro, al posto della percentuale si disegna una spunta ambra e le righe dicono 9,568 × 6,384 · ready to edit e f/8 · 1/250 s · ISO 100 · 35 mm. Open again toglie la foto, riapre la griglia e ripiega i riquadri all’indietro fino a uno solo, poi riparte. Cancel fa lo stesso e torna a riposo. Una volta su due, nella demo, a metà strada la scheda di memoria viene tolta: la cornice trema, la riga in rosso dice Card removed at 38.7 MB, il pulsante diventa Retry e riprende da dove si era fermato.

Come funziona

Un paesaggio senza foto

Il lago al tramonto è dipinto dallo script con il canvas 2D: un gradiente per il cielo, un bagliore radiale e il disco del sole, nuvole sottili come ellissi sfumate, due creste di colline fatte da un rumore 1D a quattro ottave, la collina vicina con i cipressi disegnati a curve di Bézier, l’acqua col cielo capovolto e le colline specchiate, la scia di luce come trattini sempre più larghi e radi verso la riva, le canne e una vignetta. Tutto è in frazioni della larghezza e dell’altezza e il caso viene da un generatore con seme, così la stessa scena si dipinge a qualunque misura: una copia nitida alla densità dello schermo, con la grana, e una copia piccola di 384 × 256, pulita, per l’analisi.

Media e varianza in quattro letture

Dalla copia piccola lo script costruisce quattro tabelle delle somme d’area (summed area table): rosso, verde, blu e la somma dei loro quadrati. La somma di qualunque rettangolo costa quattro letture, quindi il colore medio di un riquadro è S ÷ n e il suo errore, la somma degli scarti quadratici dal colore medio, è Σq − (R² + G² + B²) ÷ n, senza mai ripassare i pixel. 384 × 256 si dimezza pulito fino a riquadri di 3 × 2.

Il quadtree cresce con una coda a priorità

Il quadtree si costruisce tutto in anticipo, una volta sola: un heap binario tiene le foglie ordinate per errore, e ogni passo toglie quella col dettaglio più alto e la divide in quattro, che entrano nell’heap. L’ordine delle divisioni è il caricamento: i byte arrivati dicono quante divisioni mostrare (con una curva appena più lenta all’inizio, perché i riquadri grandi si vedano). Un nodo è una foglia al passo k se è nato prima di k e si divide a k o dopo: andare avanti e indietro costa solo un contatore.

Ogni divisione ha il suo scatto

Ogni nodo ricorda quando è comparso. Per 0,62 secondi i quattro figli partono dal centro del padre, al 64% della loro misura e nel suo colore, e vanno al loro posto con una molla scritta a mano, 1 − 2^(−9t) cos(2,7πt), che supera la misura di circa un decimo e si assesta; il colore passa dal padre al loro in 0,3 secondi. Sotto, per un attimo, il padre resta disegnato nel suo colore, così fra i figli non si vede il fondo. Le foglie ferme si disegnano allineate ai pixel dello schermo, così senza la griglia combaciano esatte; la griglia si assottiglia sui riquadri piccoli e gli angoli si arrotondano solo sui grandi.

La messa a fuoco

Quando tutti i byte sono arrivati una timeline di GSAP porta la griglia a zero, stringe gli angoli della messa a fuoco con un elastic.out mentre diventano ambra, e alza la copia nitida sopra i riquadri; il canvas fa un piccolo respiro di scala. Da lì in poi, finché niente si muove, il canvas non si ridisegna. Open again e Cancel fanno il contrario: la foto scende, la griglia torna e un tween riporta indietro il contatore delle divisioni, così i riquadri si ripiegano nell’ordine inverso, ognuno con un piccolo rigonfiamento.

Per chi non vede e per chi non vuole movimento

La cornice è un role=progressbar con aria-valuenow e aria-valuetext in megabyte, il pannello ha aria-busy mentre carica e una riga aria-live dice quando il file si apre, si ferma per un errore, viene annullato ed è pronto. Il pulsante cambia parola (Open, Cancel, Retry, Open again) e la pillola prende la larghezza nuova con un rimbalzo; un clic da script, quello dell’anteprima della libreria, non annulla mai.

Valori da cambiare

NomeFileDi partenzaCosa cambia
FILE_NAMEscript.js'DSC04182.ARW'Il file che si apre.
MEGAPIXELSscript.js61Quanto è grande la foto, in megapixel (la misura in pixel si calcola da qui).
SIZE_MBscript.js62.4Il peso del file, in megabyte.
SECONDSscript.js6.5Quanto dura un caricamento nella demo, in secondi (uno vero segue i suoi byte).
TILESscript.js5200In quanti riquadri finisce la foto prima di mettersi a fuoco.
POPscript.js1Lo scatto elastico di ogni divisione: 0 niente, 1 vivace.
GRIDscript.js0.8La riga scura fra i riquadri mentre carica, in pixel.
FAIL_EVERYscript.js2Nella demo, un caricamento su quanti perde la scheda di memoria (0 mai).
FAIL_ATscript.js0.62Fin dove arriva il caricamento che va storto, da 0 a 1.
SUNscript.js0.68Dove tramonta il sole, da 0 (a sinistra) a 1 (a destra).
SEEDscript.js7La forma delle colline, degli alberi e delle increspature.

Provali nel Playground

Quando usarla

Per l’apertura di un’immagine grande che arriva a pezzi: un RAW da una scheda, una foto da un archivio in rete, una mappa, una scansione, un’anteprima generata. Il quadtree dice «sta arrivando il dettaglio» meglio di una barra, e già dopo pochi byte si capisce che foto è; per un file che non è un’immagine è meglio un altro indicatore.

Sul telefono

Il pannello prende la larghezza dello schermo meno 32 pixel (358 a 390) e la cornice resta 3:2; il canvas dipinge alla densità vera dello schermo, fino a due volte, e la foto nitida si ridipinge alla misura nuova quando lo schermo gira. Il pulsante è una pillola alta 34: col dito si schiaccia e rimbalza, e la scritta si allarga sull’asse della larghezza solo sotto il mouse.

Con il movimento ridotto

Niente scatti né spostamenti: i figli compaiono subito al loro posto e passano dal colore del padre al loro in dissolvenza, la cornice non trema, gli angoli della messa a fuoco si accendono e si spengono senza stringersi, la foto sale in dissolvenza senza il respiro, e i riquadri tornano a uno solo in un colpo. La foto si divide lo stesso, perché è lei che dice a che punto si è.

Trappole

  • Il sole non si vedeva mai: stava a metà altezza, dietro la seconda cresta di colline. Alzato al 38% dell’altezza tramonta proprio sulle creste, e il quadtree ci si accanisce subito.
  • Con una riga di griglia uguale per tutti, i riquadri più piccoli (meno di tre pixel) diventavano per un terzo nero e la foto si spegneva verso la fine: ora la riga si assottiglia fino a un quarto sui riquadri piccoli.
  • Mentre i figli scattavano fuori dal centro, fra loro si vedeva il fondo nero, un lampo scuro a ogni divisione: sotto i figli giovani ora si disegna per un attimo il padre nel suo colore.
  • Senza griglia le foglie lasciavano dei fili più chiari fra loro, perché i bordi cadevano a metà pixel e si sfumavano due volte: le foglie ferme ora si disegnano coi bordi arrotondati ai pixel dello schermo.
  • La collina vicina finiva con un taglio verticale a metà foto, e anche il suo riflesso: ora scende fino all’orizzonte e lo incontra.
  • Analizzando la copia con la grana, il rumore dava errore uguale dappertutto e il cielo si divideva quanto l’orizzonte: l’analisi ora guarda una copia senza grana.
  • Ripartendo con Open again le righe dicevano ancora ready to edit e la percentuale tornava al 99% mentre i riquadri si ripiegavano: le parole cambiano subito, prima della riavvolta.

Librerie

GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0.

Compressi con gzip, i tre file della demo pesano 13 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