
The elastic button
Buttons, Hover, Text
NewFree
In the minimal style, on black: the menu of a weather app. Behind the links lies an invisible pressure field, drawn as hairline isobars recalculated every frame. The link under the pointer becomes a low: the isobars tighten round it in rings, drift slowly in towards it and take the accent colour, and its pressure reading drops on the right. Opening, the lines are drawn out from the middle in a widening circle.
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 isobar menu</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the menu of a weather app. Behind the links an invisible pressure field is drawn as hairline isobars. The link
under the pointer becomes a low: the isobars tighten round it in rings, drift in towards it and light up, its
pressure reading drops; the others relax. Opening, the isobars are drawn out from the middle -->
<div class="isobar" data-frame>
<canvas class="field" aria-hidden="true" data-canvas></canvas>
<button class="toggle" type="button" aria-expanded="false" aria-controls="isobar-menu" data-toggle data-autoclic>
<span class="toggle__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" data-icon>
<path class="toggle__iso" data-iso="0" d="M3 9.5 C7 6, 11 13, 15 9.5 S21 7, 21 7"/>
<path class="toggle__iso" data-iso="1" d="M3 14.5 C7 11, 11 18, 15 14.5 S21 12, 21 12"/>
</svg>
</span>
<span class="toggle__words" aria-hidden="true">
<span class="toggle__word" data-word-open>Menu</span>
<span class="toggle__word" data-word-close>Close</span>
</span>
<span class="sr" data-toggle-name>Open the menu</span>
</button>
<p class="brand" aria-hidden="true" data-brand>Cirrus weather</p>
<nav class="menu" id="isobar-menu" aria-label="Main" data-menu inert>
<ul class="menu__list">
<li><a class="row" href="#today" aria-current="page" data-row><span class="row__mask"><span class="row__word" data-word>Today</span></span><span class="row__read" data-read>1013 hPa</span></a></li>
<li><a class="row" href="#radar" data-row><span class="row__mask"><span class="row__word" data-word>Radar</span></span><span class="row__read" data-read>1013 hPa</span></a></li>
<li><a class="row" href="#forecast" data-row><span class="row__mask"><span class="row__word" data-word>Forecast</span></span><span class="row__read" data-read>1013 hPa</span></a></li>
<li><a class="row" href="#maps" data-row><span class="row__mask"><span class="row__word" data-word>Maps</span></span><span class="row__read" data-read>1013 hPa</span></a></li>
<li><a class="row" href="#alerts" data-row><span class="row__mask"><span class="row__word" data-word>Alerts</span></span><span class="row__read" data-read>1013 hPa</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>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.
30 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 isobar menu” from Animorio and fit it into my siteThe pressure at each point is a sum: a light slope from top to bottom, two slow waves that wander with time, and a Gaussian dip for each link, DEPTH deep times its strength and SPREAD rows wide. The pointer adds a small, narrower dip. Nothing is drawn by hand: every line comes from this formula.
Every frame the pressure is worked out on the nodes of a 5 pixel grid; for each level, RINGS apart, each cell tells which side the line enters and leaves by, and the exact point on the side is found by interpolation. They are short segments that, in a row, make smooth curves. The segments are gathered into a few groups by thickness and colour, so each frame has only seven brush strokes.
The levels don’t stand still: every second they drop by FLOW steps, so every ring round a dip slowly tightens towards the middle and a new one is born outside, like wind lines being drawn in. A line’s thickness and light grow with how much dip is felt at that point.
Each link has its strength, heading for 1 if the pointer is on it, for 0.22 if it is the current page and for 0 otherwise, on a spring (SPRING) with a push at each change: the dip goes a little too far and settles. The strength also drives Mona Sans weight and width and the pressure written on the right, 1013 less 27 times the strength. The rings within 1.35 times the dip’s width take the accent, fading with distance.
One GSAP timeline: Menu and Close swap, the isobars appear inside a circle widening from the middle in 1.4 seconds, the links rise out of their masks 50 milliseconds apart. Closing, the circle withdraws and the button’s isobars come back on an elastic.out. The button has aria-expanded, the closed menu is inert, the arrows move the dip, Esc closes, Tab goes round the button and the links. The preview’s click (detail 0) makes a whole tour.
| Name | File | Default | What it changes |
|---|---|---|---|
DEPTH | script.js | 1.1 | How deep the dip under the pointer is: the deeper, the tighter the isobars crowd round the link. |
SPREAD | script.js | 0.85 | How wide a dip is, in rows. |
RINGS | script.js | 0.12 | The pressure step between two isobars (less, more lines). |
FLOW | script.js | 0.035 | How fast the rings drift in towards the dip (0, they stand still). |
SPRING | script.js | [150, 13] | The dips’ spring: how stiff and how much it is held back. |
WEIGHT | script.js | [300, 640] | The weight of a quiet link and of the one under the pointer. |
WIDTH | script.js | [90, 112] | The width of a quiet link and of the one under the pointer. |
STAGGER | script.js | 0.05 | The seconds between one link and the next when opening and closing. |
For the menu of a weather app or site, a weather station, a service for sailing, flying or mountains, or a studio that works with data. It suits black with four, five or six short links; the reading on the right can show a real number for each section.
The frame is as wide as the screen less 32 pixels and at most 88% of the height tall; the links shrink with the width and the height, and below 340 pixels the app’s name is left out. The dip follows a finger sliding over the links, like the mouse, and a tap chooses the link.
The field stays still: no wandering waves, no drifting rings, no springs. The isobars and the links fade in, and the dip moves from link to link at once, with the same tighter lines and the same accent.
GSAP 3.15.0, Mona Sans (font variabile, con gli assi della larghezza e del peso) 5.3.0.
Compressed with gzip, the three demo files weigh 8.2 KB; the libraries: GSAP 28 KB.
Tested on 24 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.