
Words that melt into each other
Text, Scroll, SVG
NewFree
Scroll inside the preview
The way up to a mountain hut on a single thin line: as you scroll, the trail climbs in switchbacks, the ruler of heights runs under a still mark, the big height counts every metre and every stop lands on its own height letter by letter, taking on weight. At the last one, the height of the hut lights up in vermilion. Minimal style.
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>The trail of heights</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- the way up to a made-up mountain hut, drawn with a single thin line. Scrolling down, the trail climbs in
switchbacks, the ruler of heights runs down beside it, and every stop lands on its own height, taking on
weight; at the last one the height of the hut lights up -->
<main>
<section class="apertura">
<p class="piccolo">Vellmar Hut</p>
<h1 class="titolo">Four hours up,<br>one line.</h1>
<p class="piccolo piccolo--tenue">Scroll down</p>
</section>
<section class="salita" data-salita>
<div class="palco">
<header class="testa">
<p class="marchio">Vellmar</p>
<p class="piccolo piccolo--tenue">The summer path</p>
</header>
<div class="lettura" data-lettura aria-hidden="true">
<p class="quota" data-quota>1,240</p>
<p class="piccolo piccolo--tenue lettura__sotto">metres above the sea</p>
</div>
<div class="vista">
<div class="mondo" data-mondo>
<svg class="sentiero" data-sentiero aria-hidden="true">
<defs>
<clipPath id="sentiero-scopre"><rect data-scopre x="0" y="0" width="0" height="0"></rect></clipPath>
</defs>
<path class="sentiero__guida" data-guida clip-path="url(#sentiero-scopre)"></path>
<path class="sentiero__passi" data-passi></path>
</svg>
<div class="righello" data-righello aria-hidden="true"></div>
<ol class="tappe">
<li class="tappa" data-tappa data-metri="1240">
<i class="tappa__riga" aria-hidden="true"></i>
<span class="tappa__metri">1,240 m</span>
<span class="tappa__nome">Tellow Bridge</span>
</li>
<li class="tappa" data-tappa data-metri="1610">
<i class="tappa__riga" aria-hidden="true"></i>
<span class="tappa__metri">1,610 m</span>
<span class="tappa__nome">Larch Gate</span>
</li>
<li class="tappa" data-tappa data-metri="1985">
<i class="tappa__riga" aria-hidden="true"></i>
<span class="tappa__metri">1,985 m</span>
<span class="tappa__nome">The Shelves</span>
</li>
<li class="tappa" data-tappa data-metri="2390">
<i class="tappa__riga" aria-hidden="true"></i>
<span class="tappa__metri">2,390 m</span>
<span class="tappa__nome">Grey Saddle</span>
</li>
<li class="tappa" data-tappa data-metri="2846">
<i class="tappa__riga" aria-hidden="true"></i>
<span class="tappa__metri">2,846 m</span>
<span class="tappa__nome">Vellmar Hut</span>
</li>
</ol>
</div>
</div>
<i class="livello" data-livello aria-hidden="true"></i>
</div>
</section>
<section class="apertura apertura--fine">
<h2 class="titolo titolo--medio">Beds from June<br>to September.</h2>
<p class="piccolo piccolo--tenue">Twenty-two of them, and a stove.</p>
</section>
</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="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.
34 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 trail of heights” from Animorio and fit it into my siteEvery stop is an item of a list with data-metri and its name: the script reads them, sorts them and gets the lowest and the highest height. That gives the scale: a function turns a height into a position in the drawing, and everything (ticks, switchbacks, the lines of the stops) is placed with it. Between two stops the script makes up LEGS legs of switchback, a little uneven, with the stops always on the same side.
The timeline, tied to the scroll with scrub SCRUB, mostly moves numbers: the height reached, the knock on the ticks, the ruler coming in and, for every stop, its line, the small height and the line going light. On every update a single function redraws everything from those numbers: where the tip is along the switchbacks, how much of the line has been walked (stroke-dashoffset), where the whole drawing goes, how long the ticks are.
Ruler, trail and stops sit on one layer. On every frame the layer slides down by as much as it takes for the height reached to stay at the same height on the screen, where the black mark on the ruler is: so the ruler seems to run under the mark. The dashes of the way still to walk are a second path starting at the tip, with stroke-dashoffset equal to the way already walked so the dashes stay still.
The big figure is the height reached, rounded, with tabular digits that do not dance. Two CSS variables, --wd and --wg, are Archivo’s wdth and wght axes: at the start of every climb they drop to NARROW and THIN, on arrival they go back to WIDE and HEAVY on an elastic. Only the first digits click when they change: the last ones change every metre and, clicking, would shiver all the time.
Every letter of the name sits in its own box, with its weight in a --w variable. On arrival the letters drop from 20 pixels with a stagger, from transparent to solid and from weight 100 to HEAVY, along the LAND curve (a back.out that bounces by about a pixel); a second tween squashes them a touch and straightens them again. Then the line reaches from the trail to the ruler with scaleX and the small height rises into place.
| Name | File | Default | What it changes |
|---|---|---|---|
NARROW | script.js | 66 | The width of the big height on the way up (62 is the narrowest). |
WIDE | script.js | 104 | The width it lands on at every stop (125 is the widest). |
THIN | script.js | 230 | The weight of the big height on the way up. |
HEAVY | script.js | 680 | The weight the big height and the names of the stops land on. |
LEGS | script.js | 4 | How many legs of switchback between two stops (an even number). |
WAVE | script.js | 1.4 | How much the ticks near the tip lean out. |
LAND | script.js | 'back.out(1.6)' | The curve of the letters landing: the number is how much they bounce. |
SCRUB | script.js | 0.8 | How many seconds the drawing takes to catch up with the scroll. |
For the “how to get here” page of a mountain hut, a mountain hotel or a holiday home in the hills, for the route of a hike or an uphill race, or for any story made of stops with a number that grows. The stops are changed in the HTML (data-metri and the name): the scale and the switchbacks rebuild themselves. With more than five stops the section must be made longer.
The same animations: the ruler sits on the left edge, the switchbacks narrow into the right half with no sideways wobble, the big height is smaller and the drawing a little taller, so the ticks stay apart. The names of the stops are smaller and sit between the small height and the trail.
No movement: the ruler and the way ahead are already drawn. Scrolling steps from one stop to the next: the drawing and the big height fade out and come back already at the new stop, with the trail walked up to there and the stop written. At the last one the height of the hut is already vermilion.
GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Archivo (font variabile, assi wdth e wght) 5.3.0.
Compressed with gzip, the three demo files weigh 9.1 KB; the libraries: GSAP + ScrollTrigger 45 KB.
Tested on 16 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.