
The layered button
Buttons, Hover, Physics
Free
The night-blue footer of a mountain hut, with its name in giant red letters along the bottom: snow falls over the footer and settles on the top edge of every letter, of the email field and of the round buttons, in the shape real snow takes. A hand passed over the letters sweeps the snow off in a puff of powder and the caps fill up again; pointing at a link settles snow on its letters too, and signing up to the snow report brings a fresh fall.
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 snowy footer</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 footer of a mountain hut: its name stands in giant red letters along the bottom, and snow falls over the
footer and settles on them, in caps that keep their angle of repose. A hand sweeps a letter clean and the
powder flies, the caps fill up again; signing up to the snow report brings a fresh fall -->
<footer class="ft" data-footer data-autoclic>
<canvas class="ft__snow" aria-hidden="true" data-snow></canvas>
<div class="ft__top">
<form class="ft__form" action="#" novalidate aria-labelledby="ft-news" data-form>
<h2 class="ft__title" id="ft-news">The Monday snow report</h2>
<p class="ft__lede">Snow depth, open routes and free bunks, every Monday.</p>
<label class="sr" for="ft-email">Email address</label>
<div class="ft__field" data-field>
<input class="ft__input" id="ft-email" name="email" type="email" inputmode="email" autocomplete="email" autocapitalize="off" spellcheck="false" enterkeyhint="send" placeholder="you@example.com" aria-describedby="ft-note" aria-invalid="false" data-input>
<button class="ft__send" type="submit" data-send>
<span class="ft__send-bg"></span>
<span class="ft__send-label" data-send-label>Sign up</span>
<svg class="ft__spin" viewBox="0 0 24 24" aria-hidden="true" data-spin><circle cx="12" cy="12" r="8"/></svg>
<svg class="ft__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="ft__note" id="ft-note" aria-live="polite" data-note><span class="ft__line">One email a week. Leave whenever you like.</span></p>
</form>
<nav class="ft__cols" aria-label="Footer">
<div class="ft__col">
<h2 class="ft__head"><span class="ft__head-text">Stay</span><button class="ft__toggle" type="button" aria-expanded="false" aria-controls="ft-stay" data-toggle>Stay<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3.5 6l4.5 4.5L12.5 6"/></svg></button></h2>
<ul class="ft__list" id="ft-stay" data-list>
<li><a class="ft__link" href="#" data-link>Book a bunk</a></li>
<li><a class="ft__link" href="#" data-link>Prices</a></li>
<li><a class="ft__link" href="#" data-link>Half board</a></li>
<li><a class="ft__link" href="#" data-link>Groups</a></li>
</ul>
</div>
<div class="ft__col">
<h2 class="ft__head"><span class="ft__head-text">Routes</span><button class="ft__toggle" type="button" aria-expanded="false" aria-controls="ft-routes" data-toggle>Routes<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3.5 6l4.5 4.5L12.5 6"/></svg></button></h2>
<ul class="ft__list" id="ft-routes" data-list>
<li><a class="ft__link" href="#" data-link>Hut to hut</a></li>
<li><a class="ft__link" href="#" data-link>Ski tours</a></li>
<li><a class="ft__link" href="#" data-link>Conditions</a></li>
<li><a class="ft__link" href="#" data-link>Guides</a></li>
</ul>
</div>
<div class="ft__col">
<h2 class="ft__head"><span class="ft__head-text">The hut</span><button class="ft__toggle" type="button" aria-expanded="false" aria-controls="ft-hut" data-toggle>The hut<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3.5 6l4.5 4.5L12.5 6"/></svg></button></h2>
<ul class="ft__list" id="ft-hut" data-list>
<li><a class="ft__link" href="#" data-link>Our story</a></li>
<li><a class="ft__link" href="#" data-link>Getting here</a></li>
<li><a class="ft__link" href="#" data-link>Kit list</a></li>
<li><a class="ft__link" href="#" data-link>Contact</a></li>
</ul>
</div>
</nav>
</div>
<div class="ft__base">
<p class="ft__brand">
<svg class="ft__mark" viewBox="0 0 32 32" aria-hidden="true"><path class="m-hill" d="M1.5 28L11.2 11.6l4.4 7.1 4.6-7.8L30.5 28"/><path class="m-hut" d="M9.2 28v-8.6l6.8-5.8 6.8 5.8V28z"/><path class="m-door" d="M14.3 28v-4.4h3.4V28z"/><path class="m-snow" d="M7.4 19.8l8.6-7.6 8.6 7.6-1.4 1.1L16 15l-7.2 5.9z"/></svg>
<span class="ft__name">Rimefell Hut</span>
<span class="ft__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 Rimefell Hut Trust</span>
</p>
<div class="ft__social">
<a class="ft__icon" href="#" data-icon><span class="sr">Hut webcam</span><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="7" width="13" height="10.5" rx="2.4"/><circle cx="9.5" cy="12.25" r="2.6"/><path d="M16 10.6l4.6-2.4v8.6L16 14.4"/></svg></a>
<a class="ft__icon" href="#" data-icon><span class="sr">Trip journal</span><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 7.2c-2.4-1.6-5.2-2-8-1.4v12.4c2.8-.6 5.6-.2 8 1.4 2.4-1.6 5.2-2 8-1.4V5.8c-2.8-.6-5.6-.2-8 1.4z"/><path d="M12 7.2v12.4"/></svg></a>
<a class="ft__icon" href="#" data-icon><span class="sr">Route maps</span><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3.5 6.4l5.4-2 6.2 2 5.4-2v13.2l-5.4 2-6.2-2-5.4 2z"/><path d="M8.9 4.4v13.2M15.1 6.4v13.2"/></svg></a>
</div>
<nav class="ft__legal" aria-label="Legal">
<a class="ft__link ft__link--small" href="#" data-link>Privacy</a>
<a class="ft__link ft__link--small" href="#" data-link>Terms</a>
<a class="ft__link ft__link--small" href="#" data-link>Cookies</a>
</nav>
</div>
<!-- the hut's name, drawn: each letter is a path, and the snow settles on its top edge -->
<svg class="ft__giant" viewBox="0 -2 1077.5 102" aria-hidden="true" data-giant>
<defs>
<clipPath id="ft-line1" clipPathUnits="userSpaceOnUse"><rect x="-20" y="-60" width="582" height="160"/></clipPath>
<clipPath id="ft-line2" clipPathUnits="userSpaceOnUse"><rect x="562" y="-60" width="536" height="160"/></clipPath>
</defs>
<g clip-path="url(#ft-line1)">
<path data-letter d="M0 100H37V66.4H87.7Q109 66.4 121.4 58.5Q133.7 50.5 133.7 33.2Q133.7 15.8 122 7.9Q110.3 0 90.3 0H0ZM95.2 100H137.1L91.6 53H53.8ZM37 44.1V23.8H79.8Q88.6 23.8 92.6 26.2Q96.7 28.7 96.7 34Q96.7 39.2 92.7 41.6Q88.8 44.1 79.8 44.1Z"/>
<path data-letter d="M162.6 100H199.2V0H162.6Z"/>
<path data-letter d="M229 100H265.6V24.5H265.9L295.9 98.3H340.6L370.6 24.5H370.8V100H407.5V0H347.4L318.3 73.2H318.1L289.1 0H229Z"/>
<path data-letter d="M431.8 100H552.8V76.2H468.8V60.7H545.6V38.6H468.8V23.8H552.8V0H431.8Z"/>
</g>
<g data-line2>
<g clip-path="url(#ft-line2)">
<path data-letter d="M572.4 100H609.5V67.2H677.6V45.2H609.5V23.8H684.8V0H572.4Z"/>
<path data-letter d="M703.2 100H824.2V76.2H740.2V60.7H817V38.6H740.2V23.8H824.2V0H703.2Z"/>
<path data-letter d="M846.2 100H952.1V76.2H883.2V0H846.2Z"/>
<path data-letter d="M971.6 100H1077.5V76.2H1008.6V0H971.6Z"/>
</g>
</g>
</svg>
</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.
56 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 snowy footer” from Animorio and fit it into my siteEach letter of the name is an SVG path. To know where the snow lands, the letter is drawn once on a hidden canvas at twice the size, and for every column of pixels the first solid pixel from the top is found: that is its edge. The email field (a pill) and the round buttons have their edge worked out from the circle; the word of a link pointed at is drawn in its own font, on the baseline given by fontBoundingBoxAscent and fontBoundingBoxDescent.
For every column the most snow it can hold is worked out the way real snow behaves: where the edge is steeper than the angle of repose (STEEP pixels up for each pixel across) nothing stays, on a gentle slope less stays the steeper it is, on a corner only a thin lip clings and from there the cap rises in a quarter-circle shoulder to its full depth (DEPTH, never so deep it reaches the line above), and against a wall rising beside it the snow piles up. Two passes, forwards and back, keep the surface never steeper than STEEP; stretches narrower than seven pixels hold nothing.
The flakes are on three depths with their own size, speed and opacity; they fall, sway and drift with the wind (WIND, which slowly rises and falls). Those of the two front depths that cross the surface of the snow settle there and add to it in a bell over nine columns; meanwhile every cap grows towards its most in REFILL seconds, faster in a heavy fall. Every step the snow evens out along the edge, measured against its most, so no spikes grow and the walls of a channel soften. When the fall eases off, the extra flakes fade where they are, all over.
Between two positions of the pointer the hand moves in small steps, so a quick pass misses nothing. Within its width (BRUSH) the snow is taken off down to the height of the fingers, and more stays towards the sides of the hand, with a soft edge; what comes off becomes powder thrown the way the hand went, which hangs in the air and fades, and a few clumps that drop with gravity and land on the edge further down. A click on a letter knocks all its snow off, while GSAP makes it give and come back with an elastic.out.
Each stretch of snow is one shape: the surface in quadratic curves, a lip bulging past the corner in a Bézier curve, and the bottom a pixel inside the thing it lies on, filled with a gradient from white to the blue of its shade. The canvas sits behind the whole footer: the letters, the field and the buttons hide the snow's foot, so nothing is ever covered. Every frame the position of every edge is read again from its box, so the snow follows the letter coming up or giving, the field shaking, the button jumping and the column opening on a phone.
| Name | File | Default | What it changes |
|---|---|---|---|
SNOWFALL | script.js | 1 | How hard it snows: at 0 the flakes stop, the caps are already there and a swept letter stays clean. |
WIND | script.js | 16 | How hard the wind pushes the flakes sideways, in pixels a second (below zero it blows to the left). |
DEPTH | script.js | 16 | The deepest the snow lies on the big letters, in pixels (less on a phone, and never up to the line above). |
STEEP | script.js | 1.6 | How steep the snow can stand, in pixels up for each pixel across: more makes squarer caps, less pointed domes. |
REFILL | script.js | 6 | Roughly how many seconds a swept letter takes to fill up again. |
BRUSH | script.js | 26 | How wide the hand that sweeps the snow off is, in pixels. |
POWDER | script.js | 1 | How much powder flies when the snow is knocked off: at 0 the snow just goes. |
WAIT | script.js | 1.1 | How long the sign-up takes in the demo, in seconds. |
For the footer of a mountain hut, a ski school, a winter sports shop, a mountain resort, a winter market or festival: anywhere the bottom of the page can have its season, with a big name for the snow to settle on.
The footer takes the width of the screen: the newsletter goes on top and the three columns fold away behind their headings, rows 52 pixels tall with an arrow that turns: a tap opens a column, which grows with its links (44-pixel rows) coming down one after the other. The mark, the round buttons and the legal links wrap. The name splits into two lines, RIME and FELL, so the letters stay big, and each line has its own snow, a little shallower. A finger dragged sideways over the letters sweeps the snow (up and down scrolls the page), a tap on a letter knocks it all off, and tapping a link settles snow on its letters for a moment.
Nothing falls: the caps are already in place, still, and the canvas is only drawn when something changes. The name does not come up, it fades in with its snow; the hand does not sweep and a click does not knock the letters. Pointing at a link turns the word red and the snow fades in on its letters, without the word sinking; the round buttons do not jump, a wrong field does not shake, the button does not narrow and the arc keeps still, and a sign-up brings no fresh fall. On a phone the columns open without sliding, the links fading in.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 21 KB; the libraries: GSAP 28 KB.
Tested on 7 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.