Skip to content
animorio
IT
All components

The layered button

Buttons, Hover, PhysicsGSAPMediumCompressed weight: Demo 4.1 KBGSAP 28 KBFreeDownload the zip

Under the button there are three copies of it: as the pointer comes near they open into a stair on the side away from it and follow it as it moves, each a little later and a little looser than the one above; pressed, the button sinks and the stack closes.

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 button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the buttons: each one has three copies of itself underneath. As the pointer comes near they open into a stair
         on the side away from it, each copy a little later than the one above; a press pushes the button down into
         them -->
    <div class="buttons" data-buttons>
      <button class="stack stack--colour" type="button" data-stack>
        <span class="stack__layer" aria-hidden="true"></span>
        <span class="stack__layer" aria-hidden="true"></span>
        <span class="stack__layer" aria-hidden="true"></span>
        <span class="stack__face">Let’s talk<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12h13M13 6.5l5.5 5.5-5.5 5.5"/></svg></span>
      </button>
      <button class="stack stack--paper" type="button" data-stack>
        <span class="stack__layer" aria-hidden="true"></span>
        <span class="stack__layer" aria-hidden="true"></span>
        <span class="stack__layer" aria-hidden="true"></span>
        <span class="stack__face">See the work</span>
      </button>
    </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.

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

What it does

On a white background two rounded-rectangle buttons with a thick black edge: a yellow one, Let’s talk with an arrow, with three pink, blue and black copies underneath; a white one, See the work, with three white copies like sheets of paper. At rest only the copies’ edges show, a thin stair at the bottom right. As the pointer comes near (from 150 pixels) the stack opens: the copies step out on the side away from the pointer and swing round it as it moves, the nearest at once and the farthest last, with a springy wobble, while the button lifts a little towards the pointer. Pressed, the button sinks into its copies and the stack closes; let go, it opens again with a wobble. With the Tab key the stack opens towards the bottom right; on a phone a tap opens it away from the finger, presses it and then lets it close. When the page opens both stacks open once and close again.

How it works

The copies

The button holds three empty spans with its very shape, put behind it with z-index, and the face with the words. The black edge is an inset box-shadow, so every copy has exactly its edge.

The stair

One number says how far apart the copies are (REST at rest, GAP open, zero pressed) and a vector the direction, away from the pointer. Each layer goes to (place − 0.6) times that distance along the direction: the face, place zero, goes a little towards the pointer, and the copies, places 1 to 3, towards the other side.

The pointer’s field

On every move the distance between the pointer and the button’s rectangle is measured: from REACH pixels down to zero the stack opens along a soft curve. The direction runs from the pointer to the button’s centre, with a little of the bottom right, and the farther the pointer, the more it goes back to the bottom right.

The springs

Each layer hangs on a spring towards its place, moved by hand on GSAP’s ticker in steps of 4 milliseconds at most: the face’s stiffness is SPRING[0], each copy below is looser by LAG, and the damping is SPRING[1]. Pressing, the face’s spring gets four times stiffer, so the button sinks at once.

Keyboard and finger

With the focus from the Tab key the stack opens towards the bottom right, and Enter or Space give a short press by themselves. A finger opens the stack on pointerdown, away from the touch, and lets it close half a second later.

Values to change

NameFileDefaultWhat it changes
GAPscript.js7The room between two copies when the stack is open, in pixels.
RESTscript.js1.6The room at rest.
REACHscript.js150How far from a button the pointer starts to open its stack, in pixels.
SPRINGscript.js[420, 0.58]The button’s spring: how stiff, and how much it settles (1 = no wobble at all).
LAGscript.js0.45How much looser each copy’s spring is than the one above.

Try them in the Playground

When to use it

For the main button of a site with a playful, graphic or slightly retro character: a studio, a portfolio, a shop, an event. It suits solid colours and sharp edges.

On phones

The buttons wrap if the screen is narrow. A tap opens the stack away from the finger, presses it and lets it close; without a pointer the resting stack stays at the bottom right.

With reduced motion

No springs and no field: the stack opens at once only with the pointer over the button, always towards the bottom right, and closes at once under a press.

Pitfalls

  • The distance must be measured from the button’s rectangle, not from its centre: for a wide button the pointer over one end would already count as far away.
  • With a stiff spring and a slow frame the maths blows up: that is why each step is split into pieces of 4 milliseconds at most.
  • The rectangle is read from the button, which never moves: only the face and the copies inside it move, so the measure never chases itself.
  • The opening does not use :hover but pointermove on the window: that way the stack already opens before the pointer reaches the button.

Libraries

GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.

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

Testing

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