Skip to content
animorio
IT
Back to the library

The index that follows the reading

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

Scroll inside the preview

The index of a long story on a personal journal, in the minimal style: as you scroll, the chapter you are reading sits at the top, large and heavy, with a thin blue bookmark; once finished it shrinks, steps aside and goes down to the bottom among the ones already read, grey and narrow on the wdth axis, while the others climb one row each on a spring and the next one grows into its place. At the top the minutes left count down.

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 index that follows the reading</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the index of a long essay on a made-up personal journal. Scrolling, the chapter being read climbs to the top of
       the index and grows; when it is done it steps aside, shrinks, narrows and goes to the bottom with the chapters
       already read, while the next one rises in its place -->
  <main>
    <section class="apertura">
      <p class="piccolo">Odalo, a journal</p>
      <h1 class="titolo">A year<br>on foot.</h1>
      <p class="piccolo piccolo--tenue">Scroll to read along.</p>
    </section>

    <section class="racconto" data-racconto>
      <div class="palco" data-palco>
        <header class="testa">
          <p class="marchio">Odalo</p>
          <p class="piccolo piccolo--tenue"><span class="resto" data-resto>25</span> min left</p>
        </header>

        <nav class="indice" aria-label="Chapters" data-indice>
          <ol class="voci" data-voci></ol>
          <i class="filo filo--sopra" data-filo-sopra aria-hidden="true"></i>
          <i class="filo filo--letti" data-filo-letti aria-hidden="true"></i>
          <i class="nastro" data-nastro aria-hidden="true"></i>
        </nav>
      </div>
    </section>

    <section class="apertura apertura--fine">
      <h2 class="titolo titolo--medio">Thanks for<br>walking along.</h2>
    </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.

29 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 index that follows the reading” from Animorio and fit it into my site

What it does

A made-up personal journal, Odalo, on a warm white with black ink and a single ultramarine. After the opening (A year on foot) the screen stops on the story’s index: at the top the chapter being read, Leaving, large and in heavy black, with its reading time underneath and a bookmark on its left, a thin vertical blue line; under a thin grey hairline, the other four chapters in a row, smaller, each with its minutes aligned on the right. At the top right the minutes left, 25. As you scroll, at the end of every chapter the index reorders itself: the bookmark closes upwards, the chapter just read shrinks, steps aside on an arc and goes down to the bottom, turning grey and narrow (the typeface’s wdth axis goes from 100 to 76); meanwhile the others climb one row, one after the other, and settle going a hair too far; the next chapter rises to the top and grows with a small bounce, its minutes move under the title and the bookmark opens again beside it. The first time, a second hairline draws itself over the chapters already read and then follows them; when nothing is left to read it withdraws. The minutes at the top drop with every chapter passed. Everything follows the scroll, forwards and backwards.

How it works

Numbered places, not elements moving in the DOM

The chapters are absolute li elements inside a pinned stage (position: sticky, 100lvh tall) and never change order in the DOM. At chapter k every entry j sits in place (j − k + N) mod N: place 0 is the top, then the ones to read, then the read ones, set apart by a small gap. A function gives the y of every place, and the drawing only sets transform, font-size and font-variation-settings.

A single number tied to the scroll

The timeline, with scrub SCRUB, takes a number p from 0 to the number of chapters minus one. The whole part is the chapter being read, the rest is the change: for the first part (HOLD) the index stays still, for the rest every entry goes from its place to the place of the next chapter. Everything is computed from p, so scrolling back the index puts itself back in order.

Three choreographies in the same change

The chapter just read shrinks in the first half (power3.inOut), then goes down on an arc: x = sin(π·t) times a distance, so it passes beside the other entries, and it arrives last. The others climb one row with the SETTLE curve, each STAGGER later than the one above, and clear the place before it arrives. The next one rises and grows with the same curve: the top goes a hair too far and comes back.

Weight, width and grey

Instrument Sans is variable in weight (400–700) and width (75–100). The three kinds of entry each have their look (being read 640 and 100, to read 470 and 100, read 420 and 76 in grey) and during the change the values blend: the read entry narrows and greys as it goes down. The colour blends with gsap.utils.interpolate between the two CSS variables.

Bookmark, hairlines and minutes

The bookmark is a 2 pixel wide element scaled in height: it closes with power2.in and opens again with the SETTLE curve. The hairline over the read chapters draws itself with scaleX the first time, then sits halfway in the gap above the first read one. The minutes left take away each chapter’s minutes as you pass it.

Values to change

NameFileDefaultWhat it changes
CHAPTERSscript.js[['Leaving', 4], ['The coast road', 7], …]The chapters: title and minutes of reading.
BIGscript.js1How big the chapter being read is, compared to the page (0.6 to 1.4).
SETTLEscript.js'back.out(1.5)'The curve the chapters land in their rows with: the number in brackets is how far they overshoot.
STAGGERscript.js0.07How far apart the climbing entries leave, as a part of the change.
HOLDscript.js0.35The part of every chapter in which the index stays still, from 0 to 0.8.
SCRUBscript.js0.6How many seconds the index takes to catch up with the scroll.

Try them in the Playground

When to use it

For a long article, a story in chapters, a guide or a manual: beside the real text, as a pinned index that says where you are and how much is left. It works with three to seven chapters with short titles; with more the list no longer fits on a screen.

On phones

The same, with adapted measures: the index takes the whole width, the title at the top is smaller, the rows tighter and the arc of the chapter going down wider, to pass beside the other entries.

With reduced motion

No flights and no bounces: at the end of every chapter the index fades out and comes back already in its new order, with the bookmark beside the next chapter; the minutes still count.

Pitfalls

  • With all the climbing entries using the same interval, the last read one left too late and the chapter just read landed on top of it, two titles on the same row. The climbing entries finish earlier (within 60% of the change plus their delay) and the one going down arrives last.
  • When nothing is left to read, the hairline over the read chapters ended up a step from the one under the title and two parallel lines showed: in the last change it fades away.
  • The minutes change place (under the big title, on the right in the rows): moving them with the title made them fly diagonally over the other entries. They fade out halfway through the change and come back in the new place.
  • The stage must be measured again on every ScrollTrigger refresh and after the font has arrived: with the fallback font the big titles were wider.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Instrument Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 6.1 KB; the libraries: GSAP + ScrollTrigger 45 KB.

Testing

Tested on 19 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