Vai al contenuto
animorio
EN
Torna alla libreria

L’orologio a cucù

SVGGSAPImpegnativaPeso compresso: Demo 13 KBGSAP 28 KBGratisScarica lo zip

Un orologio a cucù di legno intagliato, tutto disegnato in SVG: le lancette corrono fino all’ora, le porticine si aprono con un rimbalzo, l’uccellino fa un inchino per ogni ora, le figurine ballano sul balconcino e il pendolo accelera; poi le porte sbattono e l’orologio trema sul chiodo. Un clic porta all’ora dopo.

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>L’orologio a cucù</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="pagina">
    <header class="testo">
      <p class="etichetta"><span>Kuckuckhaus, clockmakers</span></p>
      <h1 class="titolo">
        <span class="riga"><span>Carved by hand.</span></span>
        <span class="riga"><span>Opening on the hour.</span></span>
      </h1>
      <p class="corpo"><span>Our first clocks are still on the bench, one leaf at a time. The shop opens this winter, and the bird will let you know.</span></p>
      <p class="ora" aria-live="polite"><span class="ora__dentro">It’s <span class="ora__maschera"><span class="ora__parola" data-parola>three</span></span> o’clock</span></p>
      <p class="aiuto"><span>Click the clock to strike the next hour.</span></p>
    </header>

    <div class="palco">
      <button class="orologio" type="button" data-orologio aria-label="Strike the next hour">
        <svg class="orologio__svg" data-svg viewBox="-12 -40 444 872" aria-hidden="true" focusable="false">
          <defs>
            <linearGradient id="g-muro" x1="0" y1="0" x2="1" y2="1">
              <stop offset="0" style="stop-color: var(--legno-chiaro)" />
              <stop offset="0.55" style="stop-color: var(--legno)" />
              <stop offset="1" style="stop-color: var(--legno-scuro)" />
            </linearGradient>
            <linearGradient id="g-pilastro" x1="0" y1="0" x2="1" y2="0">
              <stop offset="0" style="stop-color: var(--legno-scuro)" />
              <stop offset="0.45" style="stop-color: var(--legno-luce)" />
              <stop offset="1" style="stop-color: var(--legno)" />
            </linearGradient>
            <radialGradient id="g-quadrante" cx="0.42" cy="0.38" r="0.7">
              <stop offset="0" stop-color="#fbf4e2" />
              <stop offset="0.7" stop-color="#f1e3c2" />
              <stop offset="1" stop-color="#dcc597" />
            </radialGradient>
            <linearGradient id="g-buio" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stop-color="#140c07" />
              <stop offset="1" stop-color="#2c1a0f" />
            </linearGradient>
            <linearGradient id="g-notte" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stop-color="#1d2a40" />
              <stop offset="1" stop-color="#3d5068" />
            </linearGradient>
            <linearGradient id="g-pigna" x1="0" y1="0" x2="1" y2="0">
              <stop offset="0" stop-color="#2a1b11" />
              <stop offset="0.4" stop-color="#6e4c30" />
              <stop offset="1" stop-color="#22150d" />
            </linearGradient>
            <linearGradient id="g-ottone" x1="0" y1="0" x2="1" y2="1">
              <stop offset="0" stop-color="#f0d58a" />
              <stop offset="0.5" stop-color="#c39a45" />
              <stop offset="1" stop-color="#7d5d22" />
            </linearGradient>
            <filter id="f-ombra" x="-20%" y="-20%" width="140%" height="140%">
              <feGaussianBlur stdDeviation="9" />
            </filter>
            <clipPath id="c-muro"><path d="M210 70 L60 196 L70 196 V560 H350 V196 L360 196 Z" /></clipPath>
            <clipPath id="c-sinistra"><rect x="-40" y="-60" width="250" height="400" /></clipPath>
            <clipPath id="c-destra"><rect x="210" y="-60" width="250" height="400" /></clipPath>
            <!-- la pigna, disegnata dallo script: punta di sopra in (0 0) -->
            <g id="pigna" data-pigna></g>
            <!-- le maglie delle catene, una per catena: lo script le fa scorrere -->
            <g data-maglie></g>
          </defs>

          <!-- tutto l'orologio, appeso al chiodo: trema quando le porte sbattono -->
          <g data-tutto>
            <path class="ombra" d="M210 18 L-2 214 L56 214 V600 H364 V214 L422 214 Z" transform="translate(10 16)" filter="url(#f-ombra)" />

            <!-- il pendolo, dietro la cassa: gira intorno al perno -->
            <g data-pendolo>
              <rect x="207" y="462" width="6" height="292" rx="2" class="lb" />
              <rect x="208.2" y="462" width="1.6" height="292" class="ll" opacity="0.5" />
              <g data-lente></g>
            </g>

            <!-- le catene e le pigne -->
            <g data-catene></g>

            <!-- la cassa -->
            <path d="M210 70 L60 196 L70 196 V560 H350 V196 L360 196 Z" fill="url(#g-muro)" />
            <g clip-path="url(#c-muro)" data-venature></g>
            <rect x="70" y="196" width="16" height="364" fill="url(#g-pilastro)" />
            <rect x="334" y="196" width="16" height="364" fill="url(#g-pilastro)" />
            <path d="M78 206 V550 M342 206 V550" class="solco" />
            <rect x="64" y="410" width="292" height="10" rx="2" class="ls" />
            <rect x="64" y="410" width="292" height="3" class="ll" opacity="0.6" />

            <!-- la porticina dell'uccellino -->
            <path d="M174 190 V146 A36 36 0 0 1 246 146 V190 Z" class="lb" />
            <path d="M177 188 V146 A33 33 0 0 1 243 146 V188 Z" class="lc" />
            <path d="M182 184 V146 A28 28 0 0 1 238 146 V184 Z" fill="url(#g-buio)" />
            <rect x="168" y="184" width="84" height="8" rx="2" class="ls" />
            <rect x="168" y="184" width="84" height="2.5" class="ll" opacity="0.7" />
            <g data-porta="sinistra">
              <g data-faccia="davanti">
                <path d="M182 184 V146 A28 28 0 0 1 210 118 V184 Z" class="l" />
                <path d="M186 180 V148 A23 23 0 0 1 206 124 V180 Z" class="ls" opacity="0.55" />
                <path d="M188 178 V149 A20 20 0 0 1 204 127 V178 Z" class="lc" opacity="0.65" />
                <circle cx="205" cy="156" r="2.2" fill="url(#g-ottone)" />
              </g>
              <g data-faccia="dietro">
                <path d="M182 184 V146 A28 28 0 0 1 210 118 V184 Z" class="ls" />
                <path d="M187 180 V149 A22 22 0 0 1 205 126 V180 Z" class="l" opacity="0.6" />
                <path d="M186 182 V148 A23 23 0 0 1 206 124" class="solco" />
              </g>
            </g>
            <g data-porta="destra">
              <g data-faccia="davanti">
                <path d="M238 184 V146 A28 28 0 0 0 210 118 V184 Z" class="l" />
                <path d="M234 180 V148 A23 23 0 0 0 214 124 V180 Z" class="ls" opacity="0.55" />
                <path d="M232 178 V149 A20 20 0 0 0 216 127 V178 Z" class="lc" opacity="0.65" />
                <circle cx="215" cy="156" r="2.2" fill="url(#g-ottone)" />
              </g>
              <g data-faccia="dietro">
                <path d="M238 184 V146 A28 28 0 0 0 210 118 V184 Z" class="ls" />
                <path d="M233 180 V149 A22 22 0 0 0 215 126 V180 Z" class="l" opacity="0.6" />
                <path d="M234 182 V148 A23 23 0 0 0 214 124" class="solco" />
              </g>
            </g>

            <!-- l'uccellino: esce dalla porta, i piedi sul trespolo in (0 0) -->
            <g transform="translate(210 186)">
              <g data-uccello>
                <rect x="-16" y="-1" width="40" height="5" rx="2" class="ls" />
                <g data-corpo>
                  <path d="M-4 -12 L-6 0 M4 -12 L3 0" class="zampe" />
                  <g data-coda><path d="M10 -18 L44 -34 L47 -27 L42 -24 L45 -19 L14 -10 Z" class="u-scuro" /></g>
                  <path d="M-22 -26 C-22 -40 -2 -44 12 -34 C22 -26 18 -10 2 -9 C-12 -8 -22 -14 -22 -26 Z" class="u-corpo" />
                  <path d="M-21 -24 C-18 -15 -8 -11 2 -11 C-6 -16 -12 -22 -14 -30 Z" class="u-petto" />
                  <g data-becco-su><path d="M-31 -38 L-44 -35 L-30 -33 Z" class="u-becco" /></g>
                  <g data-becco-giu><path d="M-31 -33 L-41 -32 L-30 -30.5 Z" class="u-becco" /></g>
                  <circle cx="-22" cy="-37" r="10" class="u-corpo" />
                  <circle cx="-24" cy="-39" r="1.9" class="u-occhio" />
                  <g data-ala><path d="M-10 -30 C2 -38 20 -32 28 -22 C14 -20 0 -20 -10 -30 Z" class="u-scuro" /><path d="M-4 -29 C6 -31 14 -28 20 -24" class="u-penna" /><path d="M-2 -26 C8 -27 14 -25 18 -22" class="u-penna" /></g>
                </g>
              </g>
            </g>

            <!-- il quadrante -->
            <circle cx="210" cy="300" r="104" class="lb" />
            <circle cx="210" cy="300" r="101" class="ls" />
            <g data-perline></g>
            <circle cx="210" cy="300" r="91" class="lb" />
            <circle cx="210" cy="300" r="89" fill="url(#g-quadrante)" />
            <g data-tacche></g>
            <g data-numeri class="numeri"></g>
            <g data-ore>
              <path d="M207 306 L207.5 270 C200 268 200 258 208 256 L210 247 L212 256 C220 258 220 268 212.5 270 L213 306 Z" class="lancetta" />
              <circle cx="210" cy="263" r="3.2" fill="#efe1bf" />
            </g>
            <g data-minuti>
              <path d="M208.4 308 L208.6 242 C203 240 203 233 208.6 232 L210 218 L211.4 232 C217 233 217 240 211.4 242 L211.6 308 Z" class="lancetta" />
              <circle cx="210" cy="237" r="2" fill="#efe1bf" />
            </g>
            <circle cx="210" cy="300" r="6.5" fill="url(#g-ottone)" />
            <circle cx="210" cy="300" r="2.4" fill="#3a2614" />

            <!-- il balconcino coi ballerini -->
            <path d="M118 526 V452 A92 36 0 0 1 302 452 V526 Z" class="lb" />
            <path d="M123 526 V454 A87 32 0 0 1 297 454 V526 Z" fill="url(#g-notte)" />
            <g data-sfondo></g>
            <ellipse cx="210" cy="510" rx="80" ry="11" class="lb" />
            <ellipse cx="210" cy="508" rx="78" ry="9" class="ls" />
            <g data-ballerini></g>
            <g data-ringhiera></g>

            <!-- il grembiule sotto la cassa -->
            <g data-grembiule></g>

            <!-- il tetto -->
            <g data-tetto></g>
            <!-- le foglie intagliate -->
            <g data-foglie></g>
          </g>
        </svg>
      </button>
    </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.

25 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 «L’orologio a cucù» da Animorio e adattala al mio sito

Cosa fa

Sulla carta da parati a righe di una bottega inventata, Kuckuckhaus, c’è la pagina di un negozio che apre presto: a sinistra il titolo, a destra un orologio a cucù appeso al chiodo. Ha il tetto a spiovente coperto di tegole tonde, una cresta di foglie di quercia intagliate sul colmo, la mantovana coi festoni e i fori, le foglie lungo i fianchi e intorno al quadrante, il quadrante color avorio coi numeri e le perline, un balconcino con la ringhiera tornita e, sotto, il pendolo con la lente a foglia e due pigne appese alle catene. All’apertura l’orologio scende sul chiodo e dondola fino a fermarsi. Le lancette corrono fino all’ora piena, la superano appena e si assestano; la scritta «It’s three o’clock» cambia parola con un salto. Le porticine si spalancano con un rimbalzo e l’orologio sobbalza; esce l’uccellino, che si ingrandisce venendo avanti, e fa l’inchino tante volte quante l’ora: becco aperto, ali e coda alzate, e su con un rimbalzo. A ogni inchino la pigna della suoneria scende di un dente. Intanto sul balconcino quattro figurine, due ragazze col cappello a pompon e due ragazzi col cappello di feltro, girano in tondo saltellando e piroettando, davanti più grandi e dietro più piccole, e il pendolo batte più in fretta e più largo. Poi l’uccellino rientra, le porte sbattono di colpo e tutto l’orologio trema sul chiodo, con le pigne che dondolano. La lancetta dei minuti riparte piano, la pigna del tempo scende coi minuti, e dopo un momento arriva l’ora dopo; quando una pigna è quasi in fondo, la catena la tira su con un rimbalzo. Un clic porta subito all’ora dopo; passando col mouse le porticine si schiudono appena.

Come funziona

Un orologio intagliato dallo script

La pagina contiene lo scheletro dell’orologio (cassa, porticine, uccellino, quadrante, balconcino); tutto quello che si ripete lo intaglia lo script con un generatore di numeri a caso col seme, così esce uguale a ogni visita. Una foglia di quercia è un tracciato calcolato: la larghezza segue un seno e i lobi sono una seconda sinusoide sul bordo; ogni foglia ha l’ombra spostata, il legno, una luce sul lato alto e le venature. Le tegole stanno in due falde: un gruppo con una matrix che mette l’asse x lungo la pendenza, file di tegole tonde dall’interno verso il bordo, e un clipPath che taglia ogni falda a metà, così al colmo si incontrano dritte.

Il colore del legno

WOOD è un solo colore: lo script ne ricava cinque tinte, mescolandolo verso il nero e verso un bianco caldo, e le scrive come variabili CSS sull’SVG. Le parti di legno hanno solo una classe (.l, .ls, .lb, .lc, .ll) e anche i gradienti usano le variabili con style="stop-color: var(--legno)", così cambiando un valore cambia tutto l’orologio, ombre e luci comprese.

Uno stato solo, disegnato a ogni fotogramma

Porte, uccellino, inchino, becco, ali, ballo, pendolo, pigne e scossa sono numeri in un oggetto; GSAP anima quei numeri e una funzione sul ticker riscrive gli attributi transform. Così le porte si piegano sul loro cardine con scale(x 1) e, passato lo zero, mostrano il retro; le figurine girano su un’ellisse e si riordinano davanti e dietro solo quando l’ordine cambia; l’uccellino fa l’inchino intorno ai piedi.

Il pendolo vero

Il pendolo è lungo 29 centimetri: la sua pulsazione è la radice di g su L, corretta per le grandi ampiezze dividendo per 1 + θ²/16, e il tempo passa da una fase che il ticker fa avanzare. Durante lo spettacolo un moltiplicatore della fase sale a 1,9 e l’ampiezza cresce di un quarto, poi tornano piano. Le pigne seguono l’orologio: quella del tempo scende coi minuti, quella della suoneria di un dente a ogni inchino, il capo libero della catena sale di altrettanto e le maglie, un pattern con patternTransform, scorrono con loro.

La regia

Ogni ora è una timeline: le lancette corrono con back.inOut (superano l’ora e tornano), le porte si aprono con back.out e un piccolo sobbalzo, l’uccellino esce, gli inchini sono quattro tween per volta (giù con power2.in, su con back.out), le figurine e il pendolo accelerano; alla fine le porte si chiudono con power4.in e la scossa è una serie di rotazioni alterne che si smorzano, intorno al chiodo. Al termine parte un delayedCall per l’ora dopo; il clic lo annulla e chiama subito l’ora dopo, rimettendo prima tutto al suo posto.

Valori da cambiare

NomeFileDi partenzaCosa cambia
HOURscript.js3L’ora del primo spettacolo, da 1 a 12: le lancette partono poco dopo l’ora prima e corrono fin lì.
BOWSscript.js0Quanti inchini fa l’uccellino: 0 = tanti quanti l’ora, come un orologio vero; un altro numero li fissa a ogni ora.
PENDULUMscript.js13Quanto oscilla il pendolo, in gradi per parte (0 = fermo). Più largo, un poco più lento, come un pendolo vero.
WOODscript.js'#7a4a2b'Il colore del legno: le ombre e le luci dell’intaglio si ricavano da questo.
SPEEDscript.js1La velocità di tutto, pendolo compreso: 2 è il doppio, 0.5 la metà.
RESTscript.js2.5Secondi di riposo dopo uno spettacolo prima dell’ora dopo; con 0 l’ora dopo arriva solo col clic.

Provali nel Playground

Quando usarla

Per una pagina «coming soon» o la prima schermata di una bottega artigiana, di un negozio di orologi o di giocattoli di legno, di una pasticceria di montagna, di un albergo in baita; per un conto alla rovescia, un 404 simpatico o una pagina che segna un orario.

Sul telefono

La stessa animazione con le misure adattate: il titolo va in alto, centrato, e l’orologio riempie lo spazio sotto; su uno schermo basso il testo lungo si nasconde. Un tocco porta all’ora dopo.

Con il movimento ridotto

Niente si muove: pendolo e pigne restano fermi e le lancette sono già all’ora; le porticine svaniscono e al loro posto compare l’uccellino, che poi svanisce mentre tornano le porte. La scritta dell’ora cambia in dissolvenza.

Trappole

  • Le due falde del tetto, lasciate intere, si sovrapponevano al colmo e una copriva l’altra di traverso: ognuna ha un clipPath che la taglia sulla verticale del colmo, così si incontrano su una riga dritta.
  • La matrice di una falda specchia gli assi (determinante -1): gli archi delle tegole vanno pensati nello spazio della falda, non della pagina, altrimenti girano dalla parte sbagliata.
  • Le porte piegate con scale(x 1) a zero diventano una riga e il loro retro sarebbe uguale al davanti: sotto un valore minimo la scala resta 0,02 e, passato lo zero, si mostra il retro con un altro disegno.
  • Le figurine che girano in tondo devono passare l’una dietro l’altra: si riordinano nel DOM secondo la profondità, ma solo quando l’ordine cambia davvero, non a ogni fotogramma.
  • Il clic durante uno spettacolo lasciava l’uccellino fuori o le porte a metà: ogni ora comincia riportando tutto chiuso in tre decimi di secondo, poi riparte.
  • Il pendolo non può essere un tween avanti e indietro: quando accelera cambierebbe di colpo posizione. È una fase che avanza, e quello che accelera è la velocità della fase.

Librerie

GSAP 3.15.0, Fraunces (font variabile) 5.3.0, Mona 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 10 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.

Tutte le animazioni