Skip to content
animorio
IT
Back to the library

The trail of heights

Scroll, SVG, TextGSAP, CSS onlyMediumCompressed weight: Demo 9.1 KBGSAP + ScrollTrigger 45 KBFreeDownload the zip

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.

The code

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>

Playground

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

Or ask Claude Code for it

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 site

What it does

The “how to get here” page of a made-up mountain hut, Vellmar Hut, on a warm white with black ink and a single vermilion kept for the end. The screen stops: on the left a ruler of heights draws itself from the bottom, its ticks dropping in one after the other (one every 20 metres, a longer one with its height every 100), and on the right the way still to walk appears, a light dashed line climbing in switchbacks. A black mark opens on the ruler, the big height comes in digit after digit and the first stop, Tellow Bridge, lands on its height. Then, as you scroll, the ink climbs the trail, switchback after switchback, and the whole drawing slides down so the tip stays at the same height on the screen: the ruler runs under the still mark, the ticks already passed turn black and the ones near the tip lean out in a small wave. The big height counts every metre, narrow and thin on the way up (Archivo’s width and weight axes), its first digits clicking as they change, and it lands wide and heavy on an elastic at every stop. At every stop the ticks feel the knock and shiver, the name drops onto its height one letter after another, each letter going from hairline to full weight, with a pixel of bounce and a small squash, and a line reaches from the trail back to the ruler with the height written small. When the climb goes on, the line of the stop left behind goes light. At the last stop, the hut at 2,846 metres, the big height, its line, the small height and the mark on the ruler light up in vermilion. Everything follows the scroll, forwards and backwards.

How it works

The stops from the page

Every 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.

Numbers instead of properties

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.

A still tip, a world sliding down

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 counting height

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.

The name taking on weight

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.

Values to change

NameFileDefaultWhat it changes
NARROWscript.js66The width of the big height on the way up (62 is the narrowest).
WIDEscript.js104The width it lands on at every stop (125 is the widest).
THINscript.js230The weight of the big height on the way up.
HEAVYscript.js680The weight the big height and the names of the stops land on.
LEGSscript.js4How many legs of switchback between two stops (an even number).
WAVEscript.js1.4How much the ticks near the tip lean out.
LANDscript.js'back.out(1.6)'The curve of the letters landing: the number is how much they bounce.
SCRUBscript.js0.8How many seconds the drawing takes to catch up with the scroll.

Try them in the Playground

When to use it

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.

On phones

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.

With reduced motion

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.

Pitfalls

  • The “metres above the sea” line under the big height was written in the HTML and showed on its own, on an empty screen, before the digits came in: now its opacity follows the height coming in.
  • With a coloured header band, the ruler heights rising under it were cut in half. The drawing sits in a window with a fading mask-image: under the header everything fades away instead of being cut.
  • With a ruler only as long as the trail, its end showed in the middle of the screen at the start and at the end. Now it goes on 500 metres below the first stop and 500 above the hut.
  • With too many pixels per metre only one stop showed at a time and the sense of the climb was lost: with a tighter scale you see the stop just left behind and the switchbacks up to the next one.
  • With many fromTo on the same variables (--wd, --wg, the knock) and on the letters, the timeline uses immediateRender: false on every tween and the letters are hidden by hand first: otherwise the last tween built imposes its start from the very first frame.

Libraries

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.

Testing

Tested on 16 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

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.

All animations