
Words that melt into each other
Text, Scroll, SVG
NewFree
Scroll inside the preview
An old rolled-up parchment with a wax seal: as you scroll the seal breaks, the two wooden rolls part and the map of an invented island unrolls. A little boat sails into the bay leaving a dashed red trail that draws itself, a pawn hops ashore and follows it past palms, cave and volcano, while a quill writes a note by hand at every stop and the compass rose turns. At the end the X draws itself and a chest jumps out of the ground, opens its lid and spills coins.
A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>La mappa del tesoro</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/caveat@5.3.0/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/standard.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<!-- the trip: a tall section with a still stage; scrolling unrolls the map and walks the trail -->
<section class="viaggio" data-viaggio>
<div class="palco" data-palco>
<header class="testa">
<h1 class="testa__titolo">
<span class="riga"><span data-riga>The map of</span></span>
<span class="riga"><span data-riga><em>Marrow Isle</em></span></span>
</h1>
<p class="testa__cenno" data-cenno>
<span>Scroll to unroll</span>
<svg viewBox="0 0 24 32" aria-hidden="true"><path d="M12 3V27M4 19L12 28L20 19" /></svg>
</p>
</header>
<div class="tavolo" data-tavolo>
<div class="mappa" data-mappa>
<div class="foglio" data-foglio>
<svg class="carta" data-carta aria-label="A hand-drawn treasure map of an invented island" role="img"></svg>
</div>
<div class="rullo rullo--alto" data-rullo="alto"><div class="rullo__legno"></div></div>
<div class="rullo rullo--basso" data-rullo="basso"><div class="rullo__legno"></div></div>
<svg class="sigillo" data-sigillo viewBox="-40 -40 80 80" aria-hidden="true">
<g data-sigillo-sx>
<path class="sigillo__cera" d="M0 -30C14 -31 27 -20 29 -6C31 9 22 25 6 29L0 29L3 14L-3 2L4 -10L-2 -20Z" transform="translate(0 0)" />
</g>
<g data-sigillo-dx>
<path class="sigillo__cera" d="M0 -30C-14 -31 -27 -20 -29 -6C-31 9 -22 25 -6 29L0 29L3 14L-3 2L4 -10L-2 -20Z" />
</g>
<path class="sigillo__segno" d="M-11 -9L11 9M11 -9L-11 9" />
</svg>
</div>
</div>
</div>
</section>
<footer class="fine">
<p class="fine__frase">The chest is yours.<br><em>Fold the map for next time.</em></p>
</footer>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lenis@1.3.26/dist/lenis.min.js"></script>
<script src="script.js"></script>
</body>
</html>Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.
32 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The treasure map” from Animorio and fit it into my siteA section nine screens tall holding a sticky stage 100lvh tall: the title at the top, the table below. The script measures the table and picks the layout: wide (1000 × 640 units) when the space is wider than tall, tall (600 × 1000) otherwise, and gives the map the right size. The paper is a div with clip-path inset(50% 0% 50% 0%); the two rolls are divs placed with top at 50%, and the wood inside is centred by the CSS, so GSAP only moves the top.
Everything on the paper is SVG made by the script: the coastline is a smooth curve (Catmull-Rom turned into Béziers) through some twenty points given as shares of the map, and the same curve widened by 5 and 10% makes the sea lines around it. Palms, cave, volcano, chest, boat and pawn are small drawings at 0,0 inside a moved group and a scaled one, plus an inner group for the pointer. The tall layout puts the same island in a narrower, taller box.
The trail is dashed, so it cannot be drawn with its own stroke-dashoffset. It is seen through a mask: the same path, white and wide, with a dash L+2 long and a gap of L+12; with the stroke-dashoffset at L+2−t·L only the part up to t shows. The same number t puts the boat or the pawn at getPointAtLength(t·L), so the line always ends under them. The hops are the absolute value of a sine of t.
Every note wraps by itself according to how many letters fit on a line, and every line has a rectangle 0 wide in the clipPath. A tween takes a number from 0 to 1 and widens the rectangles one line after the other, along the length measured with getComputedTextLength; the quill sits on the tip with a small wave up and down, and shows only while it writes. Each note’s time depends on its length and on WRITE_SPEED.
A single paused timeline tied to the scroll with ScrollTrigger and scrub, from the start to the end of the section: seal, unrolling with back.out, rhumb lines and rose, boat, anchor, pawn with elastic.out, the stops with their effects (palms on elastic, coconut on bounce, bats and smoke with keyframes), the X, the chest with back.out and an elastic squash, the lid with elastic.out around its hinge, the coins in an arc with bounce.out. The rose turns from start to end with a tween as long as the timeline.
| Name | File | Default | What it changes |
|---|---|---|---|
UNROLL | script.js | 1 | How much scroll the parchment needs to unroll: 0.5 quick, 2 slow. |
COMPASS_TURNS | script.js | 2 | How many turns the compass rose makes during the whole trip. |
WALK_HOPS | script.js | 26 | How many little hops the pawn makes along the whole trail. |
WRITE_SPEED | script.js | 1 | How quickly the notes write themselves as you scroll: 0.5 slow, 2 quick. |
COINS | script.js | 9 | How many coins jump out of the chest. |
SCRUB | script.js | 0.8 | How many seconds the map takes to catch up with the scroll: 0 follows it at once. |
NOTES | script.js | sea, bay, palms, cave, volcano, x | The handwritten notes at every stop; they wrap by themselves. |
--rosso | style.css | #b23a22 | The red of the trail, the X, the pawn and the seal. |
To tell a route as a treasure hunt: the stops of a trip or a hike, an adventure park, a board game, a sailing school, an app’s onboarding, an advent calendar, the steps towards a prize or a surprise at the end.
The same animation with the map standing upright: the island stretches into a taller box, the notes wrap more often and sit in the sea above and below the island, the drawings are a little smaller. A tap on a place makes it react like the pointer.
No unrolling, no trip and no smooth scrolling: the section is one screen tall, the map is already open with the trail drawn, all the notes written, the boat at anchor and the chest open with its coins, and it fades in together with the title.
GSAP 3.15.0, Lenis 1.3.26, Fraunces (font variabile) 5.3.0, Caveat (font variabile) 5.3.0, Mona Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 14 KB; the libraries: GSAP + ScrollTrigger 45 KB, Lenis 5.3 KB.
Tested on 10 October 2026
Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.