
The flaring bell
Notifications, Transitions, Physics, Text
NewFree
The menu icon's three lines are the menu: clicked, they fan out of the button like strings, cross the screen and settle trembling under the items, splitting when there are more than three, and the words rise out of their lines. Closing, the lines go back into the button, where the X has opened up again into the three lines.
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 three-line menu</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/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- the button comes before the menu, so the Tab key goes from it into the items; the canvas draws the disc, the
three lines and the X under the clear button -->
<button class="toggle" type="button" aria-expanded="false" aria-controls="menu" data-toggle data-autoclic>
<span class="sr" data-name>Open the menu</span>
</button>
<nav class="menu" id="menu" aria-label="Main" data-menu inert>
<ul class="menu__items" data-items>
<li class="menu__row" data-row><a class="menu__link" href="#" data-link><span class="menu__lift" data-lift><span class="menu__word" data-word>Collection</span><span class="menu__hint" aria-hidden="true">Shop</span></span></a></li>
<li class="menu__row" data-row><a class="menu__link" href="#" data-link><span class="menu__lift" data-lift><span class="menu__word" data-word>Workshops</span><span class="menu__hint" aria-hidden="true">Book</span></span></a></li>
<li class="menu__row" data-row><a class="menu__link" href="#" data-link><span class="menu__lift" data-lift><span class="menu__word" data-word>The kiln</span><span class="menu__hint" aria-hidden="true">Tour</span></span></a></li>
<li class="menu__row" data-row><a class="menu__link" href="#" data-link><span class="menu__lift" data-lift><span class="menu__word" data-word>Journal</span><span class="menu__hint" aria-hidden="true">Read</span></span></a></li>
<li class="menu__row" data-row><a class="menu__link" href="#" data-link><span class="menu__lift" data-lift><span class="menu__word" data-word>Visit us</span><span class="menu__hint" aria-hidden="true">Map</span></span></a></li>
</ul>
</nav>
<!-- the lines, the curtain behind them and the icon of the button: one canvas, redrawn every frame -->
<canvas class="lines" data-canvas aria-hidden="true"></canvas>
<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.
25 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 three-line menu” from Animorio and fit it into my siteA fixed canvas over the page draws everything every frame: the menu's paper, the lines, the button's disc and inside it the same lines in the paper's colour (cut by the disc with clip()), and the X. The items are real links over the canvas; the real button is a clear button in the same place. So the icon and the menu's lines are literally the same lines.
Each line has two numbers, a and b, from 0 to 1: how far the left end has travelled and how far the right one, from the icon to the line under its item. The left ends leave from the top with STAGGER seconds between them and take REACH; the right ones come down from the bottom afterwards, in LAND. So the fan opens without one line crossing another. With more than three items each line of the icon feeds a group, symmetric: with five items 2, 1, 2.
Each line is a string of 28 points. Every point is pulled by a spring towards its place on the straight line between the two ends, by its two neighbours (the tension), and damped: ROPE gives the three forces. When the ends rush, the middle lags behind and the string whips, then trembles and stops. Integration runs in steps of 1/240 of a second inside a frame capped at 1/30; a short string, near the icon, is held straight, so the icon never bends. The pointer arriving on an item gives the nearby points a bell-shaped push downwards: the line is plucked.
In the button the X draws itself once the last line has left: two strokes growing from the middle with back.out. Closing, first the two strokes turn flat and slide onto the top and the bottom line while the middle one grows between them: they are the three lines again, and the strings dock on them. While the X is there the strings inside the disc are not drawn, so there is no tangle.
Each word sits in a link clipped with clip-path right on its line: it rises from below with yPercent and sinks into it when closing. Under the pointer or with the focus the word goes from weight 360 to 520 and Fraunces' SOFT axis from 0 to 100. The button comes before the menu in the code, so Tab goes from the button into the items; the closed menu is inert, Esc closes and gives the focus back to the button.
| Name | File | Default | What it changes |
|---|---|---|---|
STAGGER | script.js | 0.07 | The seconds between one line and the next. |
REACH | script.js | 0.62 | The seconds a line's left end takes from the button to its place. |
LAND | script.js | 0.55 | The seconds the right end then takes to come down. |
ROPE | script.js | [240, 21, 900] | The lines as strings: how hard they are pulled to their place, how damped, how tightly the points hold their neighbours. |
PLUCK | script.js | 800 | How hard a line is plucked when the pointer arrives on its item. |
THICK | script.js | 1.5 | How thick the menu's lines are, in pixels (the icon's are 2). |
ICON | script.js | 20 | How long the icon's lines are, in pixels. |
For the full-screen menu of a site with few items and a typeface that deserves room: a studio, a shop, a restaurant, a portfolio. From three to seven items; with more the lines get too close.
The items narrow to the width of the screen; the strings make the same fan from the button at the top right. Without a pointer the lines do not poke out of the button and are not plucked in passing, but tapping an item plucks it, makes it the current page and closes.
The lines neither travel nor tremble: the menu's paper, the lines and the words fade in already in place, and in the button the three lines and the X cross-fade. Closing, everything fades out the same way.
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 8.3 KB; the libraries: GSAP 28 KB.
Tested on 4 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.