
La barra che diventa isola
Navigazione, Fisica, Scroll, SVG, Transizioni
NuovaGratis
Scorri dentro l’anteprima
L’indice di un articolo come nei migliori siti di documentazione: accanto alle voci corre un filo che segue la struttura dei titoli e rientra con una curva morbida per ogni sottotitolo, e il suo tratto acceso copre esattamente la parte di pagina sullo schermo, con le due estremità su molle. Una voce premuta fa scivolare la pagina fin lì; sul telefono l’indice diventa una barra con la sezione in corso.
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 table of contents rail</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/schibsted-grotesk@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="layout" data-layout>
<!-- the table of contents: on a wide screen a column on the right that stays put, on a phone a bar at the top
that opens it. The rail beside the entries is an SVG path drawn from where the entries are; its lit stretch
covers the sections on screen -->
<aside class="toc" data-toc>
<button class="toc__bar" type="button" aria-expanded="false" aria-controls="toc-panel" data-bar>
<svg class="toc__ring" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="9" pathLength="1" data-ring/></svg>
<span class="toc__bar-words"><span class="toc__bar-label">On this page</span><span class="toc__bar-now" data-now>Overview</span></span>
<svg class="toc__chevron" viewBox="0 0 16 16" aria-hidden="true"><path d="M4 6l4 4 4-4"/></svg>
</button>
<div class="toc__panel" id="toc-panel" data-panel>
<p class="toc__title" id="toc-title">On this page</p>
<nav class="toc__nav" aria-labelledby="toc-title">
<svg class="rail" aria-hidden="true" data-rail>
<path class="rail__track" data-track/>
<path class="rail__read" data-read/>
<path class="rail__ghost" data-ghost/>
<path class="rail__halo" data-halo/>
<path class="rail__lit" data-lit/>
<circle class="rail__head" r="3.5" data-head/>
</svg>
<ol class="toc__list" data-list>
<li><a href="#overview" data-depth="2">Overview</a></li>
<li><a href="#how-signing-works" data-depth="2">How signing works</a></li>
<li><a href="#the-signature-header" data-depth="3">The signature header</a></li>
<li><a href="#rotating-the-secret" data-depth="3">Rotating the secret</a></li>
<li><a href="#two-secrets-at-once" data-depth="4">Two secrets at once</a></li>
<li><a href="#verify-a-request" data-depth="2">Verify a request</a></li>
<li><a href="#with-the-sdk" data-depth="3">With the SDK</a></li>
<li><a href="#by-hand" data-depth="3">By hand</a></li>
<li><a href="#retries-and-replays" data-depth="2">Retries and replays</a></li>
<li><a href="#the-retry-schedule" data-depth="3">The retry schedule</a></li>
<li><a href="#rejecting-old-events" data-depth="3">Rejecting old events</a></li>
<li><a href="#test-locally" data-depth="2">Test locally</a></li>
<li><a href="#going-live" data-depth="2">Going live</a></li>
</ol>
</nav>
<div class="toc__foot">
<span class="toc__left" data-left>3 min read</span>
<button class="toc__up" type="button" data-up>
<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 13V3M4 7l4-4 4 4"/></svg>
Back to top
</button>
</div>
</div>
</aside>
<!-- the article it indexes: plain headings and short paragraphs, only there to be read and scrolled -->
<main class="doc" data-doc>
<h2 id="overview" tabindex="-1">Overview</h2>
<p>A webhook endpoint is a public URL. Anyone who finds it can send it a request that looks exactly like a real event, and if your code acts on it, a stranger can mark orders as paid or cancel bookings.</p>
<p>A signature on every event closes that door: your code repeats the sender’s computation and acts only when the two results match.</p>
<h2 id="how-signing-works" tabindex="-1">How signing works</h2>
<p>Each endpoint has its own signing secret, shown once when the endpoint is created. The secret never travels with the events: only what it produces does.</p>
<p>A signature covers the moment the event was sent and its body, so a request captured on the way cannot be replayed hours later.</p>
<h3 id="the-signature-header" tabindex="-1">The signature header</h3>
<p>Every event carries a header with a timestamp and one or more signatures, separated by commas. Each signature is an HMAC-SHA256 of the timestamp, a full stop and the raw body.</p>
<h3 id="rotating-the-secret" tabindex="-1">Rotating the secret</h3>
<p>Rotate a secret when someone who knew it leaves the team, when it may have been logged by accident, or simply once a year, and choose how long the old one keeps working.</p>
<h4 id="two-secrets-at-once" tabindex="-1">Two secrets at once</h4>
<p>While both secrets are valid, every event is signed with each of them. Code that accepts any of the signatures keeps working through the change, without a single rejected event.</p>
<h2 id="verify-a-request" tabindex="-1">Verify a request</h2>
<p>Verification comes before anything else in your handler: before parsing, before logging the body, before touching the database. Anything that fails gets an error and no further work.</p>
<h3 id="with-the-sdk" tabindex="-1">With the SDK</h3>
<p>The official libraries do the whole check in one call, including the tolerance on the timestamp and the secrets in rotation, and throw an error when it fails.</p>
<h3 id="by-hand" tabindex="-1">By hand</h3>
<p>Without a library the check is short enough to write yourself. Compare the signatures in constant time, and check every one in the header, not just the first.</p>
<h2 id="retries-and-replays" tabindex="-1">Retries and replays</h2>
<p>An event counts as delivered when your endpoint answers with a success status within ten seconds. Anything else, a timeout included, is a failure, and the event is sent again later.</p>
<h3 id="the-retry-schedule" tabindex="-1">The retry schedule</h3>
<p>Failed events are tried again seven times over about a day and a half, waiting longer each time. Each new attempt is signed again with a fresh timestamp.</p>
<h3 id="rejecting-old-events" tabindex="-1">Rejecting old events</h3>
<p>Reject events whose timestamp is more than five minutes away from your server’s clock: a request recorded on the way is then useless almost as soon as it is captured.</p>
<h2 id="test-locally" tabindex="-1">Test locally</h2>
<p>The command line tool forwards real, signed events to a URL on your own machine, with a temporary secret for the session, so a failed check shows up at once.</p>
<h2 id="going-live" tabindex="-1">Going live</h2>
<p>Before switching to live mode, make sure the raw body is verified first, the live secret sits in your secret manager, old events are rejected and slow work goes to a queue.</p>
<p>From then on your endpoint acts only on events that are genuine.</p>
</main>
</div>
<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.
61 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 «L’indice della pagina» da Animorio e adattala al mio sitoOgni voce ha un livello (data-depth) e da quello una x: INDENT pixel in più per ogni livello. Le posizioni vere delle voci (offsetTop e offsetHeight) danno, per ogni voce, dove comincia e dove finisce. Il filo è una funzione dell’altezza: a ogni y c’è una sola x, quella della voce, e fra due voci di livello diverso la x passa dall’una all’altra con una curva smoothstep alta BEND pixel, centrata sulla riga che le divide. Il tracciato SVG è fatto di punti presi da questa funzione: le estremità, e nove punti lungo ogni curva.
Ogni sezione dell’articolo va dal suo titolo al titolo dopo, e l’ultima fino al suo ultimo paragrafo. La finestra (sotto la barra, sul telefono) si traduce in due altezze sul filo: della prima sezione visibile si prende la frazione già passata sopra il bordo alto, dell’ultima quella arrivata al bordo basso, e le si posa sulle loro voci. Il tratto acceso è un secondo tracciato, preso dalla stessa funzione fra quelle due altezze: segue le curve da solo.
Le due estremità del tratto non saltano: ognuna è un numero con una velocità, tirato verso la sua meta da una molla (SPRING) e frenato. L’estremità verso cui si va usa la molla piena, l’altra una molla più morbida (TRAIL) con il freno in proporzione, così non oscilla: in un salto lungo il tratto si allunga e poi si raccoglie. Il passo è limitato a 1/30 di secondo e il tracciato si riscrive solo se una delle due altezze è cambiata.
Una voce premuta porta la pagina al suo titolo (meno lo scroll-margin-top, che sul telefono lascia il posto alla barra) con un tween di GSAP su un numero che a ogni aggiornamento chiama scrollTo: la durata cresce con la distanza fino a GLIDE secondi. La rotella, un dito o i tasti di scorrimento fermano il viaggio. All’arrivo il titolo prende il focus (ha tabindex=-1), l’indirizzo prende il suo #, e il colore verde sfuma via.
Sotto i 900 pixel l’indice diventa una barra appiccicata in cima allo schermo: un anello SVG riempito con stroke-dashoffset dalla frazione letta, e il nome della sezione in corso che rotola su o giù. Premuta, la lista si apre con un clip-path che scende e le voci che arrivano una dopo l’altra; il filo si rimisura perché ora le voci sono più grandi. Una voce scelta chiude la lista e fa scivolare la pagina.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
INDENT | script.js | 12 | Di quanti pixel rientra il filo per ogni livello di titolo. |
BEND | script.js | 14 | L’altezza di ogni curva del filo, in pixel. |
SPRING | script.js | [210, 24] | Le due estremità del tratto acceso: la forza della loro molla e il freno. |
TRAIL | script.js | 0.35 | Quanto è più morbida la molla dell’estremità che segue: più basso, il tratto si allunga di più nei salti. |
GLIDE | script.js | 1.1 | Il tempo più lungo che la pagina impiega a scivolare fino a una sezione, in secondi. |
READ | script.js | 230 | Le parole lette in un minuto, per i minuti che restano. |
HALO | script.js | true | Un alone tenue attorno al tratto acceso. |
Per documentazione, guide, articoli lunghi, termini di servizio: ogni pagina con titoli e sottotitoli in cui chi legge vuole sapere dove si trova e saltare a un punto. Con meno di quattro titoli non serve.
Sotto i 900 pixel l’indice diventa una barra appiccicata in cima allo schermo, con un anello di quanto si è letto e il nome della sezione in corso; il tocco apre l’elenco col suo filo, una voce toccata chiude e porta lì, un tocco fuori chiude. L’articolo va su una colonna larga quanto lo schermo, e niente sfora di lato.
Il tratto acceso segue lo scorrimento senza molle, una voce porta subito alla sezione senza scivolare, il nome nella barra cambia senza rotolare e l’elenco del telefono si apre in dissolvenza.
GSAP 3.15.0, Schibsted Grotesk (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 10 KB; le librerie: GSAP 28 KB.
Provata il 4 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.