
The layered button
Buttons, Hover, Physics
Free
The deep green footer of a small plant nursery, with a strip of meadow growing along its top edge: hundreds of blades on three planes, each one a spring stirred by the breeze and by gusts running from one side to the other. The pointer parts the grass like a hand, a link pointed at sends a gust its way, and signing up to the newsletter makes flowers bloom in the meadow, one after the other.
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 meadow footer</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/instrument-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the footer of a small plant nursery: a strip of meadow grows along its top edge, hundreds of blades on three
planes, each one a spring stirred by the breeze and by gusts running across; a hand in the grass parts it,
pointing at a link sends a gust there, and a sign-up to the newsletter makes flowers bloom in it -->
<footer class="pf" data-footer data-autoclic>
<canvas class="pf__meadow" aria-hidden="true" data-meadow></canvas>
<div class="pf__panel">
<div class="pf__top">
<form class="pf__form" action="#" novalidate data-form>
<h2 class="pf__title" data-in>Notes from the nursery</h2>
<p class="pf__lede" data-in>What to sow, what to cut back, and first pick of new plants. One letter a month.</p>
<label class="sr" for="pf-email">Email address</label>
<div class="pf__field" data-field data-in>
<input class="pf__input" id="pf-email" name="email" type="email" inputmode="email" autocomplete="email" autocapitalize="off" spellcheck="false" enterkeyhint="send" placeholder="you@example.com" aria-describedby="pf-note" aria-invalid="false" data-input>
<button class="pf__send" type="submit" data-send>
<span class="pf__send-bg" data-send-bg></span>
<span class="pf__send-label" data-send-label>Subscribe</span>
<svg class="pf__spin" viewBox="0 0 24 24" aria-hidden="true" data-spin><circle cx="12" cy="12" r="8"/></svg>
<svg class="pf__done" viewBox="0 0 24 24" aria-hidden="true" data-done><path d="M6.4 12.6l3.7 3.7 7.6-8.6"/></svg>
</button>
</div>
<p class="pf__note" id="pf-note" aria-live="polite" data-note data-in><span class="pf__line">No spam, ever. Leave with one click.</span></p>
</form>
<nav class="pf__cols" aria-label="Footer">
<div class="pf__col" data-in>
<h3 class="pf__head">Shop</h3>
<ul>
<li><a class="pf__link" href="#" data-link>Perennials</a></li>
<li><a class="pf__link" href="#" data-link>Grasses</a></li>
<li><a class="pf__link" href="#" data-link>Seeds</a></li>
<li><a class="pf__link" href="#" data-link>Garden tools</a></li>
<li><a class="pf__link" href="#" data-link>Gift cards</a></li>
</ul>
</div>
<div class="pf__col" data-in>
<h3 class="pf__head">Visit</h3>
<ul>
<li><a class="pf__link" href="#" data-link>The nursery</a></li>
<li><a class="pf__link" href="#" data-link>Find us</a></li>
<li><a class="pf__link" href="#" data-link>Workshops</a></li>
<li><a class="pf__link" href="#" data-link>Garden café</a></li>
</ul>
</div>
<div class="pf__col" data-in>
<h3 class="pf__head">Help</h3>
<ul>
<li><a class="pf__link" href="#" data-link>Delivery</a></li>
<li><a class="pf__link" href="#" data-link>Returns</a></li>
<li><a class="pf__link" href="#" data-link>Plant care</a></li>
<li><a class="pf__link" href="#" data-link>Contact us</a></li>
</ul>
</div>
</nav>
</div>
<div class="pf__legal" data-in>
<p class="pf__mark">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21.5c0-6.4-.6-11.4-3.4-16"/><path d="M12 21.5c.3-5.2 2.3-9.4 6.2-12.6"/><path d="M12 21.5c-1-3.6-3.2-6.2-6.6-7.6"/><path d="M12 21.5c.6-3 2-5 4.4-6.2"/></svg>
<span>Sorrel & Sedge</span>
<span class="pf__copy"><svg viewBox="0 0 12 12" aria-hidden="true"><circle cx="6" cy="6" r="5.1"/><path d="M7.9 4.5a2.3 2.3 0 1 0 0 3"/></svg><span class="sr">Copyright</span> 2026 Sorrel & Sedge Ltd</span>
</p>
<nav class="pf__small" aria-label="Legal">
<a class="pf__link pf__link--small" href="#" data-link>Privacy</a>
<a class="pf__link pf__link--small" href="#" data-link>Terms</a>
<a class="pf__link pf__link--small" href="#" data-link>Cookies</a>
<a class="pf__link pf__link--small" href="#" data-link>Accessibility</a>
</nav>
</div>
</div>
</footer>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>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.
55 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The meadow footer” from Animorio and fit it into my siteThe blades grow in tufts of two to five, spread evenly along the edge with a shake, on three planes with their own height, width and colour; the height also rolls along the edge, so the meadow's outline has higher and lower patches. Each blade has its own lean, curl, stiffness (higher for short blades) and damping, taken from a seeded random generator, the same every time. How many there are depends on the width: DENSITY blades per pixel.
A blade's state is an angle of bend and its speed: every step the angle is pulled towards the one the wind wants by a damped spring (SPRING and DAMPING). The blade is drawn in three pieces, bending more towards the tip (the bend grows as the length to the power of 1.2), as a tapering shape with quadratic curves for its sides. The frame's step is at most 1/30 of a second and is split into steps of 1/120 inside, so the stiff springs and the hand's push stay stable.
The wind at a point is a breeze rolling to the right that slowly swells and falls (two waves multiplied), plus a flutter of each blade's own, plus the gusts: each is a bell running at GUST_SPEED pixels a second, with a steep front and a long tail. A tall blade catches more wind than a short one. The more a blade is bent, the more its colour goes towards the light: the blades are sorted by plane, tone and light into twenty-four paths, each filled with a vertical gradient that turns into the footer's green at the root.
The pointer is a finger reaching down into the grass: from its point to the ground no blade may stand within HAND pixels. For every blade nearby the angle it needs to go round it is worked out, at the finger's height or with its tip if it is shorter, and a strong spring pushes it there, only outwards; the blade remembers which side it met it on. A fast hand also drags the blades it brushes its way, with a force that grows with the square of the speed.
Pointing at a link starts a gust that runs from the last link pointed at (or from a point at least 220 pixels away) to its position, slowing down, and dies there. On a sign-up the flowers come up in spots spread with a shake, and GSAP grows the stem (back.out) and opens the flower (elastic.out) one after the other from the form outwards: the petals spread from a bunch pointing up to the whole circle. The stems have their own spring and follow the wind and the hand like the blades.
| Name | File | Default | What it changes |
|---|---|---|---|
BREEZE | script.js | 0.5 | How hard the breeze blows all the time: at 0 the meadow keeps still until something stirs it (and no gusts come). |
GUSTS | script.js | 6 | Roughly how many seconds go by between two gusts running across the meadow. |
GUST_SPEED | script.js | 560 | How fast a gust runs from one side to the other, in pixels a second. |
DENSITY | script.js | 0.75 | How many blades grow on each pixel of width, counting the three planes. |
SPRING | script.js | 70 | How stiff a blade is: more makes it spring back up sooner. |
DAMPING | script.js | 1.5 | How quickly a blade stops swaying: less makes it swing for longer. |
HAND | script.js | 36 | How wide the hand that parts the grass is, in pixels. |
FLOWERS | script.js | 9 | How many flowers bloom when someone subscribes (fewer on a narrow footer). |
WAIT | script.js | 1.1 | How long the sign-up takes in the demo, in seconds. |
For the footer of a plant nursery, a seed or garden tool shop, an outdoor brand, a farm or a farm stay, an open-air festival: anywhere signing up to the newsletter deserves a small reward and the bottom of the page can breathe.
The footer takes the width of the screen: the newsletter goes on top and the three columns of links line up under it, narrower; the copyright and the legal links wrap. The meadow stays as tall but with fewer blades, and the flowers are fewer and a little smaller. A finger dragged sideways through the grass parts it like the pointer (up and down scrolls the page), a tap pats it down all round, and tapping a link brings up the shoot and sends the gust as the hover does.
The meadow is drawn once, still, with its curves: no breeze, no gusts, the hand does not move it and it is not redrawn. Pointing at a link the word stays where it is and the shoot fades in beside it; the button does not narrow and the arc keeps still; on a sign-up the flowers fade in already open, one after the other; a wrong field does not shake.
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 19 KB; the libraries: GSAP 28 KB.
Tested on 6 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.