
Il menu dalle tre righe
Menu, Transizioni, Fisica, Testo
NuovaGratis
Il campanello delle notifiche di un’app per fare musica insieme: la campanella nel pulsante, l’anteprima di una notifica appena arrivata e il pannello sono la stessa forma. Quando arriva una notifica la campanella suona, scende dal pulsante e si svasa in una pillola che dice chi ha scritto, poi torna campanella e il badge conta uno in più; premuta, si svasa come una gonna nel pannello. Lette, le righe gialle si spengono da sinistra e le lettere perdono peso proprio dove passa il bordo.
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, viewport-fit=cover">
<title>The flaring bell</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/recursive@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the notification bell of a music studio app. The white bell in the button, the short preview of a notification
that has just arrived and the panel are one and the same shape: script.js draws its outline at every frame
and every measure of it (the dome, the flare of the rim, the corners, the little knob on top) rides its own
spring, so the bell drops out of the button and flares like a skirt into the preview or into the panel, and
gathers back into a bell. The badge rides the bell's shoulder and lands in the panel's heading. -->
<div class="inbox" data-inbox>
<button class="bell" type="button" aria-expanded="false" aria-controls="inbox-panel" aria-label="Notifications, 2 unread" data-bell data-autoclic>
<svg class="bell__ghost" viewBox="0 0 56 56" aria-hidden="true"><path data-ghost/></svg>
</button>
<div class="sheet" data-sheet>
<p class="peek" aria-hidden="true" data-peek><span class="peek__face" data-peek-face></span><span class="peek__text" data-peek-text></span></p>
<section class="panel" id="inbox-panel" aria-label="Notifications" data-panel inert>
<header class="panel__head" data-head>
<h2 class="panel__title">Notifications</h2>
<span class="panel__slot" aria-hidden="true" data-slot></span>
<button class="panel__all" type="button" data-readall data-autoclic>
<svg class="panel__tick" viewBox="0 0 20 20" aria-hidden="true"><path d="M4.5 10.6l3.4 3.3 7.6-7.7" pathLength="1" data-tick/></svg>
<span data-readall-label>Mark all as read</span>
</button>
</header>
<ol class="notes" data-list>
<li class="note-item" data-unread>
<button class="note" type="button">
<span class="note__wash" aria-hidden="true"></span>
<span class="note__face face-2" aria-hidden="true">MH</span>
<span class="note__text">
<span class="note__line"><b>Mira Holm</b> mentioned you in <b>Harbour Lights</b></span>
<span class="note__said">“Could you take the bridge vocals tonight?”</span>
</span>
<span class="note__time">12m</span>
</button>
</li>
<li class="note-item" data-unread>
<button class="note" type="button">
<span class="note__wash" aria-hidden="true"></span>
<span class="note__face note__face--app" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M5 10.5v3M8.5 7v10M12 9v6M15.5 5v14M19 9.5v5"/></svg></span>
<span class="note__text">
<span class="note__line">Your mix of <b>Low Tide</b> is ready</span>
<span class="note__said">WAV · 48 kHz · 4 min 12 s</span>
</span>
<span class="note__time">40m</span>
</button>
</li>
<li class="note-item">
<button class="note" type="button">
<span class="note__wash" aria-hidden="true"></span>
<span class="note__face face-4" aria-hidden="true">KM</span>
<span class="note__text">
<span class="note__line"><b>Kofi Mensah</b> approved <b>Night Ferry</b></span>
<span class="note__said">“Sounds finished to me. Off to mastering.”</span>
</span>
<span class="note__time">3h</span>
</button>
</li>
<li class="note-item">
<button class="note" type="button">
<span class="note__wash" aria-hidden="true"></span>
<span class="note__face face-1" aria-hidden="true">IM</span>
<span class="note__text">
<span class="note__line"><b>Ines Moreau</b> invited you to <b>Salt Flats</b></span>
<span class="note__said">“Four songs, we start on Monday.”</span>
</span>
<span class="note__time">1d</span>
</button>
</li>
</ol>
</section>
</div>
<span class="badge" aria-hidden="true" data-badge><span class="badge__num" data-num><span></span></span><span class="badge__word" data-word>new</span></span>
<p class="sr" role="status" aria-live="polite" aria-atomic="true" 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>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.
73 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 «La campanella che si svasa» da Animorio e adattala al mio sitoLa campanella, la pillola e il pannello sono un solo tracciato, ridisegnato a ogni fotogramma: una cima che può essere una cupola o un bordo dritto con gli angoli tondi, due fianchi che sono una curva di Bézier cubica, un orlo, un pomolo e un batacchio. Coi fianchi dritti i punti di controllo stanno a un terzo e due terzi della corda; con la svasatura (fl = 1) il primo scende dritto dalla spalla e il secondo sta vicino all’orlo e verso l’interno, così il fianco si apre come quello di una campana. Il pomolo e il batacchio girano nello stesso verso del contorno, e con la regola nonzero si uniscono a lui.
Ogni misura del tracciato (dov’è la cima, dov’è il fondo, quanto sono larghe la cima e l’orlo, i due raggi degli angoli, la svasatura, il pomolo) è una molla smorzata con la sua rigidità e il suo smorzamento, x'' = −ω²(x − meta) − 2ζω·x', a passi di 1/240 di secondo e col passo del fotogramma limitato a 1/30. Aprendo il fondo e l’orlo sono veloci e rimbalzano (ζ viene da BOUNCE), la cima e la svasatura arrivano dopo: per un istante la forma è una campana alta, poi una gonna, poi il pannello. Chiudendo la cima si stringe per prima, così la campana si riforma mentre risale. Quando tutte le molle sono ferme il ciclo dorme.
Tutto il contenuto sta su un foglio bianco caldo più largo e più alto del pannello di ROOM pixel per parte, e il tracciato lo taglia con clip-path: path(). Così le parole stanno sempre dentro la forma, anche a metà strada, e la svasatura che va oltre il pannello ha spazio per vedersi. La campanella nel pulsante è il foglio stesso, tagliato a campana: nel pulsante c’è solo la sua impronta grigia, che compare quando la campana esce.
Lo squillo sono altre quattro molle poco smorzate (ζ intorno a 0,14) che ricevono una spinta: l’oscillazione intorno al pomolo, l’orlo che si allarga, la cupola che si schiaccia, e il batacchio, che è tirato dalla parte opposta all’oscillazione e resta indietro. Valgono solo vicino al pulsante: un fattore che va a zero quando la cima si allontana, e appena la forma esce il loro smorzamento sale a 0,95. Poi la forma va alla pillola, larga quanto il suo testo misurato, e dopo PEEK secondi torna campanella; quando atterra il badge conta uno in più.
Il badge ha due molle per la posizione: a pannello chiuso il suo posto è la spalla della campanella, girata con l’oscillazione; aperto, il posto tenuto per lui accanto al titolo, letto dalle misure della pagina. Mentre scende l’anello nero che lo stacca dal pulsante si assottiglia, e si apre la parola new. Le cifre rullano: la vecchia esce in alto e la nuova entra dal basso con back.out quando il numero sale, al contrario quando scende.
Il giallo di una riga ha una maschera, linear-gradient(90deg, transparent var(--f), #000 calc(var(--f) + 80px)), e --f corre da sinistra a destra in READ secondi. Le parole sono divise in lettere, e ogni lettera prende il suo peso da quanto il bordo l’ha già passata, con lo stesso smoothstep: da 560 a 420, e da 780 a 640 nei nomi. Recursive tiene ogni lettera larga uguale a ogni peso, quindi le righe non si riformano mentre cambiano. Il badge conta uno in meno quando il bordo è a un terzo della riga; Mark all as read fa partire le righe a STAGGER secondi una dall’altra.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
FIRST | script.js | 0.6 | I secondi prima che arrivi la prima notifica. |
EVERY | script.js | 7 | I secondi fra una notifica e la successiva. |
PEEK | script.js | 1.8 | I secondi in cui la pillola mostra una notifica nuova prima che la campanella la prenda. |
SPEED | script.js | 1 | Quanto è veloce la forma: 1 come è disegnata, 2 il doppio. |
BOUNCE | script.js | 0.5 | Quanto la forma va oltre mentre si svasa: 0 per niente, 1 tanto. |
RING | script.js | 1 | Quanto forte suona la campanella quando arriva una notifica: 0 per niente. |
READ | script.js | 0.6 | I secondi che la lettura impiega a passare lungo una riga. |
STAGGER | script.js | 0.11 | I secondi fra una riga e la successiva quando si segnano tutte come lette. |
MAX_ROWS | script.js | 5 | Quante notifiche tiene al massimo il pannello. |
INCOMING | script.js | sei, da Tomás Rey left a note on Low Tide a Night Ferry is mastered | Le notifiche che arrivano, a turno: chi la manda (vuoto per l’app stessa), che cosa è successo (fra *asterischi* un titolo in grassetto) e che cosa ha detto. |
Per il campanello delle notifiche di un’app o di una dashboard, in alto nella barra: un posto che si guarda spesso, dove una notifica nuova deve farsi notare senza fermare chi lavora e dove si vuole sapere chi ha scritto prima di aprire. Sta bene con poche notifiche alla volta, menzioni, risposte, file pronti; per i messaggi che confermano un’azione appena fatta ci sono la notifica a nastro e le notifiche a pila.
Il pannello prende la larghezza dello schermo meno 32 pixel (358 a 390) e la pillola non va oltre; il pulsante resta di 56 pixel. Col dito un tocco apre e chiude, un tocco su una riga la legge e un tocco fuori chiude il pannello. La svasatura che va oltre il bordo dello schermo per un istante resta tagliata e la pagina non scorre di lato.
La forma non viaggia e non si svasa: la campanella svanisce e al suo posto compare il pannello (o la pillola), e chiudendo il pannello svanisce con le sue parole e torna la campanella. La campanella non suona; il badge svanisce, cambia posto e ricompare, e le cifre si dissolvono invece di rullare. Leggendo, il giallo svanisce e le lettere cambiano peso tutte insieme, senza spostarsi.
GSAP 3.15.0, Recursive (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 14 KB; le librerie: GSAP 28 KB.
Provata il 6 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.