
The star rating
Ratings, SVG, Hover
NewFree
In the minimal style, on white: the Save for later of a recipe site, with a small wooden clothespin clipped on the edge of the pill. Under the pointer the pin leans and parts its jaws a little. Pressed, the pin opens round its steel spring, a paper tag slides into the jaws and the pin snaps shut on it: Saved. Pressed again, it lets the tag go.
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 clothespin button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the clothespin button: the Save for later of a recipe site, on white. A small beech clothespin is clipped on
the top edge of the pill. Pressed, the pin opens, a paper tag slides into its jaws and the pin snaps shut on it:
Saved. Pressed again, the pin lets the tag go -->
<div class="pin" data-pin>
<div class="pin__frame" data-frame>
<svg class="pin__art" viewBox="-60 -110 120 150" aria-hidden="true" data-art>
<defs>
<linearGradient id="legno" x1="0" x2="1" y1="0" y2="0">
<stop offset="0" stop-color="#c79f6c"/>
<stop offset="0.35" stop-color="#e3c595"/>
<stop offset="0.7" stop-color="#d6b27f"/>
<stop offset="1" stop-color="#b98d58"/>
</linearGradient>
<linearGradient id="acciaio" x1="0" x2="0" y1="0" y2="1">
<stop offset="0" stop-color="#e9ecef"/>
<stop offset="0.45" stop-color="#9aa1a8"/>
<stop offset="1" stop-color="#5d646b"/>
</linearGradient>
<filter id="morbida" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="2.4"/></filter>
</defs>
<g data-tag class="pin__tag">
<rect x="-22" y="-10" width="44" height="58" rx="2.5" class="pin__tag-carta"/>
<rect x="-22" y="40" width="44" height="2.6" class="pin__tag-riga"/>
<text x="0" y="29" text-anchor="middle" class="pin__tag-testo">SAVED</text>
</g>
<ellipse cx="3" cy="8" rx="18" ry="5" class="pin__ombra" filter="url(#morbida)" data-shadow/>
<g transform="scale(1.6 1)">
<path class="pin__notch" d="M-3 -1 L3 -1 L3 5 L-3 5 Z M-0.8 5 L0.8 5 L0.8 17 L-0.8 17 Z"/>
<g data-arm="l" class="pin__arm">
<path class="pin__wood" d="M -8.2 -96 C -13.4 -95 -14.41 -88 -13.23 -78 L -8.2 -22 C -8 -14 -9.6 -8 -9.4 -2 L -8.4 14 C -8.2 17 -6.4 18.6 -3.8 18.2 L -0.6 17.4 L -0.6 8 L -3.4 5 L -3.4 -1 L -0.6 -4 L -0.6 -33 Z"/>
<path class="pin__grain" d="M -11.62 -86 C -9.26 -60 -6.09 -40 -6.2 -24 M -9.81 -90 C -8.04 -70 -5.08 -50 -4.2 -30 M -7.2 0 C -7 6 -6.8 10 -6.4 14"/>
<path class="pin__edge" d="M -8.1 -95 L -0.6 -4"/>
</g>
<g data-arm="r" class="pin__arm">
<path class="pin__wood" d="M 8.2 -96 C 13.4 -95 14.41 -88 13.23 -78 L 8.2 -22 C 8 -14 9.6 -8 9.4 -2 L 8.4 14 C 8.2 17 6.4 18.6 3.8 18.2 L 0.6 17.4 L 0.6 8 L 3.4 5 L 3.4 -1 L 0.6 -4 L 0.6 -33 Z"/>
<path class="pin__grain" d="M 11.62 -86 C 9.26 -60 6.09 -40 6.2 -24 M 9.81 -90 C 8.04 -70 5.08 -50 4.2 -30 M 7.2 0 C 7 6 6.8 10 6.4 14"/>
<path class="pin__edge pin__edge--r" d="M 8.1 -95 L 0.6 -4"/>
</g>
<g class="pin__spring" data-spring>
<path class="pin__wire" d="M-10.5 -40 C-13 -44 -12 -50 -9.6 -52 M10.5 -40 C13 -44 12 -50 9.6 -52"/>
<rect x="-11.5" y="-40" width="23" height="9" rx="4.5" class="pin__coil"/>
<path class="pin__turns" d="M-7.5 -40 V-31 M-4 -40 V-31 M-0.5 -40 V-31 M3 -40 V-31 M6.5 -40 V-31"/>
<path class="pin__shine" d="M-9.5 -38.4 H9.5"/>
</g>
</g>
</svg>
<button class="pin__btn" type="button" data-btn data-autoclic aria-pressed="false">
<span class="pin__words">
<span class="pin__word" data-word="rest" data-rest-text>Save for later</span>
<span class="pin__word pin__word--done" data-word="done" aria-hidden="true" data-done-text>Saved</span>
</span>
</button>
</div>
<p class="pin__note" data-note>Lemon tart · 35 min</p>
<p class="sr" aria-live="polite" data-live></p>
</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.
18 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 clothespin button” from Animorio and fit it into my siteThe pin is two mirrored arms, each one path with the handle, the jaw and the notch, filled with a beech gradient and marked by three thin grain lines and a light edge; between them the spring is a rounded steel rectangle with five turns and a highlight. A group widens them one and a half times, so the pin stays a single drawing to move.
The two arms turn round the same point, the centre of the spring, one by plus degrees and the other by minus degrees: GSAP moves a single number, open, and on every step applies it to both arms with svgOrigin and squeezes the spring in width. Opening is open to OPEN in two tenths with power2.out, closing is open to zero in SNAP seconds with back.out(3), which goes past zero and makes the snap.
The tag is drawn behind the arms: it comes in from 46 units higher and 14 degrees askew, slides down in 0.34 seconds with power3.out while the pin is open, and when the pin closes it swings to minus 2 degrees with elastic.out. Meanwhile the whole pin drops a pixel and springs back.
Archivo has width and weight axes: under the pointer the words go to width 108; Saved comes in wide at 124 and weight 300 and lands at 100 and 520 with back.out, while the small line changes with a fade.
It is a real button with aria-pressed, and an aria-live line announces Saved; the keyboard focus ring shows only with the keyboard. While it moves, clicks are ignored. With reduced motion the tag fades in and out and the pin stays still.
| Name | File | Default | What it changes |
|---|---|---|---|
LABEL | script.js | Save for later | The words at rest. |
DONE | script.js | Saved | The words once the tag is pinned. |
NOTE | script.js | Lemon tart · 35 min | The small line under the pill. |
NOTE_DONE | script.js | In your recipe box | The small line once the tag is pinned. |
OPEN | script.js | 6 | How many degrees each arm of the pin opens. |
SNAP | script.js | 0.24 | The seconds of the snap that closes the pin. |
TILT | script.js | 7 | How far the pin leans on the pill, in degrees. |
For a button that puts something aside: a recipe saved for later, a product in favourites, an article bookmarked, a listing to keep an eye on.
The pill narrows to 42 pixels from the edges and the pin stays clipped on the right. A tap pins and lets go of the tag like a click; the hover lean happens only with a mouse.
The pin stays still, the tag fades in and out and the words swap without bounces.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 4.6 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.