Skip to content
animorio
IT
Back to the library

The tear-off calendar

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

Scroll inside the preview

A pad of white sheets with thin outlines, one day per sheet with a big number in a variable typeface: as you scroll, the top sheet folds up from its corner, tears along the perforation from right to left and flies off upwards turning, while underneath the next day lands and takes its weight. The last day is in the accent. 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 tear-off calendar</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- a tear-off day pad: six thin sheets under an ink binding, one big day number each. Scrolling, the top sheet
       curls up from its corner, tears along the perforation from right to left and flies off turning; the next day
       lands under it and takes its weight. The last day, the opening, is printed in the accent -->
  <main>
    <section class="apertura">
      <p class="piccolo">Ostler Print Room</p>
      <h1 class="titolo">Six days,<br>one sheet at a time.</h1>
      <p class="piccolo piccolo--tenue">Tear them off. Scroll.</p>
    </section>

    <section class="racconto" data-racconto>
      <div class="palco">
        <header class="testa">
          <p class="marchio">Ostler</p>
          <p class="piccolo piccolo--tenue">Days to the opening</p>
        </header>

        <div class="blocco" data-blocco>
          <div class="spessore" data-spessore aria-hidden="true"></div>

          <div class="fogli" data-fogli>
            <article class="foglio" data-foglio>
              <div class="foglio__carta">
                <p class="foglio__giorno">Monday</p>
                <p class="foglio__numero" data-numero>19</p>
                <p class="foglio__evento" data-evento>Proofs back from the printer.</p>
              </div>
            </article>
            <article class="foglio" data-foglio>
              <div class="foglio__carta">
                <p class="foglio__giorno">Tuesday</p>
                <p class="foglio__numero" data-numero>20</p>
                <p class="foglio__evento" data-evento>Fold, trim, count three hundred.</p>
              </div>
            </article>
            <article class="foglio" data-foglio>
              <div class="foglio__carta">
                <p class="foglio__giorno">Wednesday</p>
                <p class="foglio__numero" data-numero>21</p>
                <p class="foglio__evento" data-evento>Hang the first wall.</p>
              </div>
            </article>
            <article class="foglio" data-foglio>
              <div class="foglio__carta">
                <p class="foglio__giorno">Thursday</p>
                <p class="foglio__numero" data-numero>22</p>
                <p class="foglio__evento" data-evento>Light check at six.</p>
              </div>
            </article>
            <article class="foglio" data-foglio>
              <div class="foglio__carta">
                <p class="foglio__giorno">Friday</p>
                <p class="foglio__numero" data-numero>23</p>
                <p class="foglio__evento" data-evento>Sleep early, for once.</p>
              </div>
            </article>
            <article class="foglio foglio--ultimo" data-foglio>
              <div class="foglio__carta">
                <p class="foglio__giorno">Saturday</p>
                <p class="foglio__numero" data-numero>24</p>
                <p class="foglio__evento" data-evento>Opening night, eight o’clock.</p>
                <i class="foglio__sotto" data-sotto aria-hidden="true"></i>
              </div>
            </article>
          </div>

          <div class="testata" aria-hidden="true"><span>October</span><span>2026</span></div>
          <div class="perfora" data-perfora aria-hidden="true"></div>
        </div>
      </div>
    </section>

    <section class="apertura apertura--fine">
      <h2 class="titolo titolo--medio">See you<br>at eight.</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.

41 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 tear-off calendar” from Animorio and fit it into my site

What it does

The six days before the opening of a made-up print room, Ostler, on a tear-off calendar: a black binding with the month, a dashed perforation under it and a pad of pale sheets with thin outlines, with as many thin lines under the pad as there are sheets left. The screen stops and the first day lands: the number, thin and a little narrow, comes down a few pixels and takes its weight with a pixel of overshoot, and the line of the day rises word by word. Then, for every day, the bottom right corner of the sheet folds up and shows the back of the paper; the sheet starts tearing along the perforation from right to left, a wedge opens under the binding and the dashes of the perforation jump one after the other where the tear goes through, while the pad is pulled down a few pixels. Free, the sheet flies off upwards, turning and tipping backwards, with its shadow, and its number narrows as it goes; the pad springs back with a small shiver and loses one of the lines underneath. Meanwhile the next day lands underneath like the first. The last one, the day of the opening, is printed in orange: when it arrives an orange rule draws itself under its line, the line lights up and the number takes a little more weight. Everything follows the scroll, forwards and backwards.

How it works

The pad

Six sheets in position absolute one on top of the other (the first has the highest z-index), under a black binding and a perforation made of 4-pixel dashes every 7, written by the script on the real width of the pad. The top edge of every sheet is dashed too, with a one-pixel repeating-linear-gradient: so the sheet that flies away has its own torn edge. The lines under the pad, one for every sheet left, give it its thickness. The width of the pad is a min() of 360 pixels, the width and the height of the screen, so it always fits the stage.

The folded corner

Every sheet has two elements: outside the one the script turns and throws, inside the paper, cut by a five-point clip-path on the fold line. Over the paper an SVG draws the back: the corner triangle reflected over the fold line, that is the points (W−g, H), (W, H−g) and (W−g, H−g), in a slightly darker colour with a one-pixel outline, plus a shadow just off it. The fold g goes from 0 to FOLD times the width with a back.out, so it goes a hair too far and comes back.

The tear

While it tears the sheet hangs from its top left corner: transform-origin 0 0 and rotate up to TILT degrees, so a wedge opens under the binding, wider towards the right. The front of the tear runs from right to left with the same number: every dash on the right of the front jumps a pixel and a half with a dying cosine, and the pad is pulled down three pixels.

The flight

The timeline does not move the elements: it moves numbers from 0 to 1 (fold, tear, flight, blow, landing) and a function redraws everything. The flight composes the transform by hand: the shift up and to the right, then the rotation of SPIN degrees, the rotateX and a hair of scale around the centre of the sheet, then the rotation of the tear around the corner. So there is no jump from the tear to the flight. The flight is a power2.in, slow at first and then faster; the number goes from 92% font-stretch to NARROW, and a drop-shadow grows with the distance.

The next day

Every number waits thin (weight 220, width 78%) and a few pixels lower; when the sheet above leaves, the number lands with the LAND curve at BOLD and 92%, and the words of the line rise out of their small windows with a stagger of 0.07. The pad shivers with a dying sine and the last of the thickness lines draws back. On the last day, printed in the accent, an orange rule draws itself with scaleX, the line of the day turns orange and the number gains 40 more weight with elastic.out. With reduced motion the print of a sheet fades out and only then the next day fades in.

Values to change

NameFileDefaultWhat it changes
FOLDscript.js0.24How far the corner folds, as a share of the width of the sheet.
TILTscript.js7How many degrees the sheet hangs while it tears.
SPINscript.js26How many more degrees it turns while it flies away (with a minus it turns the other way).
BOLDscript.js640The weight of the day number once it has landed.
NARROWscript.js62How narrow the number of the flying sheet gets (the width axis, from 50 to 100).
LANDscript.js'back.out(1.8)'The curve of the next day landing: the number in brackets is how far it overshoots.
SCRUBscript.js0.6How many seconds the drawing takes to catch up with the scroll.

Try them in the Playground

When to use it

For a countdown worth telling: the days before an opening, a concert, a festival or a wedding, the programme of a week of events, the steps of a launch, an offer that runs out, a shop’s Advent calendar. Days and lines are changed in the page: it works with three to about ten sheets and short lines.

On phones

The same: the pad takes the width of the screen minus the margins, the binding is a little lower and the line of the day smaller; the sheet flies away the same way and leaves the stage.

With reduced motion

Nothing moves: the days are already printed and in place. Scrolling, the print of the top sheet fades out, the sheet goes and only then the next day fades in, so two days never overlap; at the end the orange rule and the lit line fade in.

Pitfalls

  • The clip-path that cuts the corner cuts the children too: the back of the fold, placed inside the paper, vanished with the corner. The SVG of the fold sits outside the paper, next to it, inside the element that moves.
  • Going from the tear (a rotation around the corner) to the flight (a rotation around the centre), changing transform-origin made the sheet jump. Here the origin stays at 0 0 and the rotation around the centre is written by hand as translate(c) rotate() translate(−c), before the rotation of the tear.
  • perspective on the container of the sheets creates a stacking context: the high z-index of the flying sheet was not enough to pass over the binding. While a sheet flies, the z-index of the whole container goes up.
  • With reduced motion the crossfade between two sheets, caught halfway, showed 19 and 20 on top of each other: first the print of the sheet fades out, then the next day fades in.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Anybody (font variabile, assi wdth e wght) 5.3.0.

Compressed with gzip, the three demo files weigh 7.4 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