Skip to content
animorio
IT
Back to the library

The magazine to leaf through

TransitionsGSAP, CSS onlyAdvancedCompressed weight: Demo 13 KBGSAP 28 KBFreeDownload the zip

A made-up magazine with big headlines and drawn illustrations: with a click, or taking the page by its corner, the page turns with a real curl. It folds along a line that follows the finger, shows its back, darkens towards the fold and throws its shadow on the page below. The pointer near a corner lifts it a little.

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 magazine to leaf through</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/fraunces@5.3.0/full-italic.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>
  <main class="stage">
    <!-- the magazine to leaf through: click a page or drag a corner and the page turns with a real curl,
         its back showing, the fold shaded and its shadow falling on the page below -->
    <section class="mag" aria-label="Loam, a magazine of slow places" data-mag>
      <div class="book" tabindex="0" aria-roledescription="magazine" data-book>
        <div class="base base--left" aria-hidden="true" data-base-left></div>
        <div class="base base--right" aria-hidden="true" data-base-right></div>

        <!-- the pages, in reading order: each sheet carries two of them, front and back -->
        <article class="pg pg--cover" data-page data-autoclic data-name="Cover">
          <p class="cover__mast" data-in>Loam</p>
          <p class="cover__tag" data-in>A magazine of slow places</p>
          <svg class="art" viewBox="0 0 100 134" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
            <circle class="c-ochre" cx="76" cy="68" r="14" data-pop/>
            <path class="c-olive" d="M0 96c18-10 34-12 52-6s34 4 48-4v48H0z"/>
            <path class="c-terra" d="M0 108c22-8 40-6 58 0s30 6 42 0v26H0z"/>
            <path class="c-ink" d="M86 102v-16" stroke-width="1.4"/>
            <circle class="c-deep" cx="86" cy="81" r="7" data-pop/>
            <circle class="c-deep" cx="81" cy="86" r="4.4" data-pop/>
            <circle class="c-deep" cx="91" cy="86" r="4.8" data-pop/>
            <path class="c-line" d="M56 50l3 2 3-2M64 44l2.4 1.6 2.4-1.6"/>
          </svg>
          <div class="cover__lines">
            <p class="cover__issue" data-in>Autumn issue</p>
            <p data-in>The orchard that outlived its town</p>
            <p data-in>Bread at four in the morning</p>
            <p data-in>Rivers, slowly</p>
          </div>
        </article>

        <article class="pg" data-page data-name="Contents">
          <p class="kicker" data-in>Inside</p>
          <h2 class="title title--mid" data-in>This autumn, we stayed put</h2>
          <div class="toc">
            <div class="toc__row" data-in><p class="toc__sec">Feature</p><p class="toc__name">The orchard that outlived its town</p><p class="toc__what">Forty trees and the people who still pick them.</p></div>
            <div class="toc__row" data-in><p class="toc__sec">Kitchen</p><p class="toc__name">Bread at four in the morning</p><p class="toc__what">A night with the last baker on the hill.</p></div>
            <div class="toc__row" data-in><p class="toc__sec">Places</p><p class="toc__name">Rivers, slowly</p><p class="toc__what">Following water at walking pace.</p></div>
          </div>
          <svg class="leaf" viewBox="0 0 40 40" aria-hidden="true" data-pop><path class="c-terra" d="M8 32C8 16 18 8 34 6c0 16-8 26-26 26z"/><path class="c-line" d="M8 32L26 14"/></svg>
        </article>

        <article class="pg" data-page data-autoclic data-name="Letter">
          <p class="kicker" data-in>From the editors</p>
          <h2 class="title title--big" data-in>Go slower than the weather</h2>
          <div class="body body--cols" data-in>
            <p class="drop">We meant to travel far this season. Instead we walked to the end of the lane and found more than we could write about. An orchard that nobody owns and everybody tends. A bakery whose lights come on before the birds. A river that takes a whole afternoon to cross a valley.</p>
            <p>None of it is new, and that is the point. The places in this issue have kept their own time while the rest of us hurried. We sat with them long enough to hear it.</p>
            <p>Read it slowly. Turn the pages by the corner, the way paper likes to be turned.</p>
          </div>
          <p class="sign" data-in>The editors</p>
        </article>

        <article class="pg pg--art" data-page data-name="The orchard">
          <svg class="art" viewBox="0 0 100 134" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
            <rect class="c-sky" width="100" height="134"/>
            <circle class="c-ochre" cx="78" cy="22" r="9" data-pop/>
            <path class="c-olive" d="M0 70c20-6 40-6 60-2s30 2 40-2v68H0z"/>
            <path class="c-ink" d="M22 96V78M52 92V72M80 98V80" stroke-width="2"/>
            <circle class="c-deep" cx="22" cy="70" r="12" data-pop/>
            <circle class="c-deep" cx="52" cy="64" r="13" data-pop/>
            <circle class="c-deep" cx="80" cy="72" r="11" data-pop/>
            <g class="c-terra">
              <circle cx="17" cy="66" r="1.8" data-pop/><circle cx="26" cy="73" r="1.8" data-pop/><circle cx="21" cy="62" r="1.6" data-pop/>
              <circle cx="47" cy="60" r="1.8" data-pop/><circle cx="57" cy="66" r="1.9" data-pop/><circle cx="50" cy="70" r="1.6" data-pop/>
              <circle cx="76" cy="69" r="1.7" data-pop/><circle cx="85" cy="74" r="1.8" data-pop/>
            </g>
            <path class="c-ochre" d="M0 104c30-6 60-6 100 0v30H0z"/>
            <path class="c-line" d="M60 120l8-36M66 120l8-36M61 112h6M62 104h6.6M64 96h6.6M65.6 88h6.6"/>
            <path class="c-terra" d="M30 112h14l-2 9H32z" data-pop/>
          </svg>
          <p class="caption" data-in>Picking season, early October</p>
        </article>

        <article class="pg" data-page data-autoclic data-name="The orchard">
          <p class="kicker" data-in>Feature</p>
          <h2 class="title title--huge" data-in>The orchard that outlived its town</h2>
          <p class="stand" data-in>The factory closed, the school closed, the bus stopped coming. The apple trees kept going.</p>
          <div class="body body--cols" data-in>
            <p>Nobody remembers who planted the first row. The deeds were lost in a flood, and the land has belonged to whoever turns up with a ladder ever since.</p>
            <p>Every October they do. A retired teacher, two brothers from the coast, a family who drive four hours with empty crates. They prune, they argue about which tree is sweetest, they leave a basket by the gate for anyone passing.</p>
          </div>
          <blockquote class="quote" data-in>Nobody owns it, so everybody looks after it.</blockquote>
        </article>

        <article class="pg" data-page data-name="Bread at four">
          <p class="kicker" data-in>Kitchen</p>
          <h2 class="title title--big" data-in>Bread at four in the morning</h2>
          <div class="body body--cols" data-in>
            <p class="drop">The oven is older than the house around it. It takes three hours to warm, so the baker lights it at one and sleeps on a bench until the bricks tick.</p>
            <p>By four the dough has doubled in its linen. She shapes forty loaves by feel, in the dark, and the first customers knock before the crust has stopped singing.</p>
          </div>
          <div class="box" data-in>
            <p class="box__head">You need</p>
            <p>Flour, water, salt, and a whole night of patience.</p>
          </div>
        </article>

        <article class="pg pg--art pg--night" data-page data-autoclic data-name="Bread at four">
          <svg class="art" viewBox="0 0 100 134" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
            <rect class="c-night" width="100" height="134"/>
            <circle class="c-paper" cx="74" cy="24" r="8" data-pop/>
            <circle class="c-night" cx="78" cy="21" r="7"/>
            <path class="c-brick" d="M14 112V74a36 30 0 0 1 72 0v38z"/>
            <path class="c-glow" d="M30 112V88a20 16 0 0 1 40 0v24z" data-pop/>
            <path class="c-line-light" d="M14 84h72M14 96h16M70 96h16M22 74v10M78 74v10M50 44v14"/>
            <ellipse class="c-loaf" cx="34" cy="120" rx="10" ry="5" data-pop/>
            <ellipse class="c-loaf" cx="56" cy="121" rx="11" ry="5.4" data-pop/>
            <ellipse class="c-loaf" cx="76" cy="119" rx="9" ry="4.6" data-pop/>
            <path class="c-line-light" d="M30 118l3-2M53 119l3-2M73 117l3-2"/>
            <path class="c-steam" d="M44 40c-3-4 3-6 0-10s3-6 0-10M56 40c-3-4 3-6 0-10s3-6 0-10" data-pop/>
          </svg>
          <p class="caption caption--light" data-in>The oven, lit at one</p>
        </article>

        <article class="pg pg--art pg--river-left" data-page data-name="Rivers, slowly">
          <svg class="art" viewBox="0 0 100 134" preserveAspectRatio="xMaxYMid slice" aria-hidden="true">
            <rect class="c-sky" width="100" height="134"/>
            <path class="c-olive" d="M0 74c24-10 50-8 76-2s20 4 24 4v58H0z"/>
            <path class="c-river" d="M0 100c18-4 34 6 52 2s34-14 48-10v42H0z"/>
            <path class="c-line-light" d="M8 110c6-2 10 0 16-1M36 118c6-2 10 0 16-1M60 104c6-2 10 0 14-1"/>
            <path class="c-deep" d="M14 76l5-14 5 14zM28 72l4-11 4 11z" data-pop/>
          </svg>
          <p class="kicker kicker--over" data-in>Places</p>
          <h2 class="title title--huge title--over" data-in>Rivers, slowly</h2>
        </article>

        <article class="pg pg--art pg--river-right" data-page data-autoclic data-name="Rivers, slowly">
          <svg class="art" viewBox="0 0 100 134" preserveAspectRatio="xMinYMid slice" aria-hidden="true">
            <rect class="c-sky" width="100" height="134"/>
            <circle class="c-ochre" cx="70" cy="40" r="10" data-pop/>
            <path class="c-olive" d="M0 76c10 0 30-6 50-4s34 6 50 2v60H0z"/>
            <path class="c-river" d="M0 92c14-4 28 4 44 6s36-2 56 2v34H0z"/>
            <path class="c-line-light" d="M10 104c6-2 10 0 16-1M40 112c6-2 10 0 16-1M70 106c6-2 10 0 14-1"/>
            <path class="c-terra" d="M30 96h18l-4 4H34z" data-pop/>
            <path class="c-ink" d="M39 96V84" stroke-width="0.8"/>
          </svg>
          <div class="card" data-in>
            <p>We walked the river from its spring to the sea, never faster than the water. It took eleven days. The best hour was the one we spent doing nothing on a stone.</p>
          </div>
        </article>

        <article class="pg pg--back" data-page data-name="Back cover">
          <p class="back__mast" data-in>Loam</p>
          <svg class="art art--small" viewBox="0 0 100 70" aria-hidden="true">
            <path class="c-paper" d="M0 50c24-12 48-14 72-6s20 4 28 2v24H0z"/>
            <path class="c-ink" d="M58 44v-8" stroke-width="1.2"/>
            <path class="c-paper" d="M51 38l7-14 7 14z" data-pop/>
            <circle class="c-paper" cx="24" cy="18" r="2" data-pop/><circle class="c-paper" cx="40" cy="10" r="1.4" data-pop/><circle class="c-paper" cx="80" cy="16" r="1.8" data-pop/>
          </svg>
          <p class="back__next" data-in>Next: Winter, the quiet issue</p>
          <svg class="code" viewBox="0 0 40 16" aria-hidden="true"><path d="M2 0v16M4 0v16M7 0v16M8.4 0v16M11 0v16M14 0v16M15.4 0v16M18 0v16M21 0v16M22.4 0v16M25 0v16M27 0v16M30 0v16M31.4 0v16M34 0v16M37 0v16M38.4 0v16"/></svg>
        </article>
      </div>
      <p class="where" aria-hidden="true"><span class="where__roll" data-where>Cover</span></p>
      <p class="hint">Click a page, or drag it by the corner</p>
      <p class="sr" aria-live="polite" data-live></p>
    </section>
  </main>

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

65 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 magazine to leaf through” from Animorio and fit it into my site

What it does

On a white background in comes Loam, a made-up magazine about slow places: it drops in slightly tilted and settles with a little bounce, the masthead and the cover lines rise one after the other, the sun and the tree swell with an elastic and the bottom corner lifts a little, as if inviting to turn it, then falls back with a flutter. A click turns the cover: the corner rises in an arc, the page folds along a line that runs towards the spine and shows its back, the fold has a highlight and a shade, and the page being uncovered gets the shadow of the one turning. Meanwhile the magazine slides over, with the spine in the middle. The pages being uncovered come alive: the words rise, the apples, the sun, the loaves and the boat swell. Inside are the contents and the editors' letter, an orchard drawn across a full page with its article beside it, the oven at night and a river running across two pages; at the end the green back cover. Under the magazine the name of the page rolls at every turn. Taking a page by its corner and dragging it, the fold follows the finger; let go past the middle, or with a quick flick, it finishes turning, otherwise it goes back into place. At the last page a click closes the magazine again, the pages going back one after the other.

How it works

A fold, not a rotation

The page does not swing round the spine like a door: it folds. The corner C is brought to the point P (where the finger is), and the fold is the bisector of the segment CP: the line through its midpoint, perpendicular to CP. Everything is worked out as if the sheet lay on the right; for a sheet on the left the x values are mirrored (2W − x). Two limits keep the paper whole: the corner stays within a page's width of the spine on its own edge, and within a diagonal of the spine on the opposite edge.

Two clipped faces

Every sheet has two pages, front and back, each in its own layer as big as the open magazine. The face that stays down is clipped with clip-path: the page's rectangle cut by the fold (the Sutherland-Hodgman algorithm against a half-plane). The folded face is clipped to the other part and moved with a matrix: each of its points goes onto the sheet, then is mirrored across the fold. The matrix comes from three points, (0,0), (1,0) and (0,1), and is written as matrix() with transform-origin 0 0.

The light on the fold

The paper looks curved thanks to three soft bands laid along the fold: a dark one on the face that stays down (the paper rising loses light), one on the folded back with a narrow shade, a bright highlight and then a dark veil towards the corner, and one on the page below, in the part being uncovered. Each band is a long div, turned with atan2 and laid with one edge on the fold; the clipped face trims it by itself. They grow with the fold and fade as the page lies down on the other side. The folded back also has a drop-shadow, on the layer that holds it: on the page itself the clip-path would cut it off.

Turning and dragging

A click takes the corner from C to the opposite corner (0, cy) with a GSAP tween: x goes straight, y rises in an arc (the sine of the run times CURL) towards the middle of the page, so the corner draws a curve. Dragging, P follows the pointer with a 0.22 second tween; let go, the corner's place and speed decide: past the middle, or faster than FLICK, it finishes turning, otherwise it goes back. Near a corner the pointer lifts it by LIFT pixels and an elastic.out puts it down again.

The stack and the direction

The order of the pages is rebuilt after every turn: on the right the sheet with the lowest index is on top, on the left the highest; the turning sheet goes above all of them, and its folded back above its own face. Closed, the magazine sits in the middle (half a page's x); open, the spine does. The edges of the pages below are shadows, one line per sheet. The preview's click (detail 0) turns the next page; at the last one it closes the magazine with the sheets in sequence, RIFFLE seconds apart.

Values to change

NameFileDefaultWhat it changes
TURNscript.js1.1How many seconds a page takes to turn after a click.
CURLscript.js0.4How high the corner rises while the page turns, as a share of the page's height: 0 turns it close to the edge, 0.8 lifts it in a high arc.
SHADOWscript.js0.7How dark the shadows on the fold and on the page below are (from 0 to 1).
LIFTscript.js26How many pixels the corner lifts when the pointer comes near it (0 = it does not lift).
CORNERscript.js0.3How near the corner the pointer has to come to lift it, as a share of the page's width.
FLICKscript.js650The speed, in pixels a second, at which a dragged page turns even before the middle.
RIFFLEscript.js0.16The seconds between one page and the next when, at the end, the magazine closes again.

Try them in the Playground

When to use it

To leaf through something born on paper: an online magazine or catalogue, a print portfolio, a restaurant menu, a children's book, a lookbook, an annual report read page by page, an invitation. It works best with pages that read on their own, big headlines and full-page pictures.

On phones

The same magazine with the same folds, open on two pages as wide as the screen: the sizes inside the pages are shares of the width, so the headlines stay big and the text gets small, like a real magazine seen from a distance. It turns with a tap or by dragging the corner with a finger; the lift under the pointer is not there, because a touch has no pointer coming near.

With reduced motion

Nothing folds and nothing moves: at a click the magazine fades out and comes back open on the next page, already in place; closing at the end is a fade too. On arrival it fades in, with no bounce and no corner lifting, and the words do not rise.

Pitfalls

  • The drop-shadow on the folded page did not show: clip-path is applied after the filter, so it cuts the shadow too. The filter goes on the layer holding the page, which is not clipped.
  • Turning a left page the folded back stayed hidden: a sheet's two layers had the same z-index and the document order won, which puts the back above the front. While folding, the layer of the folded face goes up by one.
  • The highlight on the fold has to follow the paper: the soft bands sit inside the pages, and their place is worked out in each face's own coordinates (mirrored for the back), not in the magazine's.
  • On a phone the magazine ran off the screen: the starting width in the CSS (before the script measures) was wider than the screen, and the phone's browser widened the page to hold it. The starting size is small now.
  • Without limits the paper tears: with the corner taken further than a page from the spine the fold would cut off the spine itself and the sheet would come loose. P is brought back inside the two circles before every drawing.
  • A click arriving while the entrance was still lifting the corner made two tweens fight over the same point: the click first takes the entrance to its end.

Libraries

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

Compressed with gzip, the three demo files weigh 13 KB; the libraries: GSAP 28 KB.

Testing

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