Skip to content
animorio
IT
Back to the library

The year on a drum

Scroll, Text, 3DGSAP, CSS onlyMediumCompressed weight: Demo 6.9 KBGSAP + ScrollTrigger 45 KBFreeDownload the zip

Scroll inside the preview

A festival’s programme, one month at a time: the twelve months sit on a drum that turns in 3D as you scroll. The month in the window is wide and heavy, the others fold away on the curve and grow narrow, thin and pale; beside it, a single line says what happens that month. 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 year on a drum</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the programme of a made-up music festival, Ondo, a month at a time. The twelve months sit on a drum that turns
       in 3D as you scroll: the month in the window is wide and heavy, the others fold away on the curve, narrower and
       lighter. Beside the window one line says what happens that month -->
  <main>
    <section class="anno" data-anno>
      <div class="palco">
        <header class="testa">
          <p class="marchio">Ondo</p>
          <p class="piccolo">Festival programme 2027</p>
        </header>

        <!-- the window: two hairlines across the page, the month in the middle reads between them -->
        <div class="finestra" data-finestra aria-hidden="true">
          <i class="filo filo--su" data-filo></i>
          <i class="filo filo--giu" data-filo></i>
          <i class="indice" data-indice></i>
        </div>

        <div class="tamburo" data-tamburo>
          <ul class="mesi" aria-label="Months">
            <li class="mese" data-mese>January</li>
            <li class="mese" data-mese>February</li>
            <li class="mese" data-mese>March</li>
            <li class="mese" data-mese>April</li>
            <li class="mese" data-mese>May</li>
            <li class="mese" data-mese>June</li>
            <li class="mese" data-mese>July</li>
            <li class="mese" data-mese>August</li>
            <li class="mese" data-mese>September</li>
            <li class="mese" data-mese>October</li>
            <li class="mese" data-mese>November</li>
            <li class="mese" data-mese>December</li>
          </ul>
        </div>

        <!-- one line per month, in the same order; only the one of the month in the window shows -->
        <div class="programma" data-programma aria-live="polite">
          <p class="voce" data-voce><span class="giorni">17–18</span> Night listening in the old glasshouse</p>
          <p class="voce" data-voce><span class="giorni">7</span> A piano on the frozen lake, no lights</p>
          <p class="voce" data-voce><span class="giorni">14–16</span> Opening weekend on the river</p>
          <p class="voce" data-voce><span class="giorni">25</span> Choirs from the four valleys</p>
          <p class="voce" data-voce><span class="giorni">9–10</span> Field recordings at dawn</p>
          <p class="voce" data-voce><span class="giorni">21</span> The longest day, twelve hours of drums</p>
          <p class="voce" data-voce><span class="giorni">4–6</span> Main stage in the open air</p>
          <p class="voce" data-voce><span class="giorni">15</span> Boats, strings and fireworks</p>
          <p class="voce" data-voce><span class="giorni">12–13</span> An electronic weekend in the quarry</p>
          <p class="voce" data-voce><span class="giorni">18</span> Brass bands through the old town</p>
          <p class="voce" data-voce><span class="giorni">8</span> A quiet hour in the library</p>
          <p class="voce" data-voce><span class="giorni">20</span> Closing night, the whole year in one set</p>
        </div>
      </div>
    </section>

    <section class="coda">
      <p class="coda__titolo">Twelve months<br>on the river.</p>
      <p class="piccolo">One ticket for the whole year.</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.

55 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 year on a drum” from Animorio and fit it into my site

What it does

The year’s programme of a made-up music festival, Ondo, on a warm white with black ink and a single vermilion. On arrival two hairlines draw themselves across the page and make a window, and the drum of months rises from below until January settles between the two lines. Then the screen stays still and, as you scroll, the drum turns: the month in the window is big, wide and black, the ones above and below fold away on the curve as on a real cylinder, and the further they go the narrower, lighter and paler they get, until they vanish at the edge. The drum is not glued to the scroll: a spring pulls it, so it has a little weight, catches up and settles on the month a hair past it. When you stop scrolling it rests on the nearest month. Beside the window a single line gives the month’s programme, with the days in vermilion: when the month changes, the letters of the old line roll out one after the other the way the drum turns and the new ones roll in from the other side. Every time a month passes the centre the two lines of the window take the knock and the vermilion mark on the left springs. Everything follows the scroll, forwards and backwards.

How it works

The drum from a single number

The whole drum is drawn from one number, pos: 2 is March, 2.5 is halfway from March to April. For each month the angle is (pos − i) × STEP degrees; the month gets translateZ(−radius) rotateX(angle) translateZ(radius), so it turns on the surface of a cylinder behind the page. Past 90 degrees it is on the back and hides.

The right radius

The longest month is measured on an invisible copy already as wide and bold as in the window, and the type size is the one that fits it in its column. A month is one row tall; the radius is row ÷ STEP in radians, which puts the next month exactly one row further along the curve.

Width and weight from the curve

Anybody is a variable typeface with two axes: width (50 to 150) and weight (100 to 900). For each month the sine of the angle says how far up the cylinder it is, from 0 in the window to 1 at the edge, and with it the month goes from WIDE to NARROW, from BOLD to THIN and from solid to FAINT, written in font-variation-settings on every frame.

The spring and the snap

A timeline with scrub takes a number from 0 to the last month as you scroll. The drum does not take it as it is: in gsap.ticker a spring (stiffness SPRING, damping DAMPING below 1) chases it in small steps, so it goes a hair past the month and comes back. ScrollTrigger’s snap, with inertia and directional turned off, rests the scroll on the nearest month.

The line of the month

Every line of the programme is split into words that do not break and letters that move, inside a window with overflow hidden. When the month in the centre changes, the old letters roll out with yPercent the way the drum turns, one after the other, and the new ones roll in from the other side with a back.out that takes them a pixel past. The knock on the window’s lines is an elastic.out as strong as the drum’s speed.

Values to change

NameFileDefaultWhat it changes
STEPscript.js24The degrees between one month and the next on the drum: fewer degrees, more months in view and a bigger drum.
WIDEscript.js128The width of the month in the window (Anybody goes from 50 to 150).
NARROWscript.js56The width of the months at the edge of the drum.
BOLDscript.js780The weight of the month in the window.
THINscript.js120The weight at the edge of the drum.
FAINTscript.js0.08How much of a month still shows at the edge, from 0 to 1.
SPRINGscript.js160How hard the spring pulls the drum towards the scroll: higher is quicker.
DAMPINGscript.js0.68The damping of the spring: below 1 the drum goes a hair past the month and comes back, at 1 it settles without passing it.
SNAPscript.jstrueWhether, when you stop scrolling, the drum rests on the nearest month.

Try them in the Playground

When to use it

For the programme of a festival, a theatre season, a museum or a venue: twelve months, or twelve dates, told one at a time, with a line for each. It also works for the stops of a tour or the courses of a school, with short words in place of the months.

On phones

The same, with the drum as wide as the screen, the type sized so that September fits whole and the programme line just under the drum instead of beside it.

With reduced motion

The drum does not turn: it shows the month of the scroll already at rest, and when the month changes the drum and the programme line swap with a cross-fade. No spring, no snap, no knocks on the window.

Pitfalls

  • ScrollTrigger’s snap with a step snapTo takes speed and direction into account: after a jump in the scroll (a link, the autopilot, someone dragging the scrollbar) it ran to the last month or back to the first. With inertia: false and directional: false it rests on the month nearest to where you stopped.
  • The new letters of the line start a moment after the old ones begin to leave: starting together, with an exit in power2.in that is slow at first, for an instant the two lines sat one on top of the other.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Anybody (font variabile) 5.3.0.

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

Testing

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