Skip to content
animorio
IT
Back to the library

The one-sentence notebook

Scroll, 3D, TextGSAP, CSS onlyAdvancedCompressed weight: Demo 10 KBGSAP + ScrollTrigger 45 KBFreeDownload the zip

Scroll inside the preview

In the minimal style: a white notebook lying open on the table, a single word on every page. As you scroll the pages turn in 3D, curl, land with a small bounce and their edge settles on the air; turned in a row they make a sentence, which grows word after word on the left page. The last page stays open, with a red full stop dropping on the line.

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 one-sentence notebook</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- a plain white notebook lying open on the table: as you scroll its pages turn in 3D, one word on each, and turned
       in a row they make a sentence. The last page stays open with a single red full stop. The words are in WORDS, at
       the top of script.js -->
  <main>
    <section class="racconto" data-racconto>
      <div class="palco">
        <header class="testa">
          <p class="marchio">Quire</p>
          <p class="nota">One line per page</p>
        </header>

        <div class="scena" data-scena>
          <div class="libro" data-libro>
            <div class="ombra-libro" aria-hidden="true"></div>
            <div class="copertina" aria-hidden="true"></div>
            <!-- the two pages that never move: the inside of the cover on the left, the last page on the right -->
            <div class="fissa fissa--sinistra" data-sinistra aria-hidden="true">
              <div class="contenuto contenuto--retro">
                <i class="riga"></i>
                <span class="sigla">Quire</span>
                <i class="velo velo--retro"></i>
              </div>
            </div>
            <div class="fissa fissa--destra" data-destra aria-hidden="true">
              <div class="contenuto contenuto--fronte">
                <i class="riga"></i>
                <span class="parola parola--segno"><span class="segno" data-segno></span></span>
                <i class="velo velo--fronte"></i>
              </div>
            </div>
            <!-- the pages that turn are written here by the script -->
          </div>
        </div>

        <!-- the sentence for screen readers -->
        <p class="frase-letta" data-frase></p>

        <p class="invito" data-invito><span data-invito-testo>Scroll to turn the pages</span></p>
      </div>
    </section>

    <section class="coda">
      <p class="coda__testo">Quire makes plain notebooks<br>for one good sentence a day.</p>
      <p class="piccolo">Pocket size, 96 pages, one line on each</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.

25 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 one-sentence notebook” from Animorio and fit it into my site

What it does

On a warm white table lies a white pocket notebook, open and leaning back a little, with the edge of its cover showing around the pages. Every page has a single thin line, at the same height on both sides. On arrival the notebook rises onto the table, the line draws itself from the left and «Write», on the right page, gains weight with a little elastic. As you scroll, the page leaves the stack: the corner lifts first, so the paper curls forward, then it crosses over the spine and falls on the other side with its free edge trailing behind, like paper in the air. On the left stack it bounces twice, by a few degrees, while the edge, lighter, lifts and settles three times; the notebook feels the knock and sinks by a hair. As the page rises, its shadow covers the page below starting from the spine, then moves onto the left stack; the turning paper darkens the more it turns its back to the light. Every page turned uncovers the next word, which is born thin and soft and gains weight with an elastic; on the back of the page just turned, on the left, is the sentence read so far, the old words in grey and the newest in black: «Write», «Write one», «Write one thing», «Write one thing well». The last page does not turn: when the page above leaves, a red full stop drops on its line, squashes, bounces a hair and turns round again, and the sentence on the left goes all black. Scrolling back up, everything goes back page by page. On a phone the notebook is bound at the top, like a reporter’s pad: the pages turn upwards and the sentence sits above the word.

How it works

A page made of strips

Every page that turns is a chain of ten vertical strips, each a child of the one before and hinged on its edge with transform-origin on the left: the first turns around the spine with rotateY, the others each add a small angle, so the paper curls. Every strip has two faces, the front and the back (turned 180 degrees, backface-visibility: hidden), and inside each is the whole page, moved as much as needed for only its slice to show. The strips are 1.6 pixels wider than their share: they overlap, and no gap ever opens between two strips at an angle.

The turn of a page, written by hand

The timeline moves a single number per page, p from 0 to 1, and a function turns it into an angle and a curl. For the first eight tenths the page is in the air: the angle follows u²(2−u), slow to leave the stack and still moving when it reaches the other side; the curl follows sin(2πu), positive as it rises (the corner leads) and negative as it falls (the edge trails). In the last two tenths, the landing: the page bounces twice by a few degrees and the edge lifts three times, with two damped sines that end exactly at zero. The curl grows towards the free edge and never pushes a strip past 0 or 180 degrees, into a stack.

Light and shadows

Every face darkens with the angle it is turned to: the front with 1−cos, the back with 1+cos. So as not to see the strips as bands, the shade of every strip is a gradient between the average of its angle with the strip before and with the one after, so two neighbouring strips match on their edge. The shadow the page throws below is another gradient, on the front of the page under it on the right and on the back of the page under it on the left, starting from the spine and as long as the page seen from above (the cosine of the angle). Pages covered by another one are not drawn at all.

The word that gains weight

The words are set in Fraunces, a variable typeface with weight and softness (SOFT) axes. As a page lifts, the word under it goes from 220 to 600 in weight with an elastic.out worked out on its travel, and from soft it turns crisp: scrolling back and forth, the elastic plays again. The words are measured by the browser with a hidden element, because the optical size axis changes the width and a canvas cannot set it; they are measured at the highest weight the elastic reaches, so a word never runs off the page.

The full stop and the upright notebook

The red full stop on the last page falls with constant acceleration, squashes as it touches the line and turns round again with a damped spring that swings one and a half times, all tied to the scroll. Then the --letta variable takes the grey words to black. When the screen is narrow the notebook is read upright: the same strips become horizontal, the page turns with rotateX around its top edge and the gradients change direction; the timeline stays the same.

Values to change

NameFileDefaultWhat it changes
WORDSscript.js['Write', 'one', 'thing', 'well']The words, one per page: turned in a row they make the sentence. The more there are, the shorter the scroll of each.
LASTscript.js'.'The sign on the last page, the one that stays open, in the accent colour: a full stop, an exclamation mark, a short word.
BENDscript.js26How much the paper curls while it turns, in degrees: 0 is stiff card.
BOUNCEscript.js0.5How much a page bounces and how far its edge lifts when it lands: 0 not at all, 1 a lot.
TILTscript.js16How far the notebook leans back on the table, in degrees (a little less on a phone).
LIGHTscript.js220The weight of a word while it is still covered.
BOLDscript.js600The weight a word settles on once its page is open.
SCRUBscript.js0.9How many seconds the pages take to catch up with the scroll: 0 ties them to the wheel.

Try them in the Playground

When to use it

For the opening of a blog or a journal, a studio’s manifesto in one sentence, the launch of a paper product (notebooks, a magazine, a book), the «about» page of a publisher: a short sentence, four to six words, worth reading one word at a time.

On phones

The same pages, the same bounces and the same full stop, but the notebook is bound at the top: the pages turn upwards around their top edge, the sentence sits above and the word below, both as wide as the screen.

With reduced motion

No pages turning and no movement: the notebook stays open and, as you scroll, the word on the right and the sentence on the left take turns with a fade, up to the red full stop and the sentence all in black.

Pitfalls

  • With strips exactly as wide as their share, a one-pixel gap opened between two strips at an angle, and the letters of the page below showed through: the strips overlap by 1.6 pixels and pages covered by another one are not drawn.
  • A flat shade per strip made the page look banded, and leaving the shade out of the overlapping part left light lines: every strip has a gradient between the average angles of its two edges, which keeps the edge value in the overlapping part, so neighbouring strips match.
  • The sentence on the left page, measured with a canvas, ran off the page: Fraunces changes width with its optical size axis, which a canvas cannot set. The browser measures it with a hidden element, inside the stage (outside it, it made the page overflow sideways on a phone).
  • An element with preserve-3d loses its depth if it has opacity: the entrance fades the scene that holds the perspective, not the notebook, and the faces have overflow hidden but no 3D children.
  • On a phone the notebook open sideways was a third of the screen tall and the sentence was hard to read: bound at the top, with the same strips turned 90 degrees and rotateX instead of rotateY, it takes the whole width.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Fraunces (font variabile, assi opsz, wght e SOFT) 5.3.0, Instrument Sans (font variabile) 5.3.0.

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

Testing

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