
L’indicatore a lancetta
Contatori, Fisica, SVG
NuovaGratis
Quante palline di gelato su un cono: col più una pallina cade dall’alto sulla pila, si schiaccia atterrando e rotola al centro di quella sotto, e la torre ondeggia sulle sue molle, più lenta quanto più è alta; col meno quella in cima si solleva e va via. Oltre il massimo la torre vacilla e torna su, sotto il minimo l’ultima pallina non si stacca dal cono.
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 cone stepper</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/opsz.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- how many scoops on a gelato cone: a card with the cone and, under it, a stepper. Every scoop added drops
onto the stack and squashes, and the tower sways on its springs; pushed past the most scoops it teeters,
and the last scoop will not come off. The scoops are drawn by the script -->
<div class="cone-card" data-card>
<svg class="scene" viewBox="0 0 340 300" aria-hidden="true" data-scene>
<defs>
<!-- one scoop, 60 wide, centred on its middle: a dome with a ruffled skirt where the scoop was turned -->
<path id="gelato-scoop" d="M-30 7C-31.5-13-17.5-29 0-29C17.5-29 31.5-13 30 7C30.8 9.5 32 12.5 30.6 15.6Q26.2 21.5 21.9 17.2Q17.5 23 13.1 16.4Q8.7 22 4.4 17.6Q0 23.4-4.4 16.8Q-8.7 22.2-13.1 17.4Q-17.5 23-21.9 16.6Q-26.2 21.6-30.6 15.6C-32 12.5-30.8 9.5-30 7Z"/>
<clipPath id="gelato-in-scoop"><use href="#gelato-scoop"/></clipPath>
<radialGradient id="gelato-round" cx="0.38" cy="0.3" r="0.78">
<stop offset="0" stop-color="#ffffff" stop-opacity="0.34"/>
<stop offset="0.34" stop-color="#ffffff" stop-opacity="0"/>
<stop offset="0.68" stop-color="#3c140a" stop-opacity="0"/>
<stop offset="1" stop-color="#3c140a" stop-opacity="0.26"/>
</radialGradient>
<linearGradient id="gelato-ruffle" x1="0" y1="0" x2="0" y2="1">
<stop offset="0.7" stop-color="#3c140a" stop-opacity="0"/>
<stop offset="0.75" stop-color="#3c140a" stop-opacity="0.09"/>
<stop offset="1" stop-color="#3c140a" stop-opacity="0.2"/>
</linearGradient>
<radialGradient id="gelato-contact">
<stop offset="0" stop-color="#3c140a" stop-opacity="0.34"/>
<stop offset="1" stop-color="#3c140a" stop-opacity="0"/>
</radialGradient>
<linearGradient id="gelato-wafer" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" class="wafer-light"/>
<stop offset="0.45" class="wafer-mid"/>
<stop offset="1" class="wafer-dark"/>
</linearGradient>
<radialGradient id="gelato-floor">
<stop offset="0" class="floor-shade" stop-opacity="0.3"/>
<stop offset="1" class="floor-shade" stop-opacity="0"/>
</radialGradient>
<clipPath id="gelato-in-cone"><path d="M-27.5 3H27.5L3.4 84.5Q0 90-3.4 84.5Z"/></clipPath>
<!-- the very top of the scene fades out, so a scoop dropped onto a tall stack comes in softly -->
<linearGradient id="gelato-fade" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#ffffff" stop-opacity="0"/>
<stop offset="0.1" stop-color="#ffffff" stop-opacity="1"/>
</linearGradient>
<mask id="gelato-top" maskUnits="userSpaceOnUse" x="0" y="0" width="340" height="300">
<rect width="340" height="300" fill="url(#gelato-fade)"/>
</mask>
</defs>
<g mask="url(#gelato-top)">
<!-- the world: the cone's rim at 0 0, the floor 100 below; the script scales it to fit the most scoops -->
<g data-world>
<ellipse class="floor" cx="0" cy="100" rx="30" ry="5" fill="url(#gelato-floor)" data-floor/>
<g data-cone>
<ellipse class="cone__mouth" cx="0" cy="-2.5" rx="28" ry="3.6"/>
<path class="cone__body" d="M-27.5 3H27.5L3.4 84.5Q0 90-3.4 84.5Z" fill="url(#gelato-wafer)"/>
<g class="cone__grid" clip-path="url(#gelato-in-cone)" data-grid></g>
<path class="cone__rim" d="M-30-2.5C-20-4.8 20-4.8 30-2.5L30.4 4.5C20 8.2-20 8.2-30.4 4.5Z"/>
<path class="cone__rim-edge" d="M-30.4 4.5C-20 8.2 20 8.2 30.4 4.5"/>
<path class="cone__rim-light" d="M-28-2C-18-4.2 18-4.2 28-2"/>
<ellipse class="cone__contact" cx="0" cy="3" rx="27" ry="6" fill="url(#gelato-contact)" data-cone-contact/>
</g>
<g data-scoops></g>
<g data-flying></g>
</g>
</g>
</svg>
<div class="order">
<div class="order__label">
<span class="order__name" id="scoops-name">Scoops</span>
<span class="order__note" id="scoops-note"><span class="order__note-in" data-note>€1.90 each</span></span>
</div>
<div class="stepper">
<button class="stepper__btn" type="button" aria-label="Remove one scoop" data-less>
<span class="stepper__disc" aria-hidden="true">
<svg viewBox="0 0 24 24"><path d="M6.5 12h11"/></svg>
</span>
</button>
<input class="stepper__value" type="text" inputmode="numeric" autocomplete="off" spellcheck="false" maxlength="2" role="spinbutton" aria-labelledby="scoops-name" aria-describedby="scoops-note" aria-valuemin="1" aria-valuemax="4" aria-valuenow="3" aria-valuetext="3 scoops" value="3" data-value>
<button class="stepper__btn" type="button" aria-label="Add one scoop" data-more data-autoclic>
<span class="stepper__disc" aria-hidden="true">
<svg viewBox="0 0 24 24"><path d="M6.5 12h11M12 6.5v11"/></svg>
</span>
</button>
</div>
</div>
<p class="sr" aria-live="polite" data-said></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>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.
41 valori da cambiare
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 contatore del cono» da Animorio e adattala al mio sitoLa pallina è un solo path in un riquadro largo 60: una cupola e sotto una gonna con sette lobi, la parte arricciata dove la paletta l’ha girata. Ogni pallina lo riusa con <use> e ci mette sopra il suo gusto (una variabile CSS), i pezzetti sparsi sempre allo stesso modo da un generatore con il seme, due sfumature (luce in alto a sinistra, ombra sul bordo e sulla gonna), il segno della paletta e l’ombra di quella sopra, tagliata dalla forma stessa con un clipPath in coordinate locali. Il cono ha la griglia di cialda in due famiglie di righe inclinate, ognuna con il suo filo di luce.
Ogni pallina sta su quella sotto in un giunto: un angolo su una molla, uno spostamento dal centro che rotola indietro a zero e un’altezza che si schiaccia (1 = tonda). A ogni fotogramma la torre si ricostruisce dal cono in su: il punto d’appoggio, il centro (altezza per schiacciamento), il punto che offre alla pallina sopra. Lo schiacciamento è ancorato al punto d’appoggio, così una pallina schiacciata abbassa tutte quelle sopra e la botta corre lungo la pila.
Ogni giunto è tirato di lato dal seno dell’inclinazione di tutte le palline sopra di lui: una torre alta è più morbida e più lenta di una bassa. Il carico accoppia tutti i giunti, e il modo più morbido in cui si piegano insieme è 1 / (4 sin²(π / (4n + 2))) volte più morbido di un giunto solo (8,3 volte con quattro palline): la spinta del peso resta ai due terzi di quella soglia, così anche la torre più alta torna sempre su.
Un giunto che accelera spinge i vicini dall’altra parte, come l’inerzia di una catena: le accelerazioni si trovano risolvendo una matrice delle masse tridiagonale e simmetrica (1 sulla diagonale, WHIP accanto) con l’algoritmo di Thomas. Simmetrica vuol dire che lo scambio fra i giunti non aggiunge mai energia: la cima resta indietro rispetto alla base e la frusta si spegne. Tutto è integrato con Euler semi-implicito in passi di 1/240 di secondo, con il passo del fotogramma limitato a 1/30.
Una pallina nuova parte appena sopra la scheda con la velocità THROW e cade con GRAVITY, guidata verso la cima della pila ma mai proprio al centro. Quando il suo centro arriva all’altezza giusta sopra il punto d’appoggio diventa parte della torre tenendo esattamente il posto che aveva: lo spostamento dal centro viene dalla distanza di lato, l’angolo dall’inclinazione della pila, lo schiacciamento dalla distanza in verticale. Poi riceve la botta: lo schiacciamento, una parte alle palline sotto, il cono che cede, e una spinta ai giunti dal lato in cui è atterrata. Con clic veloci ogni pallina parte sopra la precedente ancora in volo, e un meno manda in su prima quella più alta che sta cadendo.
Oltre il massimo ogni giunto riceve una velocità verso sinistra, un po’ di più salendo, perché la cima si pieghi di circa TEETER gradi, e le palline scivolano una sull’altra; spinte ripetute aggiungono sempre meno e due fermi morbidi (su ogni giunto e sull’inclinazione di ogni pallina) non la lasciano mai cadere. Sotto il minimo una timeline GSAP tira su l’ultima pallina di 9 pixel e la lascia ricadere. Un pulsante tenuto premuto ripete sempre più in fretta (HOLD); il numero è un campo con role="spinbutton" e aria-valuenow, risponde alle frecce, a Home e a Fine, e prende la cifra scritta dovunque fosse il cursore; una regione aria-live dice il numero a clic finiti e sempre i limiti.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
MIN | script.js | 1 | Il numero più piccolo di palline (0 lascia il cono vuoto). |
MAX | script.js | 4 | Il numero più grande di palline, fino a 7: oltre 4 il cono si rimpicciolisce per farle stare. |
START | script.js | 3 | Le palline quando si apre la pagina. |
THROW | script.js | 600 | La velocità con cui una pallina entra dall’alto della scheda, in pixel al secondo. |
GRAVITY | script.js | 2400 | Quanto accelera una pallina che cade, in pixel al secondo per secondo. |
SQUASH | script.js | 0.2 | Quanto si schiaccia una pallina atterrando (0 = per niente). |
SWAY | script.js | [100, 0.3] | Le molle della torre: quanto sono dure e quanto sono frenate (1 = niente ondeggiamento). |
TEETER | script.js | 17 | Di quanti gradi si piega la torre spinta oltre il massimo. |
HOLD | script.js | [0.42, 0.16, 0.06] | Tenendo premuto un pulsante: l’attesa prima che ripeta, il primo intervallo e il più corto, in secondi. |
WORD | script.js | ['scoop', 'scoops'] | La parola letta dopo il numero, per una e per più. |
Per scegliere quante cose dove la quantità si può far vedere: palline, porzioni, fette, piani di una torta, libri su una pila, pacchi in una spedizione. Sta bene in un ordine da asporto o in un configuratore di prodotto, dove il limite è vero (un cono non regge più di tanto) e conviene che si senta: la torre che vacilla lo dice prima della scritta.
Su un telefono la scheda sta in 390 pixel con tutto quello che ha, i pulsanti sono dischi da 48 pixel. Il dito fa come il mouse: un tocco conta subito, tenuto premuto ripete sempre più in fretta e oltre il massimo tiene la torre piegata; la pressione lunga non apre menu e due tocchi veloci non ingrandiscono la pagina. Toccando il numero si apre la tastiera numerica.
Le palline non cadono, non si schiacciano e la torre non ondeggia: una pallina aggiunta compare al suo posto con una dissolvenza e una tolta svanisce dove sta. Oltre i limiti la torre resta ferma e cambia solo la nota sotto l’etichetta, che sfuma invece di scorrere; i pulsanti non si rimpiccioliscono premuti.
GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 15 KB; le librerie: GSAP 28 KB.
Provata il 7 ottobre 2026
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.
Con l’email e la password del tuo account.
oppure con l’email
Hai fatto l’accesso come .
Con l’account scarichi lo zip di ogni animazione e di ogni pacchetto, gratis.