
The send button
Buttons, Transitions, SVG
NewFree
A confirmation dialog in the minimal style, drawn by a single thread: the outline of the Archive project button is the end of a thin line that, when pressed, leaves the button with a vermilion tip, climbs and runs all the way round the window, while the button unwinds to feed it; when the loop closes the window settles by a pixel and the words light up one after another. Cancel winds the thread back into the button, Archive closes the window into a line that tightens back into the button, now Archived.
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 dialog drawn on a thread</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" data-stage>
<!-- the dialog drawn on a thread: the button's outline is the end of one thin thread. Pressed, the thread runs out
of the button and draws the window round; Cancel winds it back into the button, Archive closes the window into
a single line that tightens into the button, now done -->
<span class="slot" data-slot data-autoclic>
<button class="opener" type="button" aria-haspopup="dialog" aria-controls="archive-dialog" data-open>
<span class="opener__fill" aria-hidden="true"></span>
<span class="opener__face">
<span class="opener__label opener__label--size" aria-hidden="true" data-size></span>
<span class="opener__label" data-rest>Archive project</span>
<span class="opener__label opener__label--done" aria-hidden="true" data-done>
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.6l4.3 4.3L19 7.4" data-tick/></svg>
<span>Archived</span>
</span>
</span>
</button>
<span class="slot__under">
<button class="undo" type="button" hidden data-undo>Undo</button>
</span>
</span>
</main>
<div class="veil" data-veil></div>
<div class="layer">
<div class="box" id="archive-dialog" role="dialog" aria-modal="true" aria-labelledby="archive-title" aria-describedby="archive-text" data-box>
<div class="box__paper" data-paper></div>
<div class="box__body">
<h2 class="box__title" id="archive-title" data-title>Archive this project?</h2>
<p class="box__text" id="archive-text" data-part><strong>Brightwell rebrand</strong> leaves your workspace with its files and comments. You can restore it from Archive at any time.</p>
<div class="box__rule" aria-hidden="true" data-rule></div>
<div class="box__actions">
<button class="act act--ghost" type="button" data-part data-cancel>Cancel</button>
<button class="act act--ink" type="button" data-part data-confirm>Archive</button>
</div>
</div>
</div>
</div>
<svg class="thread" aria-hidden="true" data-thread>
<path class="thread__ink" d="" data-ink/>
<path class="thread__tip" d="" data-tip/>
</svg>
<p class="sr" aria-live="polite" data-live></p>
<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.
23 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 dialog drawn on a thread” from Animorio and fit it into my siteThe thread is a single SVG path in a layer as big as the screen, rebuilt at every frame in pixels: the button’s outline (a pill run clockwise from the top), the stretch that climbs from the top of the button to the top of the window (straight, or an S with upright ends if they are not in line) and the window’s outline (a rounded rectangle that starts and ends at the same point). The lengths are worked out exactly: sides plus quarter circles, 2πr for the corners.
The part that shows is a single stroke-dasharray dash, moved with stroke-dashoffset: the front end goes from the end of the button to the end of the window (u), the back end from the start of the button to the start of the window (v), leaving a moment later. Both runs are fractions worked out again on that frame’s lengths, so a resize half way through the drawing moves nothing. The vermilion tip is the same path with a TIP pixel dash in front of the end.
Where the loop closes, two butt-ended strokes leave a hair of gap: the first loop starts a pixel and a half before its point, the last one ends a pixel and a half past it, and the two overlap. As soon as it closes, the outline grows by 1.4 pixels and comes back with elastic.out: the settling.
The title is split into letters (the words never break): each comes from wdth 72 and wght 300 to wdth 100 and wght 640, with back.out for a pixel of overshoot, one every LETTERS seconds. Then the sentence, the thin rule (scaleX from the left) and the two buttons, rising by 8 pixels with back.out. The button’s words use a --w variable inside font-variation-settings, and an unseen copy of the words, as wide as under the mouse, keeps the button always the same size: the outline never moves.
With Archive the window’s outline changes shape instead of unwinding: its top and bottom sides meet in the line through the middle of the button (power3.in), the line holds for an instant, tightens to the button’s width and opens to its height with back.out(1.1), a pixel past it. When it matches the button, the same drawing passes to the thread’s first piece without the change showing.
The window has role dialog and aria-modal, the button aria-haspopup and aria-expanded. Opening, the page behind becomes inert and the focus goes to Cancel; Tab goes round Cancel and Archive, Esc and a click outside cancel. As soon as it closes the window stops answering and the focus goes back to the button (or to Undo), even while the thread is still moving. An aria-live region says archived and back. A click from a script (the library’s preview) makes a whole round in a GSAP timeline: open, cancel, open again, archive, Undo.
| Name | File | Default | What it changes |
|---|---|---|---|
DRAW | script.js | 1.05 | The seconds the thread takes to run out of the button and draw the window. |
REWIND | script.js | 0.7 | The seconds the thread takes to wind back into the button on Cancel. |
FOLD | script.js | 0.8 | The seconds the window takes to close into a line and become the done button. |
TIP | script.js | 30 | The length of the coloured tip that leads the thread, in pixels. |
PEEK | script.js | 8 | How far the end of the thread sticks out of the button on hover, in pixels. |
DIM | script.js | 0.05 | How much the page darkens behind the window, from 0 to 1. |
LETTERS | script.js | 0.018 | The seconds between one letter of the title and the next. |
RADIUS | script.js | 20 | The corner radius of the window, in pixels. |
For confirming an action that can still be undone: archiving a project, moving an order, leaving a workspace, cancelling a booking. It suits apps and dashboards made of thin lines, and the button that draws itself works as an invitation too.
The window takes the whole width less 16 pixels a side, and the thread takes the same path. Under the finger the button’s fill swells and the end of the thread sticks out, as with the mouse; a tap outside cancels.
The thread does not run: the button’s outline and words fade, then the window appears in their place already drawn, with the words still; closing does the opposite, and Archived with its tick fades in. Nothing moves and the two never show together.
GSAP 3.15.0, Mona Sans (font variabile, assi wght e wdth) 5.3.0.
Compressed with gzip, the three demo files weigh 10 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.