
Words that melt into each other
Text, Scroll, SVG
NewFree
Scroll inside the preview
A ceramics studio’s year of sales drawn by a single thin line: as you scroll, the flat line bends point by point into the chart of the twelve months, the month ticks drop out under it, the three figures that matter rise above their peaks and take their weight on a spring, and the last point lights up in blue. Minimal style.
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 line that bends into a chart</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/standard.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- the year of a made-up ceramics studio drawn by a single thin line. Scrolling down, the flat line bends point
by point into the chart of the twelve months, the month ticks drop out from under it, the three figures that
matter rise above their peaks gaining weight on a spring, and the last point lights up in the accent -->
<main>
<section class="apertura">
<p class="piccolo">Kilnworth ceramics</p>
<h1 class="titolo">A whole year<br>on one line.</h1>
<p class="piccolo piccolo--tenue">Scroll down</p>
</section>
<section class="racconto" data-racconto>
<div class="palco">
<header class="testa">
<p class="marchio">Kilnworth</p>
<p class="piccolo piccolo--tenue">Pieces sold in 2025</p>
</header>
<div class="scena" data-scena>
<svg class="tela" data-tela aria-hidden="true">
<path class="tela__base" data-base />
<g data-tacche></g>
<path class="tela__riga" data-riga />
<path class="tela__accento" data-ultima />
<circle class="tela__punto" data-punto r="0" />
</svg>
<div class="mesi" data-mesi aria-hidden="true"></div>
<figure class="cima" data-cima data-mese="4">
<i class="cima__quota" aria-hidden="true"></i>
<div class="cima__corpo">
<figcaption class="cima__dida"><span data-dida>Spring fair</span></figcaption>
<p class="cima__numero" data-numero></p>
</div>
</figure>
<figure class="cima" data-cima data-mese="8">
<i class="cima__quota" aria-hidden="true"></i>
<div class="cima__corpo">
<figcaption class="cima__dida"><span data-dida>New glaze</span></figcaption>
<p class="cima__numero" data-numero></p>
</div>
</figure>
<figure class="cima cima--ultima" data-cima data-mese="11">
<i class="cima__quota" aria-hidden="true"></i>
<div class="cima__corpo">
<figcaption class="cima__dida"><span data-dida>Best month yet</span></figcaption>
<p class="cima__numero" data-numero></p>
</div>
</figure>
</div>
</div>
</section>
<section class="apertura apertura--fine">
<h2 class="titolo titolo--medio">Thank you for<br>a good year.</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.
35 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 line that bends into a chart” from Animorio and fit it into my siteThe sales of every month are a list, SALES, at the top of the script: the highest value sets the scale. Each month becomes a point with its x (the twelve points spaced evenly between the two margins) and a y going from the baseline up to the height of its value. The three figures above the peaks are in the HTML with data-mese, the month’s position from 0 to 11: the script writes the figure, taking it from the list.
The timeline, tied to the scroll with scrub SCRUB, moves numbers from 0 to 1: how much of the line is drawn, how far each point has risen, how far each tick has dropped, the final accent. On every update a single function redraws everything: the d attribute of the line’s path (a polyline cut where the pen has got to), the one of the light trace below, the ticks and the positions of the month names and figures.
Each point’s tween is linear, and the BEND curve (back.out) is applied while drawing, with gsap.parseEase: so the point goes a hair past its height and comes back down the same way every time, both scrolling down and back up. Each point starts STAGGER after the one before, so the bend runs from January to December like a wave.
Each tick is a small vertical path that starts from the baseline and drops DROP pixels along bounce.out, a moment after its point has left the line; the month name below fades in moving down six pixels. On a phone the names become initials.
Each digit sits in a window with overflow: hidden and rises from below with a stagger. The whole figure has two CSS variables, --wg (font-weight) and --wd (the wdth axis in font-variation-settings): they start from LIGHT and 70 and reach HEAVY and 100 along the LAND curve, an elastic that takes them past and back. The colour of the last figure goes from black to blue with gsap.utils.interpolate together with the final point.
| Name | File | Default | What it changes |
|---|---|---|---|
SALES | script.js | [84, 102, 96, 148, 212, 176, 131, 158, 264, 221, 238, 341] | The sales of every month, January to December: the highest sets the scale. |
BEND | script.js | 'back.out(1)' | The curve of each point rising: the number is how far it goes past before settling. |
STAGGER | script.js | 0.45 | How long each point waits after the one before it starts. |
DROP | script.js | 9 | How many pixels the month ticks drop under the line. |
LIGHT | script.js | 200 | The weight of a figure while it rises. |
HEAVY | script.js | 680 | The weight it lands on. |
LAND | script.js | 'elastic.out(1, 0.5)' | The spring of the figure taking its weight: a smaller second number means more shiver. |
SCRUB | script.js | 0.8 | How many seconds the drawing takes to catch up with the scroll. |
For a year’s numbers on an about page, in an annual report, on the page of an app or a shop that wants to show how it went: twelve values and two or three moments to tell. The values are changed in SALES and the figures above the peaks in the HTML (data-mese and the caption).
The same animations at adapted sizes: the chart takes the whole width with 26 pixel margins, the month names become initials, the figures are smaller and the ones near the edge move inwards so they never leave the screen (the dimension line stays on the point).
No movement: the chart is already drawn, with its ticks and months. Scrolling, the three figures fade in one after the other, then the last stretch, the last point and its figure light up in blue.
GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Roboto Flex (font variabile, assi wght e wdth) 5.3.0.
Compressed with gzip, the three demo files weigh 6.8 KB; the libraries: GSAP + ScrollTrigger 45 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.