Skip to content
animorio
IT
All components

The layered paper sidebar

Navigation, SVG, Physics, HoverGSAP, CSS onlyMediumCompressed weight: Demo 7.0 KBGSAP 28 KBFreeDownload the zip

The sidebar of a print studio's dashboard, made of five sheets of paper laid one on the other, from the palest on top to a full vermilion at the bottom. Round the page you are on the four top sheets are die-cut, each hole a little smaller than the one above, so the page sits at the bottom of a stepped well with a shadow under every edge. Choosing another, each sheet's hole slides there on a spring of its own: the top one first, then the deeper ones, so the new well opens sheet after sheet while the old one closes from the top. With the pointer on a page the top sheet opens a shallow tray under it.

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 layered paper sidebar</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the sidebar of a print studio's dashboard, made of five sheets of paper laid one on the other, from the palest
         on top to a deep vermilion at the bottom. Round the page you are on, a hole is cut through the four top sheets,
         each one a little smaller than the one above, so the page sits at the bottom of a stepped well. Choosing
         another page, every sheet's hole slides there on a spring of its own, the top one first and the deeper ones
         after: the new well is punched through sheet after sheet while the old one closes from the top. The sheets
         are rectangles cut by masks, redrawn every frame; the links on top are the real navigation -->
    <nav class="side" aria-label="Studio" data-side>
      <svg class="paper" aria-hidden="true" data-paper>
        <defs>
          <filter id="paper-cast" x="-5%" y="-5%" width="110%" height="110%">
            <feDropShadow dx="0" dy="1.8" stdDeviation="1.7" flood-color="#4a1a0a" flood-opacity="0.42"/>
          </filter>
          <mask id="paper-hole-3" maskUnits="userSpaceOnUse"><rect class="paper__full" data-full/><rect class="paper__cut" data-cut/></mask>
          <mask id="paper-hole-2" maskUnits="userSpaceOnUse"><rect class="paper__full" data-full/><rect class="paper__cut" data-cut/></mask>
          <mask id="paper-hole-1" maskUnits="userSpaceOnUse"><rect class="paper__full" data-full/><rect class="paper__cut" data-cut/></mask>
          <mask id="paper-hole-0" maskUnits="userSpaceOnUse"><rect class="paper__full" data-full/><rect class="paper__cut" data-cut/><g data-shallow></g></mask>
        </defs>
        <rect class="paper__base" data-full/>
        <g filter="url(#paper-cast)"><rect class="paper__sheet paper__sheet--3" mask="url(#paper-hole-3)" data-full data-sheet/></g>
        <g filter="url(#paper-cast)"><rect class="paper__sheet paper__sheet--2" mask="url(#paper-hole-2)" data-full data-sheet/></g>
        <g filter="url(#paper-cast)"><rect class="paper__sheet paper__sheet--1" mask="url(#paper-hole-1)" data-full data-sheet/></g>
        <g filter="url(#paper-cast)"><rect class="paper__sheet paper__sheet--0" mask="url(#paper-hole-0)" data-full data-sheet/></g>
      </svg>

      <p class="group" id="group-studio">Studio</p>
      <ul class="list" aria-labelledby="group-studio">
        <li><a class="item" href="#" aria-current="page" data-item>
          <svg class="item__icon" viewBox="0 0 20 20" aria-hidden="true"><path d="M3.5 6.5 10 3.2l6.5 3.3v7L10 16.8l-6.5-3.3zM3.5 6.5 10 9.8l6.5-3.3M10 9.8v7"/></svg>
          <span class="item__name">Orders</span>
        </a></li>
        <li><a class="item" href="#" data-item data-autoclic>
          <svg class="item__icon" viewBox="0 0 20 20" aria-hidden="true"><path d="M5 2.8h7l3 3v11.4H5zM12 2.8v3h3M7.6 11.2l1.7 1.7 3.3-3.6"/></svg>
          <span class="item__name">Proofs</span>
          <span class="item__count">3</span>
        </a></li>
        <li><a class="item" href="#" data-item>
          <svg class="item__icon" viewBox="0 0 20 20" aria-hidden="true"><path d="M3.2 12.6 10 16l6.8-3.4M3.2 9.6 10 13l6.8-3.4M10 3.4l6.8 3.3L10 10 3.2 6.7z"/></svg>
          <span class="item__name">Paper stock</span>
        </a></li>
        <li><a class="item" href="#" data-item data-autoclic>
          <svg class="item__icon" viewBox="0 0 20 20" aria-hidden="true"><path d="M7.6 9.4a2.9 2.9 0 1 0 0-5.8a2.9 2.9 0 0 0 0 5.8zM2.6 16.4c.6-2.9 2.5-4.4 5-4.4s4.4 1.5 5 4.4M13.2 3.9a2.7 2.7 0 0 1 0 5.2M14.6 12.3c1.6.5 2.5 1.8 2.8 4.1"/></svg>
          <span class="item__name">Clients</span>
        </a></li>
      </ul>

      <p class="group" id="group-office">Office</p>
      <ul class="list" aria-labelledby="group-office">
        <li><a class="item" href="#" data-item data-autoclic>
          <svg class="item__icon" viewBox="0 0 20 20" aria-hidden="true"><path d="M5 2.8h10v14.4l-2-1.3-1.7 1.3-1.3-1.3-1.3 1.3L7 15.9l-2 1.3zM7.6 7h4.8M7.6 10h4.8M7.6 13h2.6"/></svg>
          <span class="item__name">Invoices</span>
        </a></li>
        <li><a class="item" href="#" data-item>
          <svg class="item__icon" viewBox="0 0 20 20" aria-hidden="true"><path d="M3.5 6h13M3.5 14h13M7.5 3.9v4.2M12.5 11.9v4.2"/></svg>
          <span class="item__name">Settings</span>
        </a></li>
      </ul>
    </nav>
  </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.

26 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 layered paper sidebar” from Animorio and fit it into my site

What it does

On a white background a cream sidebar 252 pixels wide and about 390 tall, with round corners and a soft shadow. Inside, two groups of links with their thin icons: Studio (Orders, Proofs with the number 3, Paper stock, Clients) and Office (Invoices, Settings). Round the chosen link, Orders, the paper is cut: four steps show, pale peach, peach, coral and at the bottom a full vermilion, each with a thin shadow under its top edge, and the link's name, pale, sits on the red bottom. On arrival the sidebar rises a few pixels and the well opens from its middle line, one sheet after another. Choosing another link the top sheet's cut sets off first, its front edge a moment ahead of the back one, so the hole stretches on the way and then closes up to the link's size; the sheets below follow it, each a little later, and the steps are seen sliding out of step like a telescope. On the new link the well is dug sheet after sheet and the name turns pale when the bottom arrives; on the old one the well closes from the top. With the mouse on another link the top sheet opens from its middle line in a shallow peach tray; from the keyboard the focused link has the tray and a thin outline, and the up and down arrows move from link to link.

How it works

Five sheets, four masks

Inside an SVG behind the links there is a vermilion rectangle, the bottom sheet, and over it four rectangles as big as the sidebar, from coral to cream. Each has a mask: a white rectangle that keeps the paper and a black round-cornered rectangle that cuts it. With a mask two holes that overlap (the well passing over the pointer's tray) stay one hole: with a path and the evenodd rule the shared part closed up again.

The shadow of every cut

Every sheet sits in a group with a feDropShadow downwards. A group's filter works on the sheet already cut by its mask, so the shadow comes from the edge of the hole and falls on the sheet below, only inside the well: that is what makes the steps read as depth.

The cut that moves and the sheets that follow

Where the cut is going is told by two GSAP tweens, one for the top edge and one for the bottom, with a power3.inOut TRAVEL long; the front edge sets off at once and the back one after LEAD of the trip, so the hole stretches and then closes up. Every sheet's hole follows the cut on a spring of its own (SPRING), softer the deeper the sheet (LAG), drawn in by STEP pixels a step. The deep sheets arrive later: the new well is dug and the old one closes from the top by themselves.

The pointer's tray

Every link has a second hole in the mask of the top sheet only, zero tall at rest. With the pointer, a finger down or the keyboard's focus a spring opens it from its middle line to the link's size: the peach sheet shows below, with its shadow, without digging the well.

The name at the bottom

The chosen link's name turns pale (the is-deep class) only when the deepest sheet's hole is under it, at least half the link tall and centred: on the way it stays dark and reads on every sheet. The links are real links with aria-current="page"; the arrows, Home and End move the focus.

Values to change

NameFileDefaultWhat it changes
STARTscript.js0The page chosen when the sidebar opens (0 is the first one).
STEPscript.js4.2How much smaller each sheet's hole is than the one above, in pixels: the steps of the well.
TRAVELscript.js0.42The seconds the top sheet's cut takes to go one page down (a little more for a far one).
SPRINGscript.js[260, 22]The top sheet's spring behind the cut: how stiff, and how much it is held back (less, further it overshoots).
LAGscript.js0.42How much later each deeper sheet follows the one above (0, all together).
LEADscript.js0.22How far ahead the front edge of a hole sets off, as a share of the trip: on the way the hole stretches.
SHALLOWscript.jstrueThe pointer opens a shallow tray in the top sheet only.

Try them in the Playground

When to use it

For the sidebar of a dashboard or an app with five, six or eight pages: a print studio, a graphic design studio, a stationer's, anyone who works with paper and wants a warm, handmade interface. The well reads on any colour: the five sheets are variables, from the palest on top to the darkest at the bottom.

On phones

The sidebar is 252 pixels wide and about 390 tall: at 390 pixels it fits whole on the screen. With a finger down on a link the top sheet opens its tray, as with the mouse over it, and the tap chooses it.

With reduced motion

No sliding holes and no tray: choosing another link the well appears already dug under it, in a short fade. When the page opens the sidebar fades in with the well already in place.

Pitfalls

  • With the holes made as paths with the evenodd rule, the pointer's tray and the well passing over it cancelled each other out and the shared part went back to paper. Now every sheet has a mask, and the black rectangles add up.
  • With springs only, from far away the hole set off with a jolt and in sixty milliseconds it was already there: nothing could be seen. Now the cut moves with two tweens with a soft start, and the springs are only for the sheets that follow it.
  • A link's name turned pale while the well ran over it, and for a moment vanished on the cream. Now only the chosen link turns pale, once the bottom has arrived.
  • With 3.4 pixel steps and a light shadow the well looked like a flat pill with a rim: the steps are now 4.2 at the sides (a little less top and bottom, so the name has room) and the shadow is darker.

Libraries

GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.

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

Testing

Tested on 19 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 components