Skip to content
animorio
IT
All components

The origami menu

Menus, 3D, TransitionsGSAP, CSS onlyAdvancedCompressed weight: Demo 9.8 KBGSAP 28 KBFreeDownload the zip

A menu folded into a little square of indigo washi: pressed, it lifts and unfolds in 3D face after face, first sideways and then down like an accordion, with its own light and shade on every face and the printed entries appearing as the faces lie flat. Closing, it folds back up into the square.

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 origami menu</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/shippori-mincho@5.3.0/500.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/zen-kaku-gothic-new@5.3.0/400.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/zen-kaku-gothic-new@5.3.0/700.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the menu: a little square of folded paper. Pressed, it unfolds in 3D one face after another, first sideways and
         then down like an accordion, into a sheet with the menu printed on it. The box is as big as the open sheet, and
         the folded square sits in its top right corner, where the paper hangs from. The script builds the paper from
         the menu below, which lies over the open sheet: its links are the ones you press and reach with the Tab key -->
    <div class="origami" data-origami>
      <span class="origami__shadow" data-shadow aria-hidden="true"></span>
      <div class="origami__stage" data-stage aria-hidden="true" inert></div>

      <button class="origami__toggle" type="button" aria-expanded="false" aria-controls="menu" data-toggle data-autoclic>
        <span class="sr" data-name>Open the menu</span>
        <svg class="origami__glyph" viewBox="0 0 24 24" aria-hidden="true"><line x1="6" y1="9" x2="18" y2="9" data-line/><line x1="6" y1="15" x2="18" y2="15" data-line/></svg>
      </button>

      <nav class="sheet origami__nav" id="menu" aria-label="Main" data-nav inert>
        <p class="sheet__head"><span class="seal" aria-hidden="true">紙</span>Menu</p>
        <ul class="sheet__list">
          <li><a class="leaf" href="#" data-leaf><svg class="leaf__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7.5 12 4l8 3.5-8 3.5z"/><path d="M4 12l8 3.5 8-3.5"/><path d="M4 16.5 12 20l8-3.5"/></svg><span class="leaf__name">Papers</span><span class="leaf__note">Washi, chiyogami and kraft</span></a></li>
          <li><a class="leaf" href="#" data-leaf><svg class="leaf__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3.5 13.5 12 4l8.5 9.5L12 20z"/><path d="M12 4v16M3.5 13.5h17"/></svg><span class="leaf__name">Workshops</span><span class="leaf__note">Fold with us on Saturdays</span></a></li>
          <li><a class="leaf" href="#" data-leaf><svg class="leaf__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6.5C10 5 7 4.5 4 5v13c3-.5 6 0 8 1.5 2-1.5 5-2 8-1.5V5c-3-.5-6 0-8 1.5z"/><path d="M12 6.5v13"/></svg><span class="leaf__name">Journal</span><span class="leaf__note">Notes on paper and patience</span></a></li>
          <li><a class="leaf" href="#" data-leaf><svg class="leaf__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 9h16v11H4zM3 6h18v3H3zM12 6v14"/><path d="M12 6c-1.5-3-5-3-5-1s3.5 1 5 1c1.5 0 5 1 5-1s-3.5-2-5 1z"/></svg><span class="leaf__name">Gift sets</span><span class="leaf__note">Wrapped in furoshiki cloth</span></a></li>
          <li><a class="leaf" href="#" data-leaf><svg class="leaf__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21s-6.5-6.2-6.5-11a6.5 6.5 0 0 1 13 0c0 4.8-6.5 11-6.5 11z"/><circle cx="12" cy="10" r="2.3"/></svg><span class="leaf__name">Visit</span><span class="leaf__note">Our studio in Kyoto</span></a></li>
        </ul>
      </nav>
    </div>
  </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.

29 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 origami menu” from Animorio and fit it into my site

What it does

On a white page there is only a little square of indigo paper with printed waves and two light lines: it is the folded menu, in the middle of the page. With the mouse over it, the top layer of the square lifts a little at the corner, as if to be picked up; pressed, it gives a little. Then the square lifts off the page (its shadow widens and softens), grows leaning towards the viewer, and its left half swings open sideways on the middle crease; then the strip unfolds downwards like an accordion, one face after another, each with its own little paper bounce, while the whole thing glides until the open sheet sits in the middle of the page. Every face catches the light its own way as it turns: lighter towards the light, darker when it turns away; the indigo outside and the pale washi inside with its fibres take turns. The menu is printed on the inside (at the top a red seal and Menu, then Papers, Workshops, Journal, Gift sets and Visit, each with an icon in a circle and a line), and the entries on each face rise and light up as that face lies flat. At the end the sheet straightens up and lies flat, with the creases still showing; the button’s two lines have become an X. Under the pointer an entry lights up on a darker paper background and its icon turns and fills; the chosen entry has its icon in the seal’s red. Pressing the X, an entry or Esc, or pressing outside the sheet, the sheet folds back up into the square.

How it works

A chain of hinges

The sheet is a grid of 2 by ROWS faces, each an element placed with a matrix3d the script works out. A face’s matrix is the matrix of the face it hangs from, times a turn about the crease they share: a row hangs from the row above (rotateX about its top edge), the left face from the right one in the same row (rotateY about the middle crease). So a face carries along every face still folded onto it, like real paper.

An accordion unfolding

Each crease between two rows has a number from 1 (folded) to 0 (open), and folds forwards and backwards in turn: shut, the rows lie stacked like an accordion. Rows lying flipped in the folded packet turn their left half the other way, so all the left halves open together as one layer. A GSAP timeline lifts the sheet, opens the middle crease and then the creases between the rows one after another, with back.out for the paper’s bounce; closing, the same timeline runs backwards.

The thickness of the paper

The creases sit half a paper’s thickness (THICK, 2 pixels) off the sheet, on the side they fold to, and the middle crease sits in front of the whole stack: so the folded layers truly lie one over the other in the right order, instead of sharing a plane and flickering through each other.

Light and shade on every face

Each face has two sides with backface-visibility: hidden, the printed inside and the indigo outside with waves. The face’s normal is the third column of its matrix; its dot product with the light’s direction says how much to lighten or darken each side (a light or dark veil over it), times LIGHT. A face lying flat towards the viewer has no veil: the open menu shows its true colours.

The printed menu and the real one

On the inside of every face there is a copy of the whole menu, moved so that the face shows its own piece of it. How open the way from a face to the corner is (the product of its creases) becomes --show, and that face’s entries rise and light up with it. Once the sheet is flat the paper gives way to the real menu, in the same place: its links are the ones you press and the Tab key reaches.

In the middle, folded and open

The box is as big as the open sheet and the little square sits in its top right corner: to have it in the middle of the page, folded the box is moved half a sheet left and down, and the timeline brings it back to its place while the sheet opens. There are at least ROWS faces down, and more if the menu’s last entry, measured at the sheet’s width, would not fit.

Values to change

NameFileDefaultWhat it changes
OPENscript.js1.6The seconds of the whole unfolding (folding back is a little quicker).
CELLscript.js140The side of one face, in pixels: the sheet is two faces wide.
ROWSscript.js3How many faces down the sheet has, at least: if the entries do not fit, the sheet takes more.
TILTscript.js[10, -14]The degrees the sheet leans back and turns while it unfolds.
LIGHTscript.js0.7How strong light and shade on the faces are.
PEEKscript.js26The degrees the top layer lifts while the pointer is on the folded square.
EASEscript.jsback.out(1.25)How each face lands as it opens: a little bounce, like paper.

Try them in the Playground

When to use it

For the site of anyone working with paper, a stationer, a design studio, a Japanese restaurant, a magazine: wherever the menu can be a little object. With five or six entries; for a long menu the sheet gets too tall.

On phones

The faces shrink so that the open sheet fits the screen minus 32 pixels, and the sheet is rebuilt at every change of width, keeping the point it had reached. A tap opens and closes; without a pointer the top layer does not lift.

With reduced motion

No moving folds: the square and the open sheet swap in a fade, the lines become an X at once and the top layer does not lift.

Pitfalls

  • With all creases in the same plane the folded layers flickered through each other: each crease must move half a thickness towards the side it folds to, and the middle crease in front of the whole stack.
  • The left halves of the rows lying flipped in the folded packet must turn the other way: with the same direction, half the faces opened behind the sheet instead of to the side.
  • An SVG filter for the paper’s fibres, redrawn on eight faces turning in 3D, froze the browser without a GPU: the fibres are painted once on a canvas and laid on as a picture.
  • Rebuilt with the sheet open (on a change of width), the timeline took the open sheet as its starting point and would no longer fold back: it is always built from the folded sheet, run silently to the end and then taken back to where it was.
  • The printed faces are copies of the menu: left in the way of the Tab key and screen readers, every entry would be there nine times. The stage of the faces is aria-hidden and inert, and the real menu lies on top, visible only once the sheet is flat.

Libraries

GSAP 3.15.0, Shippori Mincho 5.3.0, Zen Kaku Gothic New 5.3.0.

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

Testing

Tested on 4 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: Done

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