Vai al contenuto
animorio
EN
Tutti i componenti

Il timer a incenso

Timer, Fisica, Hover, TransizioniCanvas, GSAPImpegnativaPeso compresso: Demo 16 KBGSAP 28 KBGratisScarica lo zip

Il timer di un’app di meditazione, dove una seduta dura quanto un bastoncino d’incenso: il bastoncino brucia nella sua ciotola di celadon mentre il tempo scende, il fumo sale in fili che ondeggiano e si arricciano, la cenere cresce sulla punta e cade nella ciotola, e una mano passata nel fumo lo scompiglia. A zero la brace si spegne e un bastoncino nuovo sale dalla cenere.

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 incense timer</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/newsreader@5.3.0/opsz.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the incense timer: a sitting lasts as long as a stick of incense. The stick burns down in its bowl while the
         smoke rises in threads that curl, the ash grows on the tip and drops into the bowl, and a hand passing
         through the smoke stirs it -->
    <section class="sit" aria-label="Meditation timer" data-timer>
      <div class="sit__scene" data-scene>
        <canvas class="sit__canvas" aria-hidden="true" data-canvas></canvas>
      </div>

      <div class="sit__readout">
        <span class="sit__time" role="timer" aria-atomic="true" data-time-box>
          <span class="sit__digits" aria-hidden="true" data-time></span>
          <span class="sr" data-time-words></span>
        </span>
        <span class="sit__state" aria-hidden="true" data-state></span>
      </div>

      <div class="sit__controls" data-controls>
        <button class="sit__reset" type="button" aria-label="Start over" aria-disabled="true" data-reset>
          <span class="sit__turn">
            <svg viewBox="0 0 24 24" aria-hidden="true" data-reset-icon><path d="M5.6 9.2A7.2 7.2 0 1 1 4.9 14.2"/><path d="M5.2 4.6v4.8H10"/></svg>
          </span>
        </button>
        <button class="sit__go" type="button" data-go data-autoclic>
          <span class="sit__words" data-go-words></span>
        </button>
        <span class="sit__balance" aria-hidden="true"></span>
      </div>

      <p class="sr" 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.

23 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 timer a incenso» da Animorio e adattala al mio sito

Cosa fa

Su un fondo nero una ciotola di celadon verde chiaro, con la vetrina screpolata, un riflesso di finestra a sinistra e il piede di argilla nuda, piena di cenere color sabbia; in mezzo è piantato un bastoncino d’incenso marrone sulla sua canna rossa. Sotto la ciotola il tempo, 0:15, in grandi cifre sottili, la parola Ready in corsivo e due pulsanti: uno tondo per ricominciare, spento, e una pillola dello stesso celadon della ciotola con Begin. Aprendo la pagina la ciotola compare e il bastoncino sale dalla cenere con un piccolo rimbalzo. Con Begin sulla punta si accende una fiammella che trema, la brace prende e la fiammella si spegne con uno sbuffo di fumo; da lì il fumo sale di continuo, prima dritto e sottile, poi ondeggia, si divide in tre fili che si arricciano, si allarga in un velo e svanisce in alto. Nasce azzurrino e invecchiando diventa grigio. Il bastoncino si accorcia secondo per secondo, la brace arancione scende con la punta e sopra di lei cresce una colonnina di cenere grigia, che ogni tanto si piega, si stacca, cade nella ciotola e si sbriciola: i frammenti restano sulla cenere, e la ciotola raccoglie il tempo passato. Le cifre cambiano salendo come il fumo, sfocandosi, e la nuova sale da sotto. Passando il mouse nel fumo, o trascinandoci un dito, il fumo viene spinto via e si arriccia in due vortici ai lati del passaggio, e la brace soffiata si ravviva. Pause abbassa la brace a un rosso spento e il fumo smette, l’ultimo filo sale e se ne va; Resume la riaccende con uno sbuffo. A zero la brace si ravviva un’ultima volta e si spegne, l’ultima cenere cade, l’ultimo filo sale, e sotto le cifre c’è Complete; poco dopo il mozzicone affonda nella cenere, i frammenti nella ciotola svaniscono e un bastoncino nuovo sale al suo posto, col tempo di nuovo pieno e Ready. Il pulsante tondo fa ricominciare in qualunque momento.

Come funziona

Il fumo, sbuffo per sbuffo

Dalla brace escono tre fili di sbuffi, RATE al secondo ciascuno, quasi dallo stesso punto. Ogni sbuffo sale a RISE pixel al secondo e viene portato dal rotore (curl) di un rumore di Perlin in 3D a due ottave: un campo che gira ma non raccoglie e non disperde, come l’aria. Il rumore scorre verso l’alto insieme al fumo, così i riccioli salgono con lui. Appena uscito dalla punta il campo pesa poco e il fumo sale dritto; più in alto pesa di più (SWIRL) e il filo ondeggia e si arriccia. I tre fili leggono il rumore un poco sfalsato nel tempo, quindi partono insieme e si separano salendo. Ogni sbuffo nasce dove sarebbe stato nel suo istante esatto dentro il fotogramma, così sono tutti alla stessa distanza.

Fili che si assottigliano

Gli sbuffi di un filo si uniscono nell’ordine in cui sono nati. Un tratto stirato è un filo più sottile, quindi sfuma; la distanza è smussata sui vicini, per non far tremolare la trasparenza da un giunto all’altro. Ogni tratto va in un gruppo per età e trasparenza (un Path2D per gruppo) e si disegna in modo additivo, coi capi piatti. Il corpo morbido del fumo è lo stesso disegno, largo, su un canvas grande un quarto, stirato sopra il quadro: la sfocatura viene gratis. Invecchiando il filo netto sparisce prima del corpo morbido, e il colore passa dall’azzurro al grigio, come nel fumo vero.

La mano nel fumo

Il puntatore (mouse o dito) lascia dei soffi: un punto, la velocità della mano, un raggio che si allarga e una forza che si spegne in un terzo di secondo. Gli sbuffi vicini vengono spinti nel verso della mano e girati in un vortice. Il verso del vortice dipende dal lato del passaggio su cui si trova lo sbuffo, quindi ne nascono due, come nella scia vera. Un soffio vicino alla punta ravviva la brace e il fumo per qualche istante (HAND).

La cenere che cade

La cenere cresce sulla punta quanto la parte bruciata, con un bordo irregolare e un po’ storta. Arrivata a una lunghezza scelta a caso in ASH, si piega sulla brace come un’asta sul suo piede (accelerazione 3g/2L per il seno dell’angolo) e, passati i 35 gradi, si stacca con la velocità che aveva e cade girando. Dove tocca la cenere della ciotola si sbriciola in pezzetti che rimbalzano una volta; fermi, si disegnano su un canvas a parte che si sovrappone alla ciotola, così restano senza costare niente.

Il tempo e gli stati

Il tempo che resta viene dall’orologio (performance.now), non dai fotogrammi, quindi una scheda rimasta in background finisce comunque in orario. La parte bruciata è il tempo passato. Begin è una timeline GSAP: fiammella, brace, la fiammella che si spegne e lo sbuffo. Pause porta la brace a un rosso spento e il fumo a zero, la fine fa ravvivare la brace e la spegne, e una timeline affonda il mozzicone (la parte sotto la cenere è tagliata via) e fa risalire il bastoncino nuovo con un back.out. Le parole e le cifre cambiano salendo e sfocandosi. Il clic dell’anteprima (detail 0) fa solo cominciare e riprendere, mai mettere in pausa.

Valori da cambiare

NomeFileDi partenzaCosa cambia
SECONDSscript.js15Quanto dura una seduta: il bastoncino brucia in questi secondi (breve per la prova; in un’app vera minuti).
RISEscript.js46Quanto in fretta sale il fumo, in pixel al secondo.
SWIRLscript.js1Quanto il fumo ondeggia e si arriccia lontano dalla punta: 0 = un filo dritto.
SMOKEscript.js1Quanto è denso il fumo.
HANDscript.js1Quanto una mano (o un dito) passata nel fumo lo scompiglia; 0 = il fumo non si accorge della mano.
ASHscript.js[12, 22]Quanto cresce la cenere sulla punta prima di cadere, in pixel: la più corta e la più lunga.
AFTERscript.js2.6I secondi in cui il bastoncino consumato resta lì prima che ne salga uno nuovo.

Provali nel Playground

Quando usarla

Per il timer di un’app di meditazione, di respirazione o di yoga, per una pausa di concentrazione, per lo studio a blocchi: dove il tempo deve passare con calma e senza ansia, e guardarlo fa parte del rilassarsi. Non è adatto a un conto alla rovescia che mette fretta.

Sul telefono

Il componente è largo 320 pixel e sta in uno schermo di 390 senza sforare. Il dito trascinato nel fumo fa quello che fa il mouse; sul disegno la pagina non scorre (touch-action none), quindi il dito mescola il fumo invece di spostare la pagina. Il fumo costa poco (circa seicento sbuffi e un centinaio di tratti per fotogramma) e gira a 60 fotogrammi anche senza scheda grafica.

Con il movimento ridotto

Il fumo non si muove: viene calcolato una volta sola, fermo, sta sulla punta dovunque sia e compare e sparisce in dissolvenza. Niente fiammella, niente tremolio della brace, niente mano nel fumo; la cenere non cade, sparisce in dissolvenza e i suoi pezzetti sono già nella ciotola. Il bastoncino nuovo compare al posto del vecchio senza salire, e le cifre e le parole cambiano in dissolvenza. Il bastoncino si accorcia lo stesso, perché è il tempo.

Trappole

  • Il fumo sembrava una collana di perline. Gli sbuffi nascevano a fotogrammi interi, quindi a distanze alterne; la trasparenza cambiava gruppo a ogni giunto e i capi tondi di tratti diversi si sommavano. Ora ogni sbuffo nasce al suo istante esatto, la distanza è smussata sui vicini e i tratti hanno i capi piatti.
  • La cenere sotto il fumo, sommata in modo additivo, diventava un rettangolo bianco più luminoso della brace: si disegna dopo il fumo, in grigio.
  • Il fumo vecchio, disegnato col filo netto, sembrava fil di ferro aggrovigliato: il filo netto svanisce prima del corpo morbido, che si allarga.
  • Tre fili partiti a un pixel l’uno dall’altro salivano paralleli come fibre ottiche: partono quasi dallo stesso punto e si separano solo salendo, perché leggono il rumore un poco sfalsato.
  • La mano spingeva di traverso tutta la colonna per secondi: la spinta ora è debole, e il grosso lo fanno i due vortici.
  • Col movimento ridotto il fumo fermo, calcolato dalla prima punta, era alto la metà del necessario e scendeva con la punta lasciando vuoto in alto. Ora si calcola dalla punta più bassa e si sfuma in alto quando si disegna. Va calcolato a un tempo del rumore vicino a quello vero: più avanti il rumore lo ammucchiava in basso.
  • Contando il tempo coi fotogrammi una scheda in background perdeva il tempo (niente fotogrammi, e GSAP accorcia i salti): il tempo che resta viene dall’orologio.
  • L’anteprima clicca da sola ogni 2,8 secondi e avrebbe messo in pausa la seduta appena cominciata: un clic senza mano né tastiera non mette in pausa. Invio sul pulsante fa un clic con detail 0 come lo script: lo si riconosce dal keydown.

Librerie

GSAP 3.15.0, Newsreader (font variabile) 5.3.0.

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

Collaudo

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