Skip to content
animorio
IT
Back to the library

Stars along the trail

Scroll, SVGGSAPMediumCompressed weight: Demo 5.7 KBGSAP + ScrollTrigger + CustomEase + MotionPath 58 KBFreeDownload the zip

Scroll inside the preview

A studio’s “how we work” page: as you scroll, a little train of shapes runs down an invisible trail that winds between the steps, bunched up at first and then strung out along the whole way. Over each step the bars are its weeks of work, and a kite hops across them and back.

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>Stars along the trail</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/index.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/ibm-plex-mono@5.3.0/400.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the "how we work" page of a small studio: as you scroll, a little train of shapes runs down an invisible trail
       that winds between the steps, and over each step a small kite hops along the bars of its weeks -->
  <header class="apertura">
    <p class="apertura__marchio">Paper Kite</p>
    <h1 class="apertura__titolo">How we work</h1>
    <p class="apertura__sotto">Five steps, from the first call to the day after launch.</p>
  </header>

  <section class="percorso" data-percorso>
    <svg class="sentiero" data-sentiero aria-hidden="true" focusable="false">
      <defs>
        <symbol id="forma-stella" viewBox="-10 -10 20 20"><path d="M0 -10C1.2 -2.5 2.5 -1.2 10 0C2.5 1.2 1.2 2.5 0 10C-1.2 2.5 -2.5 1.2 -10 0C-2.5 -1.2 -1.2 -2.5 0 -10Z"/></symbol>
        <symbol id="forma-fiore" viewBox="-10 -10 20 20"><circle cx="0.00" cy="-4.90" r="4.3"/><circle cx="4.66" cy="-1.51" r="4.3"/><circle cx="2.88" cy="3.96" r="4.3"/><circle cx="-2.88" cy="3.96" r="4.3"/><circle cx="-4.66" cy="-1.51" r="4.3"/><circle r="3.4"/></symbol>
        <symbol id="forma-anello" viewBox="-10 -10 20 20"><path d="M0 -9A9 9 0 1 1 0 9A9 9 0 1 1 0 -9ZM0 -4.5A4.5 4.5 0 1 0 0 4.5A4.5 4.5 0 1 0 0 -4.5Z" fill-rule="evenodd"/></symbol>
        <symbol id="forma-aquilone" viewBox="-10 -10 20 20"><path d="M0 -10L7 -1.5L0 10L-7 -1.5Z"/></symbol>
        <symbol id="forma-goccia" viewBox="-10 -10 20 20"><path d="M0 -10C4 -4 7.5 -0.5 7.5 3A7.5 7.5 0 0 1 -7.5 3C-7.5 -0.5 -4 -4 0 -10Z"/></symbol>
      </defs>
      <path class="sentiero__linea" data-linea d="M0 0"/>
      <g data-forme></g>
    </svg>

    <ol class="passi">
      <li class="passo passo--sinistra" data-passo data-lato="sinistra">
        <div class="settimane" data-settimane aria-hidden="true">
          <svg class="aquilone" data-aquilone viewBox="-12 -16 24 32"><path d="M0 -15L11 -2L0 15L-11 -2Z"/><path d="M-11 -2H11M0 -15V15" class="aquilone__croce"/></svg>
          <span class="stanghetta" data-stanghetta></span>
        </div>
        <h2 class="passo__titolo">First call</h2>
        <p class="passo__durata">1 week</p>
        <p class="passo__testo">We listen, ask a lot of questions and write down what the project has to do.</p>
      </li>
      <li class="passo passo--destra" data-passo data-lato="destra">
        <div class="settimane" data-settimane aria-hidden="true">
          <svg class="aquilone" data-aquilone viewBox="-12 -16 24 32"><path d="M0 -15L11 -2L0 15L-11 -2Z"/><path d="M-11 -2H11M0 -15V15" class="aquilone__croce"/></svg>
          <span class="stanghetta" data-stanghetta></span><span class="stanghetta" data-stanghetta></span>
        </div>
        <h2 class="passo__titolo">Sketches</h2>
        <p class="passo__durata">2 weeks</p>
        <p class="passo__testo">Rough ideas on paper and in the browser, until one of them feels right.</p>
      </li>
      <li class="passo passo--sinistra" data-passo data-lato="sinistra">
        <div class="settimane" data-settimane aria-hidden="true">
          <svg class="aquilone" data-aquilone viewBox="-12 -16 24 32"><path d="M0 -15L11 -2L0 15L-11 -2Z"/><path d="M-11 -2H11M0 -15V15" class="aquilone__croce"/></svg>
          <span class="stanghetta" data-stanghetta></span><span class="stanghetta" data-stanghetta></span><span class="stanghetta" data-stanghetta></span>
        </div>
        <h2 class="passo__titolo">Design</h2>
        <p class="passo__durata">3 weeks</p>
        <p class="passo__testo">Every screen drawn properly, with a prototype you can click through.</p>
      </li>
      <li class="passo passo--destra" data-passo data-lato="destra">
        <div class="settimane" data-settimane aria-hidden="true">
          <svg class="aquilone" data-aquilone viewBox="-12 -16 24 32"><path d="M0 -15L11 -2L0 15L-11 -2Z"/><path d="M-11 -2H11M0 -15V15" class="aquilone__croce"/></svg>
          <span class="stanghetta" data-stanghetta></span><span class="stanghetta" data-stanghetta></span><span class="stanghetta" data-stanghetta></span><span class="stanghetta" data-stanghetta></span>
        </div>
        <h2 class="passo__titolo">Build</h2>
        <p class="passo__durata">4 weeks</p>
        <p class="passo__testo">The real thing, written and tested on the phones and computers people use.</p>
      </li>
      <li class="passo passo--sinistra" data-passo data-lato="sinistra">
        <div class="settimane" data-settimane aria-hidden="true">
          <svg class="aquilone" data-aquilone viewBox="-12 -16 24 32"><path d="M0 -15L11 -2L0 15L-11 -2Z"/><path d="M-11 -2H11M0 -15V15" class="aquilone__croce"/></svg>
          <span class="stanghetta" data-stanghetta></span><span class="stanghetta" data-stanghetta></span>
        </div>
        <h2 class="passo__titolo">Looking after it</h2>
        <p class="passo__durata">2 weeks</p>
        <p class="passo__testo">Launch day, then fixes and small changes for as long as you need them.</p>
      </li>
    </ol>
  </section>

  <footer class="chiusura">
    <p class="chiusura__frase">Let’s fly something together.</p>
  </footer>

  <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/gsap@3.15.0/dist/MotionPathPlugin.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/CustomEase.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.

45 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 “Stars along the trail” from Animorio and fit it into my site

What it does

The page of a made-up studio, Paper Kite, on the palest pink: a huge title, «How we work», and under it five steps, one on the left and the next on the right, from the first call to what happens after launch. Each step has its name, how many weeks it lasts and two lines of text, and over the name a row of purple bars, one per week. On every row a small pink kite hops from bar to bar to the last one and then back, rests a moment and starts again; on the one-week step it sits still. When the section reaches the middle of the screen, a train of twenty-four coloured shapes sets off from the top of the trail, little stars, flowers, rings, kites and drops: they come down spinning along a curve that always passes on the side opposite the step, the first in front and the others behind, one at a time, so at first they are bunched in a heap and by the end they are strung out along the whole way. Scrolling moves them forwards and back: scroll up and they go back up too.

How it works

The trail

The script takes a point at the top of the section, in the middle, one next to every step on the side opposite its words, moved SWING of the width from the middle, and one at the bottom. Then it joins them with a smooth curve: every piece sets off in the direction from the point before to the point after, divided by six. The path is never drawn; it is rebuilt when the page changes size.

One number for all of them

ScrollTrigger takes a number from 0 to 1 while the section scrolls from TRAIL[0] to TRAIL[1], tied to the scroll. Shape i sits at the point of the trail given by that number minus i/COUNT, kept between 0 and 0.999: the first is always ahead, the last only sets off once the number passes 23 twenty-fourths. MotionPathPlugin.getPositionOnPath says where that point falls.

The shapes

They are five SVG symbols, each used in turn by a use element: little star, flower, ring, kite and drop, with colours taken from the style sheet. Every shape turns SPIN degrees over the whole trip, in proportion to where it is.

The kite on the weeks

The script measures the centre of every bar and makes a timeline that repeats forever, with a rest of HOP_PAUSE seconds at the end: for every bar a sideways tween of HOP[0] seconds and, at the same moment, one up of HOP[1] and one down of HOP[2]. The row is crossed to the last bar and then back to the first. The curve is a CustomEase made from the four numbers in EASE.

Bars as data

The bars do not count the steps: they are each step’s weeks of work, and the number is written next to them. A one-week step has a single bar and the kite sits still on it.

Values to change

NameFileDefaultWhat it changes
COUNTscript.js24How many shapes travel on the trail (24 on the site).
SIZEscript.js[26, 20]Their size in pixels, on a computer and on a phone.
TRAILscript.js['20% 50%', '80% 35%']Where the trip starts and ends: a point of the section meets a point of the screen (the site’s).
SPINscript.js540How many degrees each shape turns on its trip.
SWINGscript.js0.26How far from the middle the trail swings, as a share of the width.
HOPscript.js[0.8, 0.28, 0.36]The kite’s hop in seconds: sideways, up and down (the site’s).
HOP_HEIGHTscript.js[8, 20]How high the kite sits over the bars and how high it jumps, in pixels.
HOP_PAUSEscript.js0.35The rest at the end of every round trip.
EASEscript.js[0.22, 1, 0.36, 1]The curve of the hop, as in a cubic-bezier.

Try them in the Playground

When to use it

For a page that tells a method, a journey or the stages of a project: the train walks the reader from one step to the next, and the bars say how long each thing takes without needing a chart.

On phones

The same, with the steps one under the other: the trail swings from one side of the screen to the other, passing behind the words, and the shapes are a little smaller.

With reduced motion

No trip and no hops: the shapes fade in already strung out along the whole trail, and the kites sit still on the first bar.

Pitfalls

  • GSAP does not read curves written the CSS way: a string «cubic-bezier(0.22,1,0.36,1)» passed as an ease gives no error, but turns into power1.out. To really get that curve you need CustomEase.
  • Two grid columns put two steps on the same row: every step gets its own row, otherwise the trail has no room to swing from side to side.
  • The trail depends on where the steps are, which depends on the fonts: it has to be drawn once the fonts are loaded and again whenever ScrollTrigger measures the page.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, MotionPath (GSAP) 3.15.0, CustomEase (GSAP) 3.15.0, Bricolage Grotesque (font variabile) 5.3.0, IBM Plex Mono 5.3.0.

Compressed with gzip, the three demo files weigh 5.7 KB; the libraries: GSAP + ScrollTrigger + CustomEase + MotionPath 58 KB.

Testing

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