
The variable weight menu
Menus, Text, Hover, Physics
NewFree
In the minimal style: the black footer of a studio, with its name along the bottom so big it fills the whole width. The letters feel the pointer and breathe on the weight and width axes, each on a spring of its own, but the word stays justified: when one letter widens the others give the room back, and the edges never move by a pixel. Underneath, a hairline marks the joints and a vermilion line sits under the letter that breathes the most.
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 breathing name footer</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the footer of a small studio: the address, two columns of links, the year, and along the bottom the studio's
name, so big it fills the width. Its letters feel the pointer and breathe on the weight and width axes, while
the word stays justified: when one letter takes more room the others give it back, and the edges never move -->
<footer class="ft" data-footer>
<i class="ft__rule" aria-hidden="true" data-rule></i>
<div class="ft__top">
<div class="ft__reach" data-rise>
<p class="ft__label">Start a project</p>
<div class="ft__mailrow">
<a class="ft__mail" href="mailto:hello@somna.studio" data-breathe data-mail>hello@somna.studio</a>
<button class="ft__copy" type="button" aria-label="Copy the email address" data-copy>
<svg viewBox="0 0 20 20" aria-hidden="true">
<rect class="c-back" x="3.5" y="3.5" width="9" height="9" rx="2" data-copy-back/>
<rect class="c-front" x="7.5" y="7.5" width="9" height="9" rx="2" data-copy-front/>
<path class="c-tick" d="M5.2 10.4l3.2 3.2 6.6-7.2" data-copy-tick/>
</svg>
</button>
<span class="ft__copied" aria-live="polite" data-copied></span>
</div>
</div>
<nav class="ft__cols" aria-label="Footer">
<div class="ft__col" data-rise>
<h2 class="ft__head">Studio</h2>
<ul class="ft__list">
<li><a class="ft__link" href="#" data-breathe>Work</a></li>
<li><a class="ft__link" href="#" data-breathe>Approach</a></li>
<li><a class="ft__link" href="#" data-breathe>Journal</a></li>
</ul>
</div>
<div class="ft__col" data-rise>
<h2 class="ft__head">Elsewhere</h2>
<ul class="ft__list">
<li><a class="ft__link" href="#" data-breathe>Instagram</a></li>
<li><a class="ft__link" href="#" data-breathe>Are.na</a></li>
<li><a class="ft__link" href="#" data-breathe>Vimeo</a></li>
</ul>
</div>
</nav>
</div>
<!-- the name: the script builds one letter per span and solves their widths every frame -->
<div class="ft__name" data-name></div>
<!-- the scale under the name: a hairline, a tick at every joint between letters, and the span of the letter
that breathes the most -->
<div class="ft__scale" aria-hidden="true" data-scale>
<i class="ft__base-line" data-base-line></i>
<i class="ft__span" data-span></i>
</div>
<div class="ft__base" data-rise>
<p class="ft__year"><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 Somna Studio</p>
<nav class="ft__legal" aria-label="Legal">
<a class="ft__link ft__link--small" href="#" data-breathe>Privacy</a>
<a class="ft__link ft__link--small" href="#" data-breathe>Imprint</a>
</nav>
</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.
31 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 breathing name footer” from Animorio and fit it into my siteAt the start every letter of the name is measured at 100 pixels over a grid of widths (every 10, from 50 to 150) and weights (every 100, from 100 to 900): 99 positions, each a single read for all the letters together. In between, the width is read bilinearly, and since the width grows in proportion to the type size, nothing is measured again when the window changes size.
Every letter has its intensity e (0 at rest, 1 under the pointer): the weight is the rest weight plus e times the difference, the width is lam plus SPREAD times e, within the axis. lam is one for the whole word, and the sum of the widths grows with lam: every frame a 22-step bisection on the table finds the lam that makes the word exactly as wide as the footer, less the spaces between letters. If not even the narrowest lam is enough, SPREAD is scaled down instead. The leftover half pixel goes into a flex with justify-content: space-between, so the edges are still by construction.
Every letter leaves a little room at its sides (its side bearings): with the box on the edges, the S and the A sat a few pixels inside. A canvas reads the ink of the first and the last letter at three weights, as a share of their width; the name reaches past the edges by that room, in the same frame, and the solver counts the extra pixels.
Every intensity chases its goal on a damped spring (SPRING), in steps of 1/120 of a second, with the frame step capped at 1/30. The goal is the largest of three bells: the pointer's (with a strength that rises quickly and falls slowly, and fades out 180 pixels from the footer), the entrance wave's, and the slow breath that travels back and forth when nobody points. The vermilion line has two springs of its own, one for each end.
The letters of each link have font-variation-settings written with calc() on a variable --b; GSAP takes --b from 0 to 1 with a stagger that starts from the side the pointer comes in and a spring as its ease. The link keeps its whole name in aria-label for screen readers.
| Name | File | Default | What it changes |
|---|---|---|---|
NAME | script.js | 'SOMNA' | The studio's name, the big word at the bottom: one word (the longer it is, the smaller it gets to fit). |
WEIGHT | script.js | [270, 860] | The weight of a letter at rest and of one right under the pointer (100 to 900). |
SPREAD | script.js | 62 | How much wider the letter under the pointer gets, on the width axis: the others narrow to make room. |
REACH | script.js | 0.8 | How far the pointer is felt, in letters. |
SPRING | script.js | [150, 15] | Each letter's spring: how stiff, and how much it is held back (less holds it back, more it wobbles). |
BREATHE | script.js | true | When nobody points, a slow breath travels through the name by itself. |
BREATH | script.js | 9 | How many seconds a slow breath lasts, there and back. |
DEPTH | script.js | 0.62 | How deep the breath on its own goes, from 0 to 1. |
For the footer of a design studio, an agency, a photographer, a fashion label or a portfolio: anywhere the name is the best thing to leave at the bottom of the page, and words are few.
The footer takes the width of the screen: the address goes on top and the two columns of links stay side by side, with 44-pixel rows to tap. The name fills the width with narrower letters at rest, so it is taller. The letters breathe under a finger that touches and slides sideways on the name (up and down scrolls the page), and between touches the slow breath travels by itself. A tap on a link makes its letters breathe.
The name keeps still, justified, at its rest weight: no springs and no breath on its own. Everything fades in. Under the letter pointed at the vermilion line fades in, and moving to another letter it fades out and back in at the new place without sliding. The links only brighten, and the copy button swaps the squares for the tick with a fade.
GSAP 3.15.0, Anybody (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 12 KB; the libraries: GSAP 28 KB.
Tested on 16 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.