
The cookie banner
Consent, Transitions, SVG, Physics
NewFree
A made-to-measure shirt order sewn by hand on a strip of navy wool: going on, the needle runs a seam to the next step, slips under it while its ring closes and the step left behind is embroidered in satin stitch; going back, the seam jumps off as one rippling thread and is yanked back; at the end the thread is pulled, the cloth gathers into folds, the thread is cut and the cloth springs back.
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 needle and thread steps</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/encode-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the steps of a made-to-measure shirt order, sewn by hand on a strip of navy wool. Going on, the needle goes
into the cloth and runs a seam of stitches to the next step, slips under its patch (the ring closes round it)
and the step left behind is embroidered in satin stitch. Going back, the needle lifts and slides back, the
stitches come out and the loose thread whips. At the end the seam is knotted, the thread pulled until the
cloth gathers, then cut: the cloth springs back -->
<div class="order" data-order data-autoclic>
<div class="strip" data-strip>
<span class="strip__cloth" aria-hidden="true" data-cloth></span>
<svg class="strip__under" aria-hidden="true" data-under></svg>
<ol class="steps" aria-label="Shirt order" data-steps>
<li class="step" data-step>
<button class="step__hit" type="button" data-hit>
<svg class="step__patch" viewBox="0 0 40 40" aria-hidden="true">
<circle class="step__chalk" cx="20" cy="20" r="17.5"/>
<g class="step__satin" data-satin></g>
<path class="step__ring" d="M2.5 20A17.5 17.5 0 0 1 37.5 20" data-ring/>
<path class="step__ring" d="M2.5 20A17.5 17.5 0 0 0 37.5 20" data-ring/>
<g class="step__icon" transform="translate(9 9) scale(0.9167)">
<path d="M5.5 5h13v10.6l-1.63 1.65-1.62-1.65-1.63 1.65-1.62-1.65-1.63 1.65-1.62-1.65-1.63 1.65-1.62-1.65z"/>
<path d="M8.6 12.6l4.6-4.6M12.4 12.6l3-3"/>
</g>
</svg>
<span class="step__name" data-name>Fabric</span>
</button>
</li>
<li class="step" data-step>
<button class="step__hit" type="button" data-hit>
<svg class="step__patch" viewBox="0 0 40 40" aria-hidden="true">
<circle class="step__chalk" cx="20" cy="20" r="17.5"/>
<g class="step__satin" data-satin></g>
<path class="step__ring" d="M2.5 20A17.5 17.5 0 0 1 37.5 20" data-ring/>
<path class="step__ring" d="M2.5 20A17.5 17.5 0 0 0 37.5 20" data-ring/>
<g class="step__icon" transform="translate(9 9) scale(0.9167)">
<path d="M8.4 4.2 4.6 6 2.8 11.2l2.9 1.1 1.2-2.6v10h10.2v-10l1.2 2.6 2.9-1.1L19.4 6l-3.8-1.8"/>
<path d="M8.4 4.2 9.6 9 12 7.4l2.4 1.6 1.2-4.8C13.4 5.2 10.6 5.2 8.4 4.2zM12 7.4v12.3"/>
</g>
</svg>
<span class="step__name" data-name>Collar</span>
</button>
</li>
<li class="step" data-step>
<button class="step__hit" type="button" data-hit>
<svg class="step__patch" viewBox="0 0 40 40" aria-hidden="true">
<circle class="step__chalk" cx="20" cy="20" r="17.5"/>
<g class="step__satin" data-satin></g>
<path class="step__ring" d="M2.5 20A17.5 17.5 0 0 1 37.5 20" data-ring/>
<path class="step__ring" d="M2.5 20A17.5 17.5 0 0 0 37.5 20" data-ring/>
<g class="step__icon" transform="translate(9 9) scale(0.9167)">
<path d="M3.9 15.6 15.6 3.9l4.5 4.5L8.4 20.1z"/>
<path d="M7.4 12.1l1.8 1.8M10 9.5l1.2 1.2M12.6 6.9l1.8 1.8"/>
</g>
</svg>
<span class="step__name" data-name>Fit</span>
</button>
</li>
<li class="step" data-step>
<button class="step__hit" type="button" data-hit>
<svg class="step__patch" viewBox="0 0 40 40" aria-hidden="true">
<circle class="step__chalk" cx="20" cy="20" r="17.5"/>
<g class="step__satin" data-satin></g>
<path class="step__ring" d="M2.5 20A17.5 17.5 0 0 1 37.5 20" data-ring/>
<path class="step__ring" d="M2.5 20A17.5 17.5 0 0 0 37.5 20" data-ring/>
<g class="step__icon" transform="translate(9 9) scale(0.9167)">
<path d="M5.5 6.5h13a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2z"/>
<path d="M3.5 10.2h17M7 14.4h3.6"/>
</g>
</svg>
<span class="step__name" data-name>Payment</span>
</button>
</li>
</ol>
<!-- the needle and the loose thread, drawn by the script -->
<svg class="strip__over" aria-hidden="true" data-over></svg>
</div>
<div class="foot">
<p class="foot__say" aria-live="polite"><span class="foot__line" data-say>Choose the cloth for your shirt</span></p>
<div class="foot__keys">
<button class="key key--back" type="button" data-back>
<span class="key__bg" aria-hidden="true"></span>
<span class="key__clip"><span class="key__text">Back</span></span>
</button>
<button class="key key--next" type="button" data-next>
<span class="key__bg" aria-hidden="true"></span>
<span class="key__clip"><span class="key__text" data-next-text>Continue</span></span>
</button>
</div>
</div>
</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.
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 needle and thread steps” from Animorio and fit it into my siteOver and under the steps are two SVGs the script draws again on every frame, only while something moves. Each seam has one number, how far it is sewn: its stitches, spread evenly from one ring to the next, are written as strokes up to there, and the chalk shows only beyond. The ring is two arcs that leave from nine o’clock and meet at three: each arc is a row of stitches written into a stroke-dasharray that stops where the ring has got to. The satin stitch is a row of slanting lines, each revealed with stroke-dashoffset, one after the other and each the other way round from the last, like the needle going to and fro.
The needle is a steel spindle with a gradient and its eye, and a blurred shadow. Sewing, GSAP carries it along the line and the eye decides how far the seam has got; at every gap between two stitches the tip goes into the cloth: a clipPath hides the part inside, on a sine curve, while the shadow comes closer. Under the next step’s patch the same clipPath hides the stretch passing underneath, and the ring closes as the eye goes through. Stuck in the cloth, the shadow is no longer moved as a whole but slanted with a matrix: it touches the needle at the tip and leaves it towards the eye, which stays raised.
The thread between the ring and the eye is a string of 36 points worked out in steps of 1/120 of a second (verlet), with the frame step capped at 1/30: each point has a little weight towards the bottom of the strip, the string is stretched between its two ends and each point leans towards the middle of its neighbours, so it bends in soft curves instead of zigzags. Going back, the seam disappears and in its place the string lies along the same line with a push in waves; the needle is pulled back on a curve that speeds up while the string’s length shrinks more slowly: the spare thread ripples and is wound in until the usual loop is back.
At the end the strip becomes a chain: one weight for each step, plus the end, joined by springs that are soft when squeezed (the wool folds) and stiff when stretched (the wool does not give), with the start held by the knot. Pulling the thread shortens the rest length of every spring down to GATHER: the steps crowd to the left, the cloth shortens with scaleX, the patches squash with the scale property, the names narrow with font-stretch on the font’s wdth axis and between each pair of weights two folds come up, dark gradients whose opacity follows how squeezed the cloth is. Once the thread is cut the springs are long again and the cloth opens up to the small jolt of the stiff spring.
The steps are an ordered list, the current one has aria-current step; the steps done are buttons that go back, the others are disabled, and each has an aria-label saying whether it is done, current or still to do. Every press counts: the moves wait their turn (three at most) and the one playing speeds up; while the order is being placed Continue waits. With reduced motion the needle does not travel: it fades out and back in at its new place, and only the stitches, rings and embroidery that change fade. The library’s preview clicks the component (a click with no hand): on, on, back, on to the order and a new one.
| Name | File | Default | What it changes |
|---|---|---|---|
STITCH | script.js | 7 | The length of a stitch on the cloth, in pixels (the gaps are about half as long). |
SEW | script.js | 0.05 | The seconds the needle takes for each stitch, going on. |
UNPICK | script.js | 0.42 | The seconds the thread takes to come out of one seam, going back. |
GATHER | script.js | 0.86 | How short the cloth gets when the thread is pulled at the end (1: it does not gather). |
SPRING | script.js | 1 | How lively the cloth is when it springs back after the cut (0.5 calm, 2 rubbery). |
SLACK | script.js | 9 | The loose thread between the ring and the needle at rest, in pixels. |
LINES | script.js | ['Choose the cloth for your shirt', 'Pick a collar to go with it', …] | The line under the strip, one for each step. |
DONE | script.js | 'Order placed. Cutting starts Monday' | The line once the order is placed. |
For a procedure in a few steps that should feel crafted: a made-to-measure order, a configurator, signing up, a purchase in a makers’ shop. The thread says how far you have got, what is done stays embroidered, and the end really feels finished.
The strip takes the width of the screen less 16 pixels a side (358 on a 390 phone) and stays 84 tall: the steps stay in a row with their icons, the names drop to 12.5 pixels and never touch, the seams between two steps have four stitches instead of nine. The line goes on top, centred, and Back and Continue share the width, 44 pixels tall. Each step done takes a tap over its whole column.
The needle does not travel and the thread does not ripple: the needle fades out of its place and back in at the new one, and only the seams, rings and embroidery that change fade, while the rest stays still. At the end no gathering and no light on the silk: the last seam, the cut end and the upright needle fade in. The buttons do not swell, only their edge and colour change.
GSAP 3.15.0, Encode Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 19 KB; the libraries: GSAP 28 KB.
Tested on 6 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.