Vai al contenuto
animorio
EN
Tutti i componenti

Il pulsante del frullatore

Pulsanti, SVG, HoverGSAPMediaPeso compresso: Demo 13 KBGSAP 28 KBGratisScarica lo zip

Il pulsante d'ordine di un bar dei succhi, nello stile ricco: nella punta tonda della pillola lampone sta un frullatore di smalto crema con la caraffa di vetro, piena di fragole, banana, kiwi e mirtilli su un dito di latte. Al clic la manopola scatta, il motore trema, la lama gira e il latte fa il vortice: la frutta gira, si sminuzza e si scioglie, il frullato diventa rosa e sale mentre la pillola si riempie come un timer. Poi il motore si ferma, il frullato ondeggia, fa la schiuma e la scritta diventa Smoothie's ready.

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 blender button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the blender button: the order button of a juice bar, with a cream enamel blender standing in the round left end
         of the pill. Strawberries, banana and kiwi slices and a few blueberries wait on a splash of milk in the glass
         jar. A click turns the dial: the motor hums, the blade spins, the fruit is pulled into the vortex and chopped,
         the milk turns pink and rises, and the pill fills like a timer. Then the motor stops, the smoothie sloshes,
         settles under a crown of froth, and the words turn to Smoothie's ready. A second click pours a fresh one -->
    <div class="bl" data-bl>
      <button class="bl__btn" type="button" data-btn data-autoclic>
        <span class="bl__fill" aria-hidden="true"><span class="bl__timer" data-timer></span></span>
        <span class="bl__faces">
          <span class="bl__face" data-face="rest">
            <span class="bl__word" data-label-text>Blend my smoothie</span>
            <span class="bl__note" data-note-text>Berry &amp; banana</span>
          </span>
          <span class="bl__face bl__face--busy" data-face="busy" aria-hidden="true">
            <span class="bl__shine" data-busy-text>Blending…</span>
          </span>
          <span class="bl__face bl__face--done" data-face="done" aria-hidden="true">
            <svg class="bl__tick" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path data-tick d="M3 8.6 L6.6 12 L13 4.4" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
            <span class="bl__done" data-done-text>Smoothie's ready</span>
          </span>
        </span>
      </button>

      <svg class="bl__art" viewBox="0 0 120 172" width="120" height="172" aria-hidden="true" data-art>
        <defs>
          <linearGradient id="bl-enamel" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0" style="stop-color:var(--enamel-deep)"/>
            <stop offset="0.28" style="stop-color:var(--enamel-light)"/>
            <stop offset="0.62" style="stop-color:var(--enamel)"/>
            <stop offset="1" style="stop-color:var(--enamel-deep)"/>
          </linearGradient>
          <linearGradient id="bl-chrome" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" style="stop-color:var(--chrome-light)"/>
            <stop offset="0.48" style="stop-color:var(--chrome)"/>
            <stop offset="0.52" style="stop-color:var(--chrome-dark)"/>
            <stop offset="1" style="stop-color:var(--chrome-light)"/>
          </linearGradient>
          <radialGradient id="bl-dial" cx="0.4" cy="0.35" r="0.7">
            <stop offset="0" style="stop-color:var(--chrome-light)"/>
            <stop offset="0.7" style="stop-color:var(--chrome)"/>
            <stop offset="1" style="stop-color:var(--chrome-dark)"/>
          </radialGradient>
          <linearGradient id="bl-glass" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0" stop-color="#cfe6ee" stop-opacity="0.55"/>
            <stop offset="0.2" stop-color="#ffffff" stop-opacity="0.08"/>
            <stop offset="0.8" stop-color="#ffffff" stop-opacity="0.04"/>
            <stop offset="1" stop-color="#cfe6ee" stop-opacity="0.6"/>
          </linearGradient>
          <linearGradient id="bl-rubber" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stop-color="#4a3c45"/>
            <stop offset="1" stop-color="#241b22"/>
          </linearGradient>
          <linearGradient id="bl-liquid-shade" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0" stop-color="#000" stop-opacity="0.16"/>
            <stop offset="0.3" stop-color="#000" stop-opacity="0"/>
            <stop offset="0.75" stop-color="#fff" stop-opacity="0.1"/>
            <stop offset="1" stop-color="#000" stop-opacity="0.2"/>
          </linearGradient>
          <!-- the inside of the jar: the liquid and the fruit are cut by it -->
          <clipPath id="bl-inside">
            <path d="M32.6 23 L87.4 23 L82.2 113 Q60 117.5 37.8 113 Z"/>
          </clipPath>
          <!-- the four kinds of fruit, drawn once -->
          <g id="bl-straw">
            <path d="M0 -7.6 C5.4 -7.6 7.4 -3.6 6.2 0.6 C5 4.8 2 7.6 0 8.4 C-2 7.6 -5 4.8 -6.2 0.6 C-7.4 -3.6 -5.4 -7.6 0 -7.6 Z" style="fill:var(--berry)"/>
            <path d="M0 -5.2 C3.2 -5.2 4.4 -2.6 3.6 0.4 C2.8 3.2 1.2 5 0 5.6 C-1.2 5 -2.8 3.2 -3.6 0.4 C-4.4 -2.6 -3.2 -5.2 0 -5.2 Z" style="fill:var(--berry-flesh)"/>
            <path d="M0 -4.4 L0 4.4" stroke="#fff" stroke-opacity="0.55" stroke-width="0.9" stroke-linecap="round"/>
            <g fill="#ffe7a8">
              <ellipse cx="-4.6" cy="-2.2" rx="0.45" ry="0.7"/><ellipse cx="4.6" cy="-2.2" rx="0.45" ry="0.7"/>
              <ellipse cx="-4.4" cy="2" rx="0.45" ry="0.7"/><ellipse cx="4.4" cy="2" rx="0.45" ry="0.7"/>
              <ellipse cx="-2.4" cy="5.2" rx="0.4" ry="0.6"/><ellipse cx="2.4" cy="5.2" rx="0.4" ry="0.6"/>
            </g>
            <path d="M-4.6 -7 C-2.4 -10 -1 -8 0 -9.6 C1 -8 2.4 -10 4.6 -7 C2.6 -6.2 1.4 -7.4 0 -6.4 C-1.4 -7.4 -2.6 -6.2 -4.6 -7 Z" style="fill:var(--leaf)"/>
          </g>
          <g id="bl-banana">
            <circle r="6.4" style="fill:var(--banana-skin)"/>
            <circle r="5.5" style="fill:var(--banana)"/>
            <circle r="2.2" style="fill:var(--banana-core)"/>
            <g style="fill:var(--banana-seed)">
              <circle cx="0" cy="-1.3" r="0.42"/><circle cx="1.15" cy="0.65" r="0.42"/><circle cx="-1.15" cy="0.65" r="0.42"/>
            </g>
            <path d="M-3.6 -3.4 A5 5 0 0 1 2 -4.6" fill="none" stroke="#fff" stroke-opacity="0.6" stroke-width="0.9" stroke-linecap="round"/>
          </g>
          <g id="bl-kiwi">
            <circle r="6.6" style="fill:var(--kiwi-skin)"/>
            <circle r="5.7" style="fill:var(--kiwi)"/>
            <circle r="3.6" style="fill:var(--kiwi-light)" fill-opacity="0.5"/>
            <ellipse rx="1.7" ry="1.4" style="fill:var(--kiwi-core)"/>
            <g fill="#1d2414">
              <ellipse cx="0" cy="-2.9" rx="0.32" ry="0.7"/><ellipse cx="2.05" cy="-2.05" rx="0.32" ry="0.7" transform="rotate(45 2.05 -2.05)"/>
              <ellipse cx="2.9" cy="0" rx="0.7" ry="0.32"/><ellipse cx="2.05" cy="2.05" rx="0.32" ry="0.7" transform="rotate(-45 2.05 2.05)"/>
              <ellipse cx="0" cy="2.9" rx="0.32" ry="0.7"/><ellipse cx="-2.05" cy="2.05" rx="0.32" ry="0.7" transform="rotate(45 -2.05 2.05)"/>
              <ellipse cx="-2.9" cy="0" rx="0.7" ry="0.32"/><ellipse cx="-2.05" cy="-2.05" rx="0.32" ry="0.7" transform="rotate(-45 -2.05 -2.05)"/>
            </g>
          </g>
          <g id="bl-blue">
            <circle r="3.4" style="fill:var(--blueberry)"/>
            <circle cx="-1.1" cy="-1.1" r="1.2" fill="#fff" fill-opacity="0.28"/>
            <path d="M-1 -2.6 L0 -1.8 L1 -2.6 L0.6 -3.3 L-0.6 -3.3 Z" fill="#1c2050"/>
          </g>
        </defs>

        <!-- the shadow on the pill's foot line -->
        <ellipse cx="60" cy="168.6" rx="40" ry="2.6" fill="#3a1424" fill-opacity="0.18"/>

        <!-- the power cord, out of the back of the base and down to the floor -->
        <path d="M24 158 C14 158 10 162 8 168 C7 170.4 4 171 1 171" fill="none" stroke="#2a1f26" stroke-width="2.2" stroke-linecap="round"/>
        <path d="M23 157.2 C15 157.4 11.6 160.6 9.8 165" fill="none" stroke="#fff" stroke-opacity="0.25" stroke-width="0.7" stroke-linecap="round"/>
        <g data-body>
          <!-- the motor base, cream enamel -->
          <path d="M30 122 L90 122 Q93 122 93.6 125 L99 162 Q99.6 167 94.6 167 L25.4 167 Q20.4 167 21 162 L26.4 125 Q27 122 30 122 Z" fill="url(#bl-enamel)"/>
          <path d="M30 122 L90 122 Q93 122 93.6 125 L94 128 L26 128 L26.4 125 Q27 122 30 122 Z" fill="#fff" fill-opacity="0.35"/>
          <path d="M21.6 159 L98.4 159 L99 162 Q99.6 167 94.6 167 L25.4 167 Q20.4 167 21 162 Z" fill="#000" fill-opacity="0.1"/>
          <!-- the chrome band with the name -->
          <rect x="27" y="130" width="66" height="7" rx="2" fill="url(#bl-chrome)"/>
          <text class="bl__brand" x="60" y="135.3" text-anchor="middle" data-brand-text>WHIRL</text>
          <!-- the vent slots on the side and the two screws of the band -->
          <g stroke="#000" stroke-opacity="0.16" stroke-width="1.1" stroke-linecap="round">
            <path d="M28.6 142 L27.6 150"/><path d="M31.6 142 L30.8 150"/><path d="M34.6 142 L34 150"/>
            <path d="M91.4 142 L92.4 150"/><path d="M88.4 142 L89.2 150"/><path d="M85.4 142 L86 150"/>
          </g>
          <g>
            <circle cx="30.6" cy="133.5" r="1.7" fill="url(#bl-dial)" stroke="#7d8a92" stroke-width="0.4"/>
            <path d="M29.6 132.7 L31.6 134.3" stroke="#5d6870" stroke-width="0.5" stroke-linecap="round"/>
            <circle cx="89.4" cy="133.5" r="1.7" fill="url(#bl-dial)" stroke="#7d8a92" stroke-width="0.4"/>
            <path d="M88.4 134.3 L90.4 132.7" stroke="#5d6870" stroke-width="0.5" stroke-linecap="round"/>
          </g>
          <!-- a small scratch in the enamel -->
          <path d="M80.6 156 l4.2 -1.4" stroke="#fff" stroke-opacity="0.55" stroke-width="0.5" stroke-linecap="round"/>
          <!-- the speed dial with its ticks -->
          <g fill="none" style="stroke:var(--enamel-ink)" stroke-width="1" stroke-linecap="round" stroke-opacity="0.55">
            <path d="M48.6 152.8 L46.8 154.2"/><path d="M49.2 144.6 L47.2 143.6"/><path d="M54.4 139.6 L53.8 137.6"/>
            <path d="M65.6 139.6 L66.2 137.6"/><path d="M70.8 144.6 L72.8 143.6"/><path d="M71.4 152.8 L73.2 154.2"/>
          </g>
          <circle cx="60" cy="149" r="10.2" fill="#000" fill-opacity="0.12"/>
          <circle cx="60" cy="148.4" r="9.6" fill="url(#bl-dial)"/>
          <circle cx="60" cy="148.4" r="6.6" fill="none" stroke="#fff" stroke-opacity="0.45" stroke-width="0.8"/>
          <g data-dial>
            <rect x="58.9" y="139.6" width="2.2" height="6.6" rx="1.1" style="fill:var(--berry-deep)"/>
          </g>
          <!-- the rubber feet -->
          <rect x="26" y="164" width="12" height="5" rx="2.2" fill="#2a1f26"/>
          <rect x="82" y="164" width="12" height="5" rx="2.2" fill="#2a1f26"/>

          <!-- the jar, which shakes a little more than the base when the motor runs -->
          <g data-jar>
            <!-- the collar that locks the jar on the base -->
            <path d="M34 112 L86 112 L88.6 122.4 L31.4 122.4 Z" fill="url(#bl-rubber)"/>
            <path d="M35 113.6 L85 113.6" stroke="#fff" stroke-opacity="0.18" stroke-width="1"/>
            <!-- the handle -->
            <path d="M86.4 34 C101 34 104.6 40 104.6 52 L104.6 82 C104.6 94 100 99 84.2 99" fill="none" style="stroke:var(--handle)" stroke-width="7" stroke-linecap="round"/>
            <path d="M88 37.4 C98 37.6 100.8 42 100.8 52 L100.8 82" fill="none" stroke="#fff" stroke-opacity="0.3" stroke-width="1.6" stroke-linecap="round"/>

            <!-- what is inside, cut by the glass -->
            <g clip-path="url(#bl-inside)">
              <rect x="30" y="20" width="60" height="100" fill="#eaf6fa" fill-opacity="0.55"/>
              <g data-bubbles></g>
              <path data-liquid d="M30 92 L90 92 L90 120 L30 120 Z" style="fill:var(--milk)"/>
              <path data-liquid-shade d="M30 92 L90 92 L90 120 L30 120 Z" fill="url(#bl-liquid-shade)"/>
              <path data-surface d="M30 92 L90 92" fill="none" stroke="#fff" stroke-opacity="0.55" stroke-width="1.1"/>
              <g data-foam opacity="0"></g>
              <g data-bits></g>
              <g data-fruit></g>
              <!-- the blade, seen from the side: it turns by squeezing -->
              <g transform="translate(60 109.6)">
                <rect x="-1.4" y="-1" width="2.8" height="5" rx="0.6" fill="#7a868e"/>
                <g data-blade>
                  <path d="M-12 -1.2 C-6 -3.4 6 -3.4 12 -1.2 C6 0.4 -6 0.4 -12 -1.2 Z" fill="url(#bl-chrome)"/>
                </g>
                <circle r="1.6" fill="#5d6870"/>
              </g>
            </g>

            <!-- the glass in front: its edge, its marks and the light on it -->
            <path d="M31 21 L89 21 L83.6 112.6 Q60 117.6 36.4 112.6 Z" fill="url(#bl-glass)" stroke="#9fbfcc" stroke-opacity="0.9" stroke-width="1.6" stroke-linejoin="round"/>
            <g stroke="#7fa3b2" stroke-opacity="0.7" stroke-width="1" stroke-linecap="round">
              <path d="M78.6 46 L84 46"/><path d="M80.2 58 L83.4 58"/><path d="M78.4 70 L82.8 70"/><path d="M80 82 L82.2 82"/><path d="M77.8 94 L81.6 94"/>
            </g>
            <!-- the paper label of the juice bar, stuck on the glass a little crooked -->
            <g transform="rotate(-3 54 32)">
              <rect x="42" y="26" width="25" height="12" rx="1.6" fill="#fffaf2" stroke="#e7d6bd" stroke-width="0.5"/>
              <rect x="42" y="26" width="25" height="2.4" rx="1" style="fill:var(--pill)"/>
              <text class="bl__label" x="54.5" y="33.6" text-anchor="middle">PULP</text>
              <text class="bl__label-small" x="54.5" y="36.6" text-anchor="middle">juice bar</text>
              <path d="M64.4 37.4 L67 34.8 L67 37.4 Z" fill="#000" fill-opacity="0.08"/>
            </g>
            <!-- a few drops of condensation on the cold glass -->
            <g fill="#fff" fill-opacity="0.7">
              <ellipse cx="74" cy="42" rx="0.7" ry="1"/><ellipse cx="76.4" cy="50" rx="0.5" ry="0.75"/>
              <ellipse cx="44" cy="44" rx="0.55" ry="0.8"/><ellipse cx="71" cy="31" rx="0.5" ry="0.7"/>
            </g>
            <g data-splash></g>
            <path d="M37.6 28 L36.8 54" stroke="#fff" stroke-opacity="0.85" stroke-width="2.6" stroke-linecap="round"/>
            <path d="M38.6 62 L38.2 70" stroke="#fff" stroke-opacity="0.7" stroke-width="2" stroke-linecap="round"/>
            <path d="M84 30 L82.6 60" stroke="#fff" stroke-opacity="0.4" stroke-width="1.2" stroke-linecap="round"/>

            <!-- the lid and its cap -->
            <g data-lid>
              <path d="M28.6 13.6 Q28.6 11 31.2 11 L88.8 11 Q91.4 11 91.4 13.6 L91.4 20.4 Q91.4 22.6 89.2 22.6 L30.8 22.6 Q28.6 22.6 28.6 20.4 Z" fill="url(#bl-rubber)"/>
              <path d="M31 13.4 L89 13.4" stroke="#fff" stroke-opacity="0.22" stroke-width="1.2" stroke-linecap="round"/>
              <g data-cap>
                <path d="M51 11.4 L51 6.6 Q51 4.4 53.2 4.4 L66.8 4.4 Q69 4.4 69 6.6 L69 11.4 Z" style="fill:var(--berry)"/>
                <path d="M53 6.4 L67 6.4" stroke="#fff" stroke-opacity="0.4" stroke-width="1.1" stroke-linecap="round"/>
              </g>
            </g>
          </g>
        </g>
      </svg>

      <p class="sr" aria-live="polite" data-live></p>
    </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.

47 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 pulsante del frullatore» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco una pillola lampone con la scritta Blend my smoothie in crema e, sotto, Berry & banana in giallo mango. Nella sua punta tonda sinistra sta un frullatore disegnato in SVG: la base del motore di smalto crema con la luce sul fianco, una fascia cromata col nome WHIRL fissata da due viti, le feritoie sui lati, la manopola cromata della velocità con le tacche e la lancetta lampone, i piedini di gomma; sopra, il collare di gomma, la caraffa di vetro col manico, le tacche delle misure, un'etichetta di carta incollata un po' storta, qualche goccia di condensa e i riflessi, il coperchio di gomma col tappo lampone. Dentro, su un dito di latte, una pila di fragole tagliate a metà coi semi e le foglie, fette di banana, fette di kiwi coi semini e mirtilli. Sotto il mouse il motore dà un colpetto: la caraffa trema e la frutta fa un saltello. Al clic la manopola scatta a fondo, il motore parte e fa tremare la caraffa, la lama gira, il latte si scava in un vortice che sale sulle pareti, ridisegnato a ogni fotogramma; la frutta viene trascinata in giro, si fa piccola e si sminuzza in pezzetti dei suoi colori, salgono le bollicine, schizzi rosa colano sul vetro, il latte diventa rosa e sale fino in cima mentre una fascia mango riempie la pillola e la scritta diventa Blending… con un riflesso. Alla fine il motore si ferma e la manopola torna: il frullato ondeggia da una parete all'altra e si calma, in cima si forma la schiuma, il tappo fa un salto e ricade, e la scritta diventa Smoothie's ready con una spunta disegnata. Un secondo clic svuota la caraffa e fa cadere dentro la frutta fresca, che rimbalza sulla pila.

Come funziona

Il frullatore in SVG, a strati

Un solo SVG sopra la punta sinistra della pillola, che non prende il puntatore. Dentro la caraffa tutto è tagliato da un clipPath con la forma dell'interno: prima il fondo del vetro, poi il liquido, la schiuma, i pezzetti, la frutta e la lama; davanti il vetro coi suoi bordi, le tacche, l'etichetta e i riflessi, così il contenuto sembra dietro il vetro.

La superficie ridisegnata a ogni fotogramma

Il liquido è un percorso di 19 punti che va da una parete all'altra: la sua altezza è il livello, meno una conca gaussiana in mezzo che è il vortice (più profonda quanto più gira il motore), più l'acqua che sale sulle pareti, più un'onda stazionaria per lo sciabordio. Il colore del liquido va dal latte al rosa con gsap.utils.interpolate, letto dalle variabili di :root.

La frutta in giro

Ogni pezzo ha il suo posto nella pila e un'orbita nel vortice, a un'altezza e con un raggio suoi: la spinta del motore lo porta dalla pila all'orbita, dove gira con un'ellisse vista di lato e si fa più piccolo dietro. Ogni pezzo ha il momento in cui la lama lo prende: da lì si rimpicciolisce e svanisce, mentre nascono pezzetti dei suoi colori che girano e si sciolgono nel rosa.

Lo sciabordio come una molla smorzata

Quando il motore si ferma il programma dà un colpo all'ampiezza dell'onda, che a ogni fotogramma si moltiplica per un esponenziale che la spegne: il frullato va da una parete all'altra sempre meno, come una molla. Il tremito della base e della caraffa è fatto di seni a frequenze diverse, proporzionali alla velocità del motore.

La regia e il pulsante vero

Una timeline GSAP gira la manopola, avvia il motore, sminuzza, colora e alza il livello per BLEND_TIME secondi, riempie il timer, ferma il motore, fa sciabordare, mette la schiuma e fa saltare il tappo. Il ciclo di disegno sta sul ticker di GSAP e si spegne quando niente si muove. È un button: Invio e Spazio come il clic, aria-busy, aria-disabled e una regione aria-live.

Valori da cambiare

NomeFileDi partenzaCosa cambia
LABELscript.jsBlend my smoothieLe parole a riposo.
NOTEscript.jsBerry & bananaLe parole piccole sotto.
BUSYscript.jsBlending…Le parole mentre il motore gira.
DONEscript.jsSmoothie's readyLe parole quando il frullato è pronto.
BRANDscript.jsWHIRLIl nome sulla fascia cromata della base.
BLEND_TIMEscript.js2.8Quanto gira il motore, in secondi.
SWIRLscript.js1Quanto è profondo il vortice: 0,4 calmo, 1,6 selvaggio.
SLOSHscript.js1Quanto ondeggia il frullato quando il motore si ferma.
FRUITscript.js11Quanti pezzi di frutta ci sono nella caraffa.
SPEEDscript.js1Quanto corre tutto: 0,6 lento, 1,6 svelto.

Provali nel Playground

Quando usarla

Per il pulsante d'ordine di un bar dei succhi, di un bar per la colazione, di un'app di consegne o di un negozio di elettrodomestici, o per un pulsante che fa partire un lavoro che richiede qualche secondo.

Sul telefono

Il componente è largo 318 pixel o lo schermo meno 32, e alto 172 con la pillola di 60; a riposo la scritta piccola sta sotto quella grande, così entrano tutte e due. Senza hover, il dito che si appoggia dà il colpetto al motore come il mouse.

Con il movimento ridotto

Niente tremito, niente vortice, niente frutta che gira né schizzi: al clic la frutta svanisce, il latte diventa rosa e sale in una dissolvenza, la pillola si riempie e le parole cambiano svanendo.

Trappole

  • Il contenuto disegnato davanti al vetro sembrava appiccicato fuori: va tagliato con un clipPath della forma dell'interno e il vetro va disegnato dopo, coi suoi riflessi.
  • In SVG un attributo come fill="var(--x)" non legge le variabili CSS: serve style="fill:var(--x)".
  • Il colore del liquido cambia nel tempo, quindi non può stare solo nel CSS: lo script legge i colori di :root all'avvio e li mescola con gsap.utils.interpolate.
  • Senza svgOrigin la manopola e il tappo giravano attorno all'angolo dell'SVG: ogni pezzo ha il suo perno nelle coordinate dell'SVG.
  • Un ciclo di disegno sempre acceso consuma anche a riposo: il ticker si toglie quando motore, sciabordio e colpetto sono fermi.

Librerie

GSAP 3.15.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 23 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