
Standing letters with a long shadow
Text, Scroll, 3D
NewFree
Scroll inside the preview
A label mill weaves a word while you scroll, in the minimal style: the warp is a row of thin black threads between two beams, and every pick a vermilion weft runs from one side to the other, over the warp where the word is and under it everywhere else; the reed beats it into the cloth with a small knock. Row by row, from the bottom, the word comes out of the threads; at the end the warp is cut and the loose ends spring back up.
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 word on the loom</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>
<!-- a made-up mill of woven labels, Tessa, weaves a word while you scroll. The warp is a row of black hairlines
between two beams; every pick, a vermilion weft runs across, over the warp where the word is and under it
everywhere else, and the reed beats it into the cloth with a small knock. Row by row, from the bottom, the word
comes out of the threads; at the end the warp is cut and springs back to the top beam -->
<main>
<section class="apertura">
<p class="piccolo">Tessa, woven labels</p>
<h1 class="titolo">Your name,<br>one thread at a time.</h1>
<p class="piccolo piccolo--tenue">Scroll to weave it.</p>
</section>
<section class="racconto" data-racconto>
<div class="palco" data-palco>
<header class="testa">
<p class="marchio">Tessa</p>
<p class="piccolo piccolo--tenue">Jacquard labels, made to order</p>
</header>
<h2 class="nascosto" data-nome>A word woven on a loom</h2>
<svg class="telaio" data-telaio aria-hidden="true">
<g data-sotto></g>
<g data-ordito></g>
<g data-sopra></g>
<g data-telai></g>
</svg>
<div class="piede">
<p class="didascalia" aria-hidden="true">
<span class="didascalia__riga" data-dida>The warp is set.</span>
<span class="didascalia__riga" data-dida>Over, under, over, under.</span>
<span class="didascalia__riga" data-dida>Cut from the loom.</span>
</p>
<p class="misura"><span data-cm>0.0</span> cm woven</p>
</div>
</div>
</section>
<section class="apertura apertura--fine">
<h2 class="titolo titolo--medio">Sewn into the collar,<br>it outlasts the shirt.</h2>
</section>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/ScrollTrigger.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.
25 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 word on the loom” from Animorio and fit it into my siteThe script draws the word on a hidden canvas eight times bigger than the cloth, at weight 720 and in Mona Sans’ condensed width (written in the canvas font: «condensed 720 …px»), one letter at a time with a stitch and a half between them. Then every stitch of the cloth looks at the 8 by 8 pixels it covers: if more than half is ink, the weft goes over there. The word’s height, in picks, is the largest the width allows, plus MARGIN rows of plain cloth above and below.
In the SVG of the pinned stage (position: sticky, 100lvh tall) there are three groups one above the other: the weft running under, then the warp, then the weft floating over, which covers the threads. That way over and under really show. The rows already woven are a single path per layer, rebuilt only when a row closes; the one on the shuttle is redrawn every frame, up to the head of the weft.
The timeline, tied to the scroll with scrub SCRUB, carries a number from 0 to 1 that becomes the picks made. In every pick, for the first 72 per cent the weft runs (power1.inOut) with the reed raised by almost two rows, once from the left and once from the right; then the reed comes down on the BEAT curve, a back.out that takes it a pixel too far, and the weft, always just under it, goes into the cloth with it.
Every warp thread is two lines meeting just above the last row. At the cut the top part shortens up to the beam with an elastic.out, one thread after the other from the left, leaving a short fringe above the cloth; the cloth drops a pixel and a half and comes back. The captions at the bottom leave upwards through an overflow hidden window, widening on the wdth axis.
On every ScrollTrigger refresh and on every resize the script works out again the size of a stitch (half on a phone), how many columns fit the width, the height of the word and of the beams, and redraws the stitch map. That is why the timeline works in fractions of the cloth and not in rows: if the number of rows changes, the scroll does not break.
| Name | File | Default | What it changes |
|---|---|---|---|
WORD | script.js | 'WOVEN' | The word on the label: short, in capitals. |
CELL | script.js | 12 | The size of a stitch in pixels (half on a phone): the smaller it is, the finer the word. |
MARGIN | script.js | 4 | The rows of plain cloth above and below the word. |
BEAT | script.js | 'back.out(1.6)' | How the reed beats every pick: the number in brackets is how far it goes past. |
LENGTH | script.js | 10 | How much scroll the weaving takes, in steps of the story. |
SCRUB | script.js | 0.6 | How many seconds the drawing takes to catch up with the scroll. |
For a clothing brand, a tailor, a weaving mill, a fabric or yarn shop, or for the page that tells how a handmade product is made: the name is born before your eyes, one thread at a time.
The same, with adapted measures: the stitches are half the size, so enough columns fit the phone’s width for a readable word; the caption and the centimetres go one under the other.
No runs and no beats: every row fades in whole, there is no reed, the warp fades in and at the cut the top part of the threads fades instead of springing; the captions cross-fade.
GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Mona Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 6.9 KB; the libraries: GSAP + ScrollTrigger 45 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.