
La stanza delle carte
3D, Transizioni, Immagini
Gratis
La pagina è una cartina stradale stampata: al clic si stacca dal tavolo e si piega davvero in sei riquadri, le due colonne laterali a fisarmonica e poi a metà. Il pacchetto salta, si gira in aria e si riapre riquadro dopo riquadro sulla pagina stampata sul retro. Il clic dopo la ripiega e torna indietro.
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 road map fold</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/standard.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage" data-stage>
<!-- the desk under the page: you only see it while the map is folded up -->
<div class="desk" aria-hidden="true">
<svg class="desk__lines" data-desk viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid slice"></svg>
</div>
<div class="shadow" data-shadow aria-hidden="true"></div>
<!-- the sheet that folds: three columns and two rows of panels, hinged to each other.
The middle column holds the other two; every column holds its top and bottom panel.
The panels are filled with copies of the two pages when a fold starts (page A on the front, page B on the back). -->
<div class="rig" data-rig aria-hidden="true">
<div class="col col--m" data-col="1">
<div class="cell cell--top" data-cell data-c="1" data-r="0"></div>
<div class="cell cell--bot" data-cell data-c="1" data-r="1"></div>
<div class="col col--l" data-col="0">
<div class="cell cell--top" data-cell data-c="0" data-r="0"></div>
<div class="cell cell--bot" data-cell data-c="0" data-r="1"></div>
</div>
<div class="col col--r" data-col="2">
<div class="cell cell--top" data-cell data-c="2" data-r="0"></div>
<div class="cell cell--bot" data-cell data-c="2" data-r="1"></div>
</div>
</div>
</div>
<!-- the two real pages, the ones you read and click while the sheet lies flat -->
<div class="live" data-live>
<!-- page A: the home of a road trip guide -->
<section class="page page--a" data-page="a" aria-label="Byway, slow road trips">
<header class="bar">
<span class="brand">
<svg class="brand__mark" viewBox="0 0 32 32" aria-hidden="true">
<rect x="1" y="1" width="30" height="30" rx="9" class="brand__tile"/>
<path d="M11 30 C11 22 21 21 21 15 C21 9 12 9 13 2" class="brand__road"/>
<path d="M11 30 C11 22 21 21 21 15 C21 9 12 9 13 2" class="brand__dash"/>
</svg>
<span class="brand__name">Byway</span>
</span>
<nav class="links" aria-label="Byway">
<a href="#routes" class="link"><span class="link__plate" aria-hidden="true"></span><span class="link__text">Routes</span></a>
<a href="#stays" class="link"><span class="link__plate" aria-hidden="true"></span><span class="link__text">Stays</span></a>
<a href="#journal" class="link"><span class="link__plate" aria-hidden="true"></span><span class="link__text">Journal</span></a>
</nav>
<span class="bar__tag">Spring routes</span>
</header>
<div class="hero">
<div class="hero__text">
<p class="kicker">Slow road trips on the Northern Coast</p>
<h1 class="title">Take the <em>long way</em> round.</h1>
<p class="lede">Hand-drawn routes along the coast road, with the bakeries, lay-bys and empty beaches worth stopping for.</p>
<button class="cta" type="button" data-go data-autoclic>
<span class="cta__bg" aria-hidden="true"></span>
<span class="cta__label">Open the Coast Road</span>
<span class="cta__map" aria-hidden="true"><i></i><i></i><i></i></span>
</button>
<dl class="facts">
<div class="fact"><dt>Coast road</dt><dd>412 km</dd></div>
<div class="fact"><dt>Stops</dt><dd>7</dd></div>
<div class="fact"><dt>Days</dt><dd>6</dd></div>
</dl>
</div>
<figure class="mapcard" data-card>
<svg class="map" viewBox="0 0 600 500" preserveAspectRatio="xMidYMid meet" role="img" aria-label="Map of the Coast Road from Wren Harbour to Saltmere">
<rect x="-600" y="-400" width="1800" height="1300" class="map__sea"/>
<g class="map__waves">
<path d="M40 70 q10 -6 20 0 t20 0"/><path d="M96 128 q10 -6 20 0 t20 0"/><path d="M30 260 q10 -6 20 0 t20 0"/>
<path d="M60 352 q10 -6 20 0 t20 0"/><path d="M150 40 q10 -6 20 0 t20 0"/><path d="M22 440 q10 -6 20 0 t20 0"/>
</g>
<path d="M54 190 C40 172 66 156 86 166 C108 176 104 202 84 206 C70 210 62 200 54 190Z" class="map__land"/>
<path d="M262 0 C244 46 196 70 204 122 C212 170 158 196 166 248 C174 300 116 326 128 380 C138 424 100 452 108 500 C112 560 90 640 96 900 H1200 V-400 H300 C286 -260 276 -90 262 0Z" class="map__land"/>
<path d="M300 -400 C286 -260 276 -90 262 0 C244 46 196 70 204 122 C212 170 158 196 166 248 C174 300 116 326 128 380 C138 424 100 452 108 500 C112 560 90 640 96 900" class="map__beach"/>
<g class="map__hills">
<ellipse cx="476" cy="150" rx="92" ry="52"/><ellipse cx="482" cy="146" rx="62" ry="34"/><ellipse cx="488" cy="142" rx="32" ry="17"/>
<ellipse cx="452" cy="378" rx="78" ry="40"/><ellipse cx="458" cy="374" rx="46" ry="22"/>
</g>
<path d="M514 236 C530 222 560 226 566 244 C584 248 586 274 568 282 C560 300 528 298 518 284 C498 284 494 252 514 236Z" class="map__wood"/>
<path d="M346 456 C356 442 384 444 390 458 C402 462 400 482 386 484 C376 496 350 494 346 480 C332 478 334 460 346 456Z" class="map__wood"/>
<ellipse cx="384" cy="262" rx="30" ry="15" class="map__lake"/>
<path d="M332 22 C304 52 254 74 262 124 C270 174 214 198 224 250 C234 302 174 328 188 380 C198 420 168 446 186 484" class="map__road" data-road/>
<path d="M332 22 C304 52 254 74 262 124 C270 174 214 198 224 250 C234 302 174 328 188 380 C198 420 168 446 186 484" class="map__dash" data-road-dash/>
<g class="map__scale"><path d="M470 470 H550"/><path d="M470 465 V475 M550 465 V475 M510 467 V473"/><text x="510" y="460">20 km</text></g>
<g class="pin" data-pin data-at="0.04"><g class="pin__body"><path d="M0 0 C-7 -10 -11 -15 -11 -21 A11 11 0 1 1 11 -21 C11 -15 7 -10 0 0Z"/><circle cy="-21" r="4.2"/></g><text x="16" y="-14">Wren Harbour</text></g>
<g class="pin" data-pin data-at="0.35"><g class="pin__body"><path d="M0 0 C-7 -10 -11 -15 -11 -21 A11 11 0 1 1 11 -21 C11 -15 7 -10 0 0Z"/><circle cy="-21" r="4.2"/></g><text x="16" y="-14">Lantern Cliffs</text></g>
<g class="pin" data-pin data-at="0.66"><g class="pin__body"><path d="M0 0 C-7 -10 -11 -15 -11 -21 A11 11 0 1 1 11 -21 C11 -15 7 -10 0 0Z"/><circle cy="-21" r="4.2"/></g><text x="16" y="-14">Gull Bay</text></g>
<g class="pin" data-pin data-at="0.88"><g class="pin__body"><path d="M0 0 C-7 -10 -11 -15 -11 -21 A11 11 0 1 1 11 -21 C11 -15 7 -10 0 0Z"/><circle cy="-21" r="4.2"/></g><text x="16" y="-14">Saltmere</text></g>
<g class="car" data-car>
<g data-car-in>
<rect x="-12" y="-6.5" width="24" height="13" rx="4.5" class="car__body"/>
<rect x="2" y="-5" width="5.5" height="10" rx="1.6" class="car__glass"/>
<rect x="-9" y="-5" width="4" height="10" rx="1.4" class="car__glass"/>
</g>
</g>
</svg>
</figure>
</div>
<div class="creases" aria-hidden="true"><i class="crease crease--v1"></i><i class="crease crease--v2"></i><i class="crease crease--h"></i></div>
</section>
<!-- page B: the guide to one route, printed on the back of the same sheet -->
<section class="page page--b is-off" data-page="b" aria-label="The Coast Road">
<header class="bar">
<span class="brand">
<svg class="brand__mark" viewBox="0 0 32 32" aria-hidden="true">
<rect x="1" y="1" width="30" height="30" rx="9" class="brand__tile"/>
<path d="M11 30 C11 22 21 21 21 15 C21 9 12 9 13 2" class="brand__road"/>
<path d="M11 30 C11 22 21 21 21 15 C21 9 12 9 13 2" class="brand__dash"/>
</svg>
<span class="brand__name">Byway</span>
</span>
<button class="back" type="button" data-back data-autoclic>
<span class="back__bg" aria-hidden="true"></span>
<svg class="back__arrow" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 12 H5 M11 5 L4 12 L11 19"/></svg>
<span class="back__label">All routes</span>
</button>
</header>
<div class="route">
<div class="route__head">
<p class="kicker">Route guide, spring edition</p>
<h2 class="title">The Coast Road</h2>
<p class="lede">Six days from Wren Harbour to Saltmere, never more than a mile from the sea.</p>
<figure class="profile">
<svg class="profile__svg" viewBox="0 0 600 170" preserveAspectRatio="none" aria-hidden="true">
<path class="profile__area" data-area/>
<path class="profile__line" data-line/>
</svg>
<figcaption class="profile__cap">
<span>Wren Harbour</span>
<span class="profile__peak" data-peak>Highest point: Lantern Cliffs, 212 m</span>
<span>Saltmere</span>
</figcaption>
</figure>
</div>
<ol class="legs">
<li class="leg"><span class="leg__day">Monday</span><span class="leg__way">Wren Harbour<svg class="leg__arrow" viewBox="0 0 40 12" aria-hidden="true"><path d="M1 6 H37 M31 1.5 L37 6 L31 10.5"/></svg>Lantern Cliffs</span><span class="leg__km">64 km</span></li>
<li class="leg"><span class="leg__day">Tuesday</span><span class="leg__way">Lantern Cliffs<svg class="leg__arrow" viewBox="0 0 40 12" aria-hidden="true"><path d="M1 6 H37 M31 1.5 L37 6 L31 10.5"/></svg>Gull Bay</span><span class="leg__km">58 km</span></li>
<li class="leg"><span class="leg__day">Wednesday</span><span class="leg__way">Gull Bay<svg class="leg__arrow" viewBox="0 0 40 12" aria-hidden="true"><path d="M1 6 H37 M31 1.5 L37 6 L31 10.5"/></svg>Fennick</span><span class="leg__km">81 km</span></li>
<li class="leg"><span class="leg__day">Thursday</span><span class="leg__way">Fennick<svg class="leg__arrow" viewBox="0 0 40 12" aria-hidden="true"><path d="M1 6 H37 M31 1.5 L37 6 L31 10.5"/></svg>Old Ferry</span><span class="leg__km">72 km</span></li>
<li class="leg"><span class="leg__day">Friday</span><span class="leg__way">Old Ferry<svg class="leg__arrow" viewBox="0 0 40 12" aria-hidden="true"><path d="M1 6 H37 M31 1.5 L37 6 L31 10.5"/></svg>Marram Dunes</span><span class="leg__km">69 km</span></li>
<li class="leg"><span class="leg__day">Saturday</span><span class="leg__way">Marram Dunes<svg class="leg__arrow" viewBox="0 0 40 12" aria-hidden="true"><path d="M1 6 H37 M31 1.5 L37 6 L31 10.5"/></svg>Saltmere</span><span class="leg__km">68 km</span></li>
</ol>
</div>
<div class="creases" aria-hidden="true"><i class="crease crease--v1"></i><i class="crease crease--v2"></i><i class="crease crease--h"></i></div>
</section>
</div>
<p class="sr-only" aria-live="polite" data-say></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>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.
78 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 transizione a cartina stradale» da Animorio e adattala al mio sitoIl foglio è un contenitore con transform-style: preserve-3d. La colonna di mezzo è la base e tiene dentro le altre due: quella di sinistra ha transform-origin sul bordo destro, quella di destra sul bordo sinistro, così ruotando con rotateY si chiudono proprio lungo la piega. In ogni colonna il riquadro di sotto ha transform-origin sul bordo alto e si piega con rotateX. Ogni riquadro ha due facce con backface-visibility: hidden, il fronte e il retro girato di 180 gradi.
Le pagine vere stanno sopra il foglio e si usano normalmente. Quando parte la piega se ne fanno copie (cloneNode): ogni faccia tiene la pagina intera, larga e alta come lo schermo, spostata in modo da mostrare solo il suo pezzo. Il fronte mostra la pagina A, il retro la pagina B con le colonne scambiate (la colonna 0 mostra il pezzo 2), perché dopo il giro il foglio è visto da dietro. Nelle copie si tolgono data-autoclic e i ritocchi che arrivano dopo (strada, puntine, profilo).
Le pieghe arrivano a 180 gradi esatti, ma ogni cerniera gira intorno a una linea staccata dalla carta di mezzo spessore: translateZ, rotazione, translateZ al contrario. Così ogni strato atterra alla sua profondità e i riquadri non si toccano mai (niente sfarfallio). L'ordine degli strati è quello di una cartina vera, e la metà di sotto si piega in avanti o indietro secondo la pagina che se ne va, così le due facce del pacchetto mostrano sempre quella.
Scala, inclinazione, giro, torsione, salto e i tre angoli di piega stanno in un oggetto (st) che GSAP anima con una timeline: si alza (power3), si chiude (power2.inOut), salta e si gira, si riapre con back.out e si distende. A ogni aggiornamento una funzione scrive le trasformazioni e calcola la luce: la normale di ogni riquadro, girata come il riquadro, contro una lampada in alto a sinistra, dà l'ombra o il lucido sopra le due facce.
L'ombra è un elemento a parte sul tavolo, fuori dal 3D. La sua misura è l'impronta del foglio, calcolata dai coseni degli angoli (una colonna chiusa non conta più) e stretta dal coseno del giro, così di taglio è una riga. Più il foglio si alza o salta, più l'ombra si sposta, si sfoca e schiarisce. Arrivata la pagina nuova, il foglio sparisce e torna quella vera, identica, che fa partire i suoi ritocchi.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
FOLD | script.js | 0.6 | I secondi di ogni piega della cartina. |
SIZE | script.js | 0.66 | Quanto resta grande la cartina piegata in aria (1 = tutto lo schermo); sugli schermi alti un po' di più. |
TILT | script.js | 18 | Di quanti gradi la cartina piegata si inclina all'indietro. |
HOP | script.js | 1 | Quanto salta il pacchetto quando si gira (0 = si gira sul posto). |
BOUNCE | script.js | 1 | Quanto i riquadri vanno oltre e tornano indietro quando si riaprono. |
CREASE | script.js | 0.55 | Quanto si vedono le pieghe sulla pagina aperta (0 = niente). |
SPEED | script.js | 1 | La velocità di tutta la transizione: 2 è il doppio, 0.5 la metà. |
Per passare dalla home a una pagina di dettaglio in un sito di viaggi, di itinerari in auto o in bici, di un ufficio del turismo, di una casa editrice di guide e cartine; per un archivio di mappe, un evento all'aperto con il suo percorso, ogni volta che la pagina nuova è «il retro» di quella di prima.
La stessa piega con le misure adattate: le due pagine si mettono in colonna e il foglio piegato, che su uno schermo alto è una striscia sottile, resta in aria un po' più grande. Un tocco sul pulsante o sulla mappa la fa partire; gli hover (cartello, mappa che si apre, tappe) ci sono solo col mouse.
Niente si piega né si muove: la pagina compare in dissolvenza già completa, con la strada, le puntine e la macchinina al loro posto; al clic la pagina sfuma e compare quella nuova, anche lei già completa.
GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0, Instrument Sans (font variabile) 5.3.0.
Compressi con gzip, i tre file della demo pesano 14 KB; le librerie: GSAP 28 KB.
Provata il 13 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.