
The elastic button
Buttons, Hover, Text
NewFree
On black, the sign-up of a site for personal pages where you claim the address of your page, orrin.page/ and your name. Every change of the name is a letter-by-letter morph: the letters in common slide to their new place, the others drop away or rise in narrow and light. A capital is seen turning into a small letter, a space into a hyphen; a taken name is struck through and three free names arrive, a free one turns lime, and once claimed the button becomes Copy link.
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 name to claim</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 sign-up of a page for makers: you claim the address of your page. The letters are drawn over a real
field, and every change is a morph: the letters both words share slide to their new place, the others drop
out or rise in. Checking and claiming are pretended: see check() and post() in the script -->
<form class="claim" action="#" novalidate aria-labelledby="claim-title" data-claim data-autoclic>
<h2 class="claim__title" id="claim-title">Claim your page</h2>
<div class="claim__box" data-box>
<label class="claim__field" for="claim-handle" data-field>
<span class="claim__prefix" data-prefix>orrin.page/</span>
<span class="claim__slot" data-slot>
<input class="claim__input" id="claim-handle" name="handle" type="text" autocomplete="username" autocapitalize="off" autocorrect="off" spellcheck="false" enterkeyhint="go" maxlength="30" aria-label="Page name, after orrin.page/" aria-describedby="claim-status" aria-invalid="false" data-input>
<span class="claim__glyphs" aria-hidden="true" data-glyphs></span>
<span class="claim__hint" aria-hidden="true" data-hint>yourname</span>
<span class="claim__strike" aria-hidden="true" data-strike></span>
<span class="claim__sweep" aria-hidden="true" data-sweep><span></span></span>
<span class="claim__caret" aria-hidden="true" data-caret></span>
</span>
</label>
<button class="go" type="submit" data-go>
<span class="go__bg" aria-hidden="true"></span>
<span class="go__label" aria-hidden="true" data-go-glyphs></span>
<span class="sr" data-go-text>Claim</span>
</button>
<span class="claim__line" aria-hidden="true" data-line></span>
</div>
<div class="claim__under">
<p class="claim__status" id="claim-status" data-status><span class="status__line">Letters, numbers and hyphens, 3 to 24 of them.</span></p>
<div class="claim__ideas" data-ideas></div>
</div>
<p class="sr" role="status" aria-live="polite" data-live></p>
</form>
</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.
32 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 name-to-claim field” from Animorio and fit it into my siteThe name is a real input, its own words transparent: the caret, the selection, pasting and the keyboard stay the browser’s. Over it every letter is a box as wide as the letter at rest, put in place with widths measured on a canvas in the same type (measureText of the beginnings of the name, with kerning). If the name is longer than the field, the letters follow the input’s scroll.
Between the word before and the new one the longest common subsequence is found (a dynamic programming table): the letters in common slide to their new place with back.out, the others drop RISE pixels narrowing on the wdth axis of Mona Sans and losing weight, the new ones rise from below, narrow and light, and take wdth 100 and their weight, staggered by STAGGER. The same engine sets the button’s words, and the button takes the new width on the same rebound.
At every key the text is shown first as typed and 12 hundredths of a second later normalised (small letters, spaces and dots into hyphens, the rest removed), putting the caret back in the right place: the capital is seen falling and the small letter rising. Length, hyphens and reserved names are checked at once; the rest QUIET seconds after the last key with check(), a promise to replace with a real request, and an old answer is ignored.
Taken: a line strikes the name through (scaleX from the left), the field has aria-invalid and three free names built from yours arrive below, with the letters in common in white; picking one, the letters you already have stay still. Free: name and button in lime. Pressing the button while the name is still to be checked checks it at once and claims it if it is free. Claimed (post() pretends the request), the weight rises to CLAIMED letter by letter with the places measured again, and a lime line draws under the whole address.
| Name | File | Default | What it changes |
|---|---|---|---|
MORPH | script.js | 0.5 | The seconds a letter takes to slide to its new place. |
RISE | script.js | 10 | How far below a new letter rises from, in pixels. |
STAGGER | script.js | 0.03 | The seconds between one new letter and the next. |
QUIET | script.js | 0.45 | The seconds of quiet after the last key before the name is checked. |
CHECK | script.js | 0.6 | How long the pretended check of a name takes, in seconds. |
WAIT | script.js | 0.7 | How long the pretended claiming takes, in seconds. |
CLAIMED | script.js | 700 | The weight the letters take once the name is yours. |
TAKEN | script.js | ['nora', 'mira', 'sam', 'alex', 'studio', 'hello', 'design', 'photo', 'anna', 'luca', 'maker', 'shop'] | The names already taken in this demo. |
In the sign-up of a service where everyone has an address: personal pages, portfolios, shops on a platform, profiles, links in bio. It also works as the first step of a landing page, where choosing the name is the gesture that signs you up. The morph shows what happens to the name as you write it, without error messages for a capital or a space.
The field takes the width of the screen (358 pixels on a 390 phone), 60 pixels tall, with the letters at 17 pixels (the input stays above 16, so Safari does not zoom); the button stays inside the field. The keyboard’s Enter key says Go and claims. A name longer than the room scrolls and the drawn letters scroll with it. The pills of the free names wrap if needed and are 34 pixels tall.
The letters do not slide, drop or rise: they fade in and out, already in place. The checking line does not run, the strike of a taken name and the line under a claimed one appear at once; the messages change with a fade.
GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 10 KB; the libraries: GSAP 28 KB.
Tested on 19 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.