Skip to content
animorio
IT
All components

The puffer menu

Menus, SVG, Physics, HoverGSAP, CSS onlyAdvancedCompressed weight: Demo 8.7 KBGSAP 28 KBFreeDownload the zip

The menu of a mountain clothing shop quilted like an orange down jacket: pressing Menu, a flat panel unrolls below the button and its channels fill with down one after the other, puff past their size and settle. The light slides on the nylon with the pointer, which presses a dimple into the channel it is on.

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 puffer menu</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the menu of a shop of outdoor clothing, quilted like a down jacket. At rest a glossy orange button with its
         stitching. Pressed, a flat quilted panel drops below it and its channels fill with down one after the other,
         from the top: each one puffs up with an overshoot and pushes the others down. The light slides on the nylon
         with the pointer, and the pointer presses a dimple into the channel it is on -->
    <div class="shop" data-frame>
      <button class="puff" type="button" aria-expanded="false" aria-controls="puffer-menu" data-toggle data-autoclic>
        <svg class="puff__icon" viewBox="0 0 20 16" aria-hidden="true">
          <rect data-icon-bar x="1.5" y="1" width="17" height="4.4" rx="2.2"/>
          <rect data-icon-bar x="1.5" y="5.8" width="17" height="4.4" rx="2.2"/>
          <rect data-icon-bar x="1.5" y="10.6" width="17" height="4.4" rx="2.2"/>
        </svg>
        <span class="puff__words" aria-hidden="true">
          <span class="puff__word" data-word-open>Menu</span>
          <span class="puff__word" data-word-close>Close</span>
        </span>
        <span class="sr" data-toggle-name>Open the menu</span>
      </button>

      <nav class="quilt" id="puffer-menu" aria-label="Shop" data-menu inert>
        <svg class="quilt__fabric" aria-hidden="true" data-fabric></svg>
        <ul class="quilt__list">
          <li><a class="channel" href="#jackets" data-channel aria-current="page"><span class="channel__name">Jackets</span><span class="channel__note">New season</span></a></li>
          <li><a class="channel" href="#fleece" data-channel><span class="channel__name">Fleece</span><span class="channel__note">Mid layers</span></a></li>
          <li><a class="channel" href="#base" data-channel><span class="channel__name">Base layers</span><span class="channel__note">Merino</span></a></li>
          <li><a class="channel" href="#footwear" data-channel><span class="channel__name">Footwear</span><span class="channel__note">Trail and town</span></a></li>
          <li><a class="channel" href="#sale" data-channel><span class="channel__name">Sale</span><span class="channel__note">Up to 40% off</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.

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

What it does

On a white page there is an orange button glossy like the nylon of a down jacket, with a dashed stitch all round it and an icon of three channels; the light on it follows the pointer. Pressed, the button goes up, its word becomes «Close» and the three channels of the icon squash. Below it a quilted panel unrolls, still flat, and its five channels fill with down one after the other from the top: each puffs up, goes a little past its size and settles, with its sides bulging and its seams pinched, and pushes the ones below down. On each channel there is a link, Jackets, Fleece, Base layers, Footwear and Sale, with a line on the right; the page you are on, Jackets, is sewn on like a patch, with a running stitch round it. The gleam of the light slides on the nylon where the pointer goes; on the channel pointed at a dimple forms and follows it, the link stretches wider and an arrow comes out. Choosing a link the channel is pressed hard and springs back, then the channels empty from the bottom up, the panel rolls back into the button and the button goes back to the middle. It also closes with Esc, with the button or by pressing outside.

How it works

A channel is a shape that breathes

Every channel is redrawn each frame from one number, how full it is (from 0 to 1): its height goes from FLAT to the whole of LOFT, its sides bulge with two quadratic curves the more the fuller it is, the seams stay straight and a little drawn in, and the first and last channels have round corners and an outer edge that swells. The channels are stacked: when one grows it pushes the others down.

The springs of the down

Every channel has its own spring (PUFF: stiffness and damping), lightly held back, so it goes past its size and settles. When the menu opens the panel unrolls with a clip-path and the springs switch on one every STAGGER seconds from the top; when it closes they switch off from the bottom, then the clip-path rolls everything back up.

The nylon in three layers

Over the flat colour lie three layers with the same shape: a vertical gradient darkening the seams and lighting the round (stronger the more the channel is puffed); a long radial gradient, the gleam, sliding sideways towards the pointer with a soft delay (SHEEN); and the dimple, another radial gradient dark in the middle and light at the rim, following the pointer on a spring of its own.

The press

The channel under the pointer is pressed by PRESS: the dimple darkens, the sides bulge a little more, like air pushed aside, and the link sinks a pixel and a half. Choosing presses hard and gives the channel a knock downwards, which the spring brings back up. The links are real links placed in the middle of their channel; the arrows go from one to the next.

Values to change

NameFileDefaultWhat it changes
LOFTscript.js62The height of a channel full of down, in pixels.
FLATscript.js0.55How tall an empty channel is, against a full one.
PUFFscript.js[190, 11]The springs of the channels filling up: how stiff, and how much they are held back.
STAGGERscript.js0.08The seconds between one channel filling and the next.
PRESSscript.js1How deep the pointer presses into the down (0 not at all, 2 a lot).
SHEENscript.js0.55How bright the light is on the nylon.

Try them in the Playground

When to use it

For the shop of a mountain clothing brand, of down jackets, outdoor gear or winter goods: the menu is made of the material of what you sell. It works with four, five or six links, one for each channel.

On phones

The panel narrows to the width of the screen and the channels puff up the same way; a tap chooses the link. Without a pointer the gleam stays still and the dimple shows only when choosing.

With reduced motion

No channels puffing up and no springs: the panel fades in already full of down and fades out the same way. Under the pointer the dimple and the light change without moving anything.

Pitfalls

  • The clip-path that unrolls the panel also cut its shadow (a drop-shadow on the svg): a straight edge of shadow was left at the sides. Now the clip reaches 40% beyond three sides and cuts only from the bottom.
  • The gleam and the dimple are radial gradients in page coordinates with a radius of 1, stretched with a gradientTransform round their centre: with a real radius they would be round, while on a long, low channel they must be ovals.
  • The seams between the channels are drawn again every time after the channels, or the channel puffing up below would cover them.
  • A panel that puffs up changes height every frame: the viewBox and the height of the svg are written again with the channels, and the links are placed in the middle of their channel every time.

Libraries

GSAP 3.15.0, Archivo (font variabile) 5.3.0.

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