Vai al contenuto
animorio
EN
Torna alla libreria

Il flipper

Fisica, SVGGSAPImpegnativaPeso compresso: Demo 15 KBGSAP 28 KBGratisScarica lo zip

Un piccolo flipper visto dall’alto e inclinato come uno vero, tutto in SVG: la pallina d’acciaio segue la fisica (gravità sul piano, rimbalzi, respingenti che la calciano con un lampo pieno, bersagli che cadono, una rampa da scalare) e i due flipper scattano col clic o coi tasti. Da sola gioca un pilota automatico; il punteggio rotola come un contatore meccanico.

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>Night Comet pinball</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/unbounded@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage>
    <!-- the backbox: the name of the table, the rolling score and a strip for messages -->
    <header class="backbox" data-backbox>
      <p class="backbox__title">Night Comet</p>
      <div class="score" data-score role="img" aria-label="Score"></div>
      <p class="message" data-message aria-live="polite"></p>
    </header>

    <!-- the table, tilted away from you: the playfield is one SVG, 440 by 800 units -->
    <div class="tilt" data-tilt>
      <div class="tilt__plane">
        <svg class="table" data-table viewBox="0 0 440 824" role="img" aria-label="A small pinball table with three pop bumpers, five drop targets, a ramp and two flippers">
          <defs>
            <radialGradient id="pf" cx="50%" cy="38%" r="75%">
              <stop offset="0" class="stop-pf-a"/>
              <stop offset="1" class="stop-pf-b"/>
            </radialGradient>
            <radialGradient id="steel" cx="38%" cy="32%" r="72%">
              <stop offset="0" stop-color="#ffffff"/>
              <stop offset="0.35" stop-color="#d9dde6"/>
              <stop offset="0.75" stop-color="#7d8496"/>
              <stop offset="1" stop-color="#3b4152"/>
            </radialGradient>
            <linearGradient id="tail" x1="0" y1="1" x2="1" y2="0">
              <stop offset="0" class="stop-tail-a"/>
              <stop offset="1" class="stop-tail-b"/>
            </linearGradient>
            <filter id="soft" x="-30%" y="-30%" width="160%" height="160%">
              <feGaussianBlur stdDeviation="3"/>
            </filter>
            <clipPath id="field">
              <path d="M20 800 L20 220 A200 200 0 0 1 420 220 L420 800 Z"/>
            </clipPath>
          </defs>

          <g data-art>
            <path class="playfield" d="M20 800 L20 220 A200 200 0 0 1 420 220 L420 800 Z"/>
            <g clip-path="url(#field)">
              <!-- the comet: a head and three streaks of tail -->
              <path class="comet__tail" d="M188 506 C240 470 300 420 384 300 C320 390 262 440 206 490 Z"/>
              <path class="comet__tail comet__tail--thin" d="M176 494 C210 440 250 380 300 300 C270 370 236 420 196 486 Z"/>
              <path class="comet__tail comet__tail--thin" d="M200 520 C260 500 320 470 388 420 C330 480 270 512 214 530 Z"/>
              <path class="comet__head" d="M190 478 C194 500 202 508 224 512 C202 516 194 524 190 546 C186 524 178 516 156 512 C178 508 186 500 190 478 Z"/>
              <path class="comet__core" d="M190 496 C192 506 196 510 206 512 C196 514 192 518 190 528 C188 518 184 514 174 512 C184 510 188 506 190 496 Z"/>
              <!-- the orbit rings drawn round the bumpers -->
              <ellipse class="orbit" cx="204" cy="282" rx="118" ry="78"/>
              <ellipse class="orbit orbit--dash" cx="204" cy="282" rx="150" ry="104"/>
              <!-- a few stars, drawn as four-point sparkles -->
              <g class="stars">
                <path d="M300 520 l3 -9 l3 9 l9 3 l-9 3 l-3 9 l-3 -9 l-9 -3 Z"/>
                <path d="M120 560 l2 -6 l2 6 l6 2 l-6 2 l-2 6 l-2 -6 l-6 -2 Z"/>
                <path d="M330 130 l2 -6 l2 6 l6 2 l-6 2 l-2 6 l-2 -6 l-6 -2 Z"/>
                <path d="M150 150 l2 -7 l2 7 l7 2 l-7 2 l-2 7 l-2 -7 l-7 -2 Z"/>
                <path d="M250 610 l2 -6 l2 6 l6 2 l-6 2 l-2 6 l-2 -6 l-6 -2 Z"/>
                <path d="M78 600 l1.6 -5 l1.6 5 l5 1.6 l-5 1.6 l-1.6 5 l-1.6 -5 l-5 -1.6 Z"/>
              </g>
              <text class="label" x="93" y="458" text-anchor="middle">ORBIT</text>
              <text class="label" x="204" y="408" text-anchor="middle">POP</text>
            </g>
            <!-- the apron at the bottom, with the drain between the flippers -->
            <path class="apron" d="M20 560 L121 672 L140 740 L158 800 L20 800 Z"/>
            <path class="apron" d="M388 560 L287 672 L268 740 L250 800 L388 800 Z"/>
            <text class="apron__name" x="72" y="770" text-anchor="middle">NIGHT</text>
            <text class="apron__name" x="334" y="770" text-anchor="middle">COMET</text>
          </g>

          <g data-walls>
            <path class="rail" d="M20 800 L20 220 A200 200 0 0 1 420 220 L420 792"/>
            <path class="rail rail--thin" d="M388 262 L388 800"/>
            <path class="rail rail--thin" d="M20 560 L121 672"/>
            <path class="rail rail--thin" d="M388 560 L287 672"/>
            <rect class="lane" x="390" y="262" width="28" height="550"/>
            <circle class="post" cx="68" cy="426" r="5"/>
            <circle class="post" cx="118" cy="426" r="5"/>
            <path class="lip" d="M72 408 L114 408"/>
            <path class="rail rail--thin" d="M388 800 L388 812 M420 792 L420 812"/>
            <rect class="lockbar" x="12" y="812" width="416" height="11" rx="4"/>
          </g>
          <g data-parts></g>
          <g data-ball-low></g>
          <g data-ramp></g>
          <g data-ball-high></g>
          <g data-pops></g>
        </svg>
      </div>
    </div>

    <p class="hint" data-hint>Click the left or right half to flip. Keys: Z and M, or the arrows.</p>
  </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.

39 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 flipper» da Animorio e adattala al mio sito

Cosa fa

Su un fondo blu notte c’è un flipper inventato, Night Comet, inclinato all’indietro in prospettiva: il campo blu con una cometa rosa, gli anelli d’orbita, tre respingenti rotondi rosa, verde acqua e ambra, cinque bersagli gialli lungo la parete sinistra con le lettere C O M E T accanto, una rampa di plastica trasparente che sale a sinistra, passa in alto e scende a destra, due fionde sopra i flipper e la corsia del lanciatore a destra. Sopra il tavolo c’è la testata col nome, il punteggio a sette cifre e una striscia per i messaggi. All’apertura il tavolo si posa, i respingenti spuntano con un rimbalzo, i bersagli si alzano e i flipper fanno uno scatto di prova. Poi la pallina d’acciaio compare nella corsia, il lanciatore si carica (la molla si schiaccia e trema) e la spara in alto: la pallina gira sull’arco, scende e da lì è fisica vera. Rotola giù per il piano inclinato, rimbalza sulle sponde, i respingenti la calciano via con un lampo che li riempie tutti di luce e un sobbalzo elastico, le fionde la ributtano con l’elastico che si tende; se colpisce un bersaglio, quello cade nel suo buco e la lettera accanto si accende. Se entra nella rampa abbastanza veloce, la scala diventando un po’ più grande (è più vicina a noi), con l’ombra che si stacca, e scende dall’altra parte; se è troppo lenta si ferma e torna indietro. Ogni punto fa rotolare le cifre del punteggio e sale dal punto colpito in piccolo. Con le cinque lettere accese arriva il bonus e i bersagli si rialzano. Da sola gioca un pilota: quando la pallina rotola su un flipper aspetta un punto scelto a caso e la ribatte; dopo diciotto secondi la lascia andare, la pallina cade nello scarico, il punteggio lampeggia e torna a zero rotolando, e il giro ricomincia. Un clic sulla metà sinistra o destra della pagina (o i tasti Z e M, o le frecce) alza il flipper di quel lato finché si tiene premuto, e il pilota si fa da parte.

Come funziona

Un tavolo in un SVG inclinato

Il tavolo è un SVG di 440 per 800 unità, e le stesse unità le usa la fisica: niente conversioni. L’inclinazione è solo CSS: il contenitore ha perspective, il piano dentro ha rotateX con l’origine sul bordo in basso, così la parte alta si allontana. I clic non hanno bisogno di sapere dove cade la pallina sullo schermo: conta solo se sono a sinistra o a destra della metà della pagina.

La fisica a passi fissi

La pallina avanza a passi di 1/480 di secondo, quanti ne stanno nel tempo del fotogramma (requestAnimationFrame, con un accumulatore). A ogni passo la gravità aumenta la velocità verso il basso, poi la pallina si sposta e si controllano gli urti: segmenti (sponde, fionde, bersagli, l’arco fatto di quaranta pezzi), cerchi (respingenti e paletti) e i flipper. Per ognuno si cerca il punto più vicino: se è più vicino del raggio, la pallina si rimette fuori e la parte della velocità che va contro la superficie si rovescia, smorzata. Coi passi così piccoli la pallina non attraversa mai una sponda.

I flipper che colpiscono

Un flipper è un segmento con le punte rotonde, più grosso al perno. Si alza e si abbassa a velocità fissa verso il suo angolo, e la sua velocità angolare dà la velocità del punto che tocca la pallina (perpendicolare al raggio, proporzionale alla distanza dal perno): il rimbalzo si calcola rispetto a quel punto che si muove. Per questo la pallina colpita vicino alla punta parte più forte e in una direzione diversa da quella colpita vicino al perno. I respingenti invece garantiscono una velocità minima in uscita, e le fionde aggiungono una spinta lungo il loro lato.

La rampa e i bersagli

La rampa è una curva di quattro Bézier, campionata e misurata una volta. Quando la pallina entra nella bocca andando verso l’alto, lascia il piano e si muove lungo la curva: la sua velocità cala in salita e cresce in discesa secondo l’altezza della rampa in quel punto, come una pallina vera. Se si ferma prima della cima torna indietro e esce dalla bocca. Mentre è sulla rampa è disegnata in un altro strato, sopra la plastica, più grande e con l’ombra spostata. Un bersaglio colpito abbastanza forte smette di contare negli urti; quando sono giù tutti e cinque si rialzano dopo un attimo, se la pallina non è lì davanti.

Il pilota, il punteggio e il giro che torna uguale

Il pilota guarda dove la pallina è lungo il flipper e scatta quando arriva al punto scelto a caso (o vicino alla punta), tiene alzato un quinto di secondo e poi aspetta. Il caso viene da un generatore con il seme: lo stesso seme dà la stessa partita, quindi il primo giro e il secondo sono identici e il video dell’anteprima si chiude da solo. Il punteggio sono sette colonne di cifre da 0 a 9 più uno 0: GSAP porta ogni colonna al suo numero intero (le centinaia di 12.300 sono 123), e lo spostamento mostrato è quel numero modulo 10, così le cifre rotolano passando per tutte quelle in mezzo e il riporto gira da solo.

Valori da cambiare

NomeFileDi partenzaCosa cambia
GRAVITYscript.js1Quanto è ripido il tavolo: 0.6 è lento e leggero, 1.6 veloce e pesante.
LAUNCHscript.js1Quanto forte il lanciatore spara la pallina in alto.
BUMPERscript.js1Quanto forte calciano i respingenti e le fionde: 0.2 appena, 2 il doppio.
FLIPPERscript.js1Quanto veloci, e quindi quanto forti, scattano i flipper.
ROUNDscript.js18Quanti secondi gioca il pilota automatico prima di lasciar cadere la pallina e ricominciare.
TILTscript.js26Quanto il tavolo è inclinato all’indietro, in gradi (0 = visto dritto dall’alto).

Provali nel Playground

Quando usarla

Per una pagina di gioco o di un locale con i flipper, per un evento a tema arcade, una pagina 404 da giocare, la schermata d’attesa di un’app, il sito di uno studio che vuole mostrare la fisica nel browser. Il modello di urti (segmenti, cerchi, flipper che si muovono) serve anche per altri giochi da tavolo in SVG.

Sul telefono

Lo stesso tavolo e la stessa fisica, con le misure adattate: il tavolo prende tutta l’altezza libera sotto la testata e i caratteri si stringono. Un tocco sulla metà sinistra o destra dello schermo alza il flipper di quel lato, e due dita li alzano insieme.

Con il movimento ridotto

La pallina non viaggia: il tavolo compare in dissolvenza e ogni due secondi e mezzo la pallina sparisce e ricompare in un punto nuovo (un respingente che si accende, i bersagli giù con le lettere accese, la rampa), col punteggio già aggiornato. I flipper si alzano al clic senza movimento.

Trappole

  • Il tavolo inclinato con rotateX e l’entrata con GSAP (che sposta e dissolve) stavano sullo stesso elemento: il transform in linea di GSAP cancellava la rotazione del CSS. L’entrata muove il contenitore, la rotazione sta sul figlio.
  • Il fondo della discesa laterale finiva proprio sul perno del flipper: la pallina si fermava nell’incavo fra i due e il giro non finiva mai. La discesa ora finisce un poco sopra il flipper e la pallina ci scivola sopra.
  • Il primo banco di bersagli, obliquo in mezzo al campo, con una sponda che lo univa alla parete faceva una V in cui la pallina scesa lungo il muro restava ferma. I bersagli ora stanno sulla parete stessa, che fa da fondo quando cadono.
  • Una pallina ferma per più di un secondo e mezzo fuori dalla corsia riceve una spintarella: senza, un incastro raro bloccava la demo per sempre.
  • Con un caso vero ogni partita è diversa e il video dell’anteprima non trova mai un giro che torna uguale: i primi due giri usano lo stesso seme e la fisica avanza a passi fissi, quindi si ripetono identici; dal terzo il seme è nuovo.
  • Il video dell’anteprima si ferma quando non ci sono animazioni GSAP in programma, ma la fisica corre su requestAnimationFrame: a ogni pallina parte un tween vuoto lungo, che tiene la regia aperta fino al giro dopo.

Librerie

GSAP 3.15.0, Unbounded (font variabile) 5.3.0.

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