Vai al contenuto
animorio
EN
Tutti i componenti

La treccia della sincronizzazione

Caricamento, Fisica, WebGLWebGL, GSAPImpegnativaPeso compresso: Demo 16 KBGSAP 28 KBGratisScarica lo zip

Il pannello di sincronizzazione di un’app di foto, con una corda colorata per ogni dispositivo: man mano che arrivano i byte le tre corde tese vengono intrecciate da sinistra in una treccia sola, che è la barra di avanzamento. Se un dispositivo va offline la sua corda esce dal morsetto e resta lenta e grigia finché Retry non la riaggancia; alla fine il morsetto si chiude sulla treccia, una stretta la percorre all’indietro e un riflesso in avanti.

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 sync braid</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/radio-canada@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the sync panel of a photo app: one cord for every device, plaited into a single braid as the bytes arrive.
         The braid is the progress bar; the loose cords still running to the clamp on the right are what is left.
         The cords are painted by a WebGL shader on the canvas; the words, the clamps and the button are HTML -->
    <section class="sync" aria-labelledby="sync-title" data-sync>
      <div class="sync__head">
        <div class="sync__words">
          <h2 class="sync__title" id="sync-title"><span class="sync__swap" data-title>Photos</span></h2>
          <p class="sync__meta"><span class="sync__swap" data-meta>Last synced yesterday</span></p>
        </div>
        <p class="sync__figure" aria-hidden="true">
          <span class="sync__pct" data-pct>2.4 GB</span>
          <svg class="sync__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="sync__bar" role="progressbar" aria-labelledby="sync-title" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" data-bar>
        <canvas class="sync__paint" aria-hidden="true" data-paint></canvas>
        <span class="sync__cap sync__cap--start" aria-hidden="true"></span>
        <span class="sync__cap sync__cap--end" aria-hidden="true" data-clamp></span>
      </div>
      <div class="sync__foot">
        <p class="sync__devices" data-devices></p>
        <button class="sync__btn" type="button" data-action data-autoclic><span class="sync__label" data-label>Sync now</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.

32 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 treccia della sincronizzazione» 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 Photos e Last synced yesterday, a destra 2.4 GB; in mezzo tre corde, blu, verde e corallo, che escono da un tappo d’acciaio a sinistra e corrono lente e un po’ incurvate fino a un morsetto d’acciaio aperto sulla destra; sotto, Laptop · Tablet · Phone, ognuno nel colore della sua corda, e il pulsante nero Sync now. Premuto, le corde vengono tirate una dopo l’altra e si tendono con uno schiocco, vibrando; mentre i dispositivi vengono confrontati (Comparing 3 devices…) degli impulsi corrono lungo le corde dal morsetto verso sinistra. Poi arrivano i byte e le corde si intrecciano da sinistra: la treccia a tre capi si allunga verso destra, dalla sua punta le corde si aprono a ventaglio e tornano nelle loro corsie, e ogni incrocio manda una piccola increspatura lungo il tratto ancora sciolto. In alto la percentuale sale e la riga dice quanti gigabyte sono arrivati e quanto manca; il pulsante diventa Pause, chiaro e col bordo. In pausa le corde si allentano e tornano a incurvarsi (Sync paused, Resume); riprendendo si tendono di nuovo. Quando la treccia arriva in fondo il morsetto si chiude sulla sua punta con uno schiacciamento elastico, una stretta percorre la treccia da destra a sinistra, un riflesso la attraversa da sinistra a destra, al posto della percentuale si disegna una spunta verde e il titolo diventa Photos up to date; Sync again riapre il morsetto, la treccia si disfa verso sinistra e la sincronizzazione riparte. Una volta su due, nella demo, a metà strada il telefono va offline: la corda corallo esce dal morsetto, torna indietro con un rimbalzo e resta lenta e grigia nel tratto sciolto (quello già intrecciato tiene il suo colore), le altre due hanno un sussulto, il titolo in rosso dice Phone went offline, Phone sotto è barrato e il pulsante diventa Retry. Retry rimette la corda nel morsetto, le ridà il colore, la tende con lo schiocco e l’intreccio riprende da dove si era fermato.

Come funziona

Una colonna per pixel

Le corde non si disegnano a tratti: per ogni colonna di pixel del canvas lo script calcola a che altezza passa ognuna delle tre corde e quanto è profonda, e scrive i numeri in una piccola texture di tre righe (l’altezza in due byte, con un 256° di pixel di precisione, la profondità in uno, più un byte che dice se lì la corda c’è). A ogni fotogramma la texture si aggiorna con texSubImage2D: poche centinaia di colonne e nessuna geometria.

Tubi come in un ray tracer

Per ogni pixel lo shader cerca il punto più vicino di ogni corda fra le colonne intorno (i segmenti da una colonna alla successiva) e ne prende la distanza d. Dentro il raggio r la corda è un tubo: la sua altezza lì è la profondità del capo più la curva del tubo, √(r² − d²); vince il tubo più alto, e i tre si posano dal più basso al più alto con il bordo sfumato di mezzo pixel. Così gli incroci della treccia sono esatti al pixel, anche dove due corde si toccano di sbieco. Dalla normale del tubo vengono la luce diffusa e il riflesso, dei trefoli inclinati girano intorno a ogni corda, e le ombre cadono in basso a destra sul pannello e sulla corda di sotto, tanto più lontane quanto più la corda sta sopra.

La treccia a tre capi

Il capo k segue y = A sin θ e z = sin 2θ, con θ = 2π (x ÷ P + k ÷ 3): vista di fronte è la treccia classica, e il seno doppio della profondità fa passare ogni capo una volta sopra e una volta sotto gli altri. Fino alla punta (la parte già arrivata) i capi seguono la treccia; dopo, in un tratto poco più lungo di un giro, si aprono verso la loro corsia con una smootherstep e la profondità si spegne insieme. La punta segue i byte su una molla con lo smorzamento critico, che non torna mai indietro.

Le corde sciolte sono corde vere

Il tratto sciolto di ogni corda è una fila di 48 punti che si muove di lato secondo l’equazione delle onde, con una spinta verso la curva in cui dovrebbe stare e uno smorzamento, calcolata a passi di 1/480 di secondo. La tensione cambia tutto: tesa, le onde corrono veloci e la corda è tirata dritta; lenta, le onde sono pigre e la corda torna alla curva che ricorda (le due esterne si piegano verso fuori, quella in mezzo a S). Tesa di colpo vibra: è lo schiocco. Mentre i dispositivi si confrontano parte un impulso alla volta, con la posizione e la velocità di un’onda che va a sinistra, w = g(x + ct), così corre in una direzione sola; durante l’intreccio ogni incrocio dà alle corde una piccola spinta.

Offline, riprova e fine

Quando un dispositivo va offline la sua corda si stacca: l’estremo torna indietro con back.out, diventa libero (la corda ha un punto fantasma a specchio invece del capo fermo) e lo shader la ingrigisce solo oltre la punta della treccia. Retry la riporta nel morsetto, le ridà il colore e la tende. Alla fine il morsetto si chiude con uno schiacciamento elastico mentre le corsie si stringono sulla treccia; poi una stretta, l’ampiezza della treccia che cala sotto una campana, corre da destra a sinistra, e un riflesso da sinistra a destra.

Per chi non vede e per chi non vuole movimento

La barra è un role=progressbar con aria-valuenow e aria-valuetext in gigabyte, il pannello ha aria-busy mentre lavora e una riga aria-live dice quando la sincronizzazione parte, si ferma, perde un dispositivo e finisce. Il pulsante cambia parola (Sync now, Pause, Resume, Retry, Sync 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. Senza WebGL le corde diventano tre strisce disegnate dal CSS, e tutto il resto funziona.

Valori da cambiare

NomeFileDi partenzaCosa cambia
SECONDSscript.js5.5Quanto dura una sincronizzazione nella demo, in secondi (una vera segue i suoi byte).
SIZEscript.js2.4I gigabyte da sincronizzare.
DEVICESscript.js['Laptop', 'Tablet', 'Phone']I tre dispositivi, uno per corda, dall’alto.
FAIL_EVERYscript.js2Nella demo, una sincronizzazione su quante va storta (0 mai).
FAIL_ATscript.js0.58Fin dove arriva la sincronizzazione che va storta, da 0 a 1.
OFFLINEscript.js2Quale dispositivo va offline allora (0 quello in alto, 2 quello in basso).
CORDscript.js9Lo spessore di una corda, in pixel.
PITCHscript.js4.2Quanto è lungo un giro della treccia, in spessori di corda.
SPREADscript.js1.65Quanto corrono distanti le corde sciolte, in spessori di corda.
TWANGscript.js1Quanto vibra una corda quando viene tesa: 0 per niente, 1 molto.
FOLLOWscript.js0.35Quanto ci mette la treccia a raggiungere i byte, in secondi.
SHEENscript.js0.8Il riflesso che corre sulla treccia finita: 0 niente, 1 forte.

Provali nel Playground

Quando usarla

Per un’attesa di qualche secondo che ha un esito: sincronizzare dei dispositivi, unire delle librerie, un backup, un’importazione da più fonti. Le tre corde dicono bene «tre cose che diventano una», e il dispositivo che si stacca si vede subito; per un file solo da caricare è meglio una barra più semplice.

Sul telefono

Il pannello prende la larghezza dello schermo meno 32 pixel (358 a 390) e resta alto 183; la treccia si accorcia con lui e lo shader dipinge alla densità vera dello schermo, fino a due volte. 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 schiocchi, impulsi né sussulti: le corde passano subito dalla curva lenta alla linea tesa, la corda che va offline è già fuori dal morsetto, il morsetto si chiude senza schiacciarsi, senza stretta e senza riflesso, la spunta e le parole nuove arrivano in dissolvenza. La treccia cresce lo stesso, perché è lei che dice a che punto si è.

Trappole

  • Quando la treccia arrivava al morsetto compariva una riga grigia sottile, alta quanto il canvas: l’ombra misurava la distanza dalla retta che passa per il segmento, e un segmento quasi verticale (le corde che si aprono in pochi pixel) ha la retta vicina a tutta la colonna. Ora l’ombra misura la distanza dai segmenti veri.
  • Con un dispositivo offline diventava grigia tutta la sua corda, anche la parte già intrecciata, come se quei dati fossero persi: lo shader ora riceve la punta della treccia e ingrigisce solo oltre.
  • A sincronizzazione finita le punte delle corde spuntavano sopra e sotto il morsetto chiuso, ancora nelle loro corsie: le corsie ora si stringono sulla treccia insieme al morsetto, e le corde finiscono sotto l’acciaio.
  • Lo schiocco non si vedeva: la corda tesa vibrava a più di sei volte al secondo, smorzata in fretta, partendo da una curva di pochi pixel. Con una rigidezza più bassa, meno smorzamento e le corde lente un po’ più incurvate la vibrazione si vede per tre o quattro oscillazioni.
  • Una spinta di velocità in un punto della corda si divide in due mezze onde che vanno una per parte, piccole e confuse: l’impulso ora parte con la posizione e la velocità di un’onda che va a sinistra, e corre in una direzione sola.
  • All’inizio la riga diceva «about 76 s left»: la velocità era misurata anche durante il confronto dei dispositivi, quando non arriva niente. Ora è la media da quando arrivano i byte, e il tempo si scrive solo dopo l’8% arrivato.
  • La molla della treccia si avvicina all’ultimo pezzo molto piano, e il morsetto restava aperto mezzo secondo con la treccia già in fondo: il morsetto si chiude appena la punta è sotto l’acciaio.
  • Col movimento ridotto il morsetto si chiudeva in dissolvenza, e a metà scopriva le punte delle corde: ora si chiude e basta.
  • Il nome del dispositivo offline restava corallo anche barrato: il colore scritto in linea vinceva sulla classe. I colori dei nomi ora vengono dal CSS, un po’ più scuri delle corde per leggersi bene.

Librerie

GSAP 3.15.0, Radio Canada (font variabile) 5.3.0.

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

Collaudo

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