Skip to content
animorio
IT
Back to the library

A number made of marks

Scroll, TextGSAP, CanvasAdvancedCompressed weight: Demo 9.2 KBGSAP + ScrollTrigger 45 KBFreeDownload the zip

Scroll inside the preview

A studio’s hundred clients in a single number: as you scroll, the “100” opens into a hundred thin marks cut to the shape of the digits, which line up in tens, fold into a ten by ten grid, lie down into one bar per year and in the end close back into the number. Minimal style.

The code

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>A number made of marks</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>
  <!-- the clients of a made-up design studio, told with one big number. Scrolling, the number comes apart into one
       thin mark per client: the marks line up in tens, fold into a ten by ten grid, lie down into one bar per year,
       and in the end stand up again into the number -->
  <main>
    <section class="apertura">
      <p class="piccolo">Orrin, design studio</p>
      <h1 class="titolo">Five years,<br>one client at a time.</h1>
      <p class="piccolo piccolo--tenue">Scroll to count them.</p>
    </section>

    <section class="racconto" data-racconto>
      <div class="palco" data-palco>
        <header class="testa">
          <p class="marchio">Orrin</p>
          <p class="piccolo piccolo--tenue">Clients since <span data-dal>2021</span></p>
        </header>

        <h2 class="nascosto" data-numero>100 clients since 2021</h2>
        <canvas class="tela" data-tela aria-hidden="true"></canvas>
        <div class="anni" data-anni aria-hidden="true"></div>

        <p class="didascalia" aria-hidden="true">
          <span class="didascalia__riga" data-dida>A hundred clients.</span>
          <span class="didascalia__riga" data-dida>One mark for each.</span>
          <span class="didascalia__riga" data-dida>Ten to a row.</span>
          <span class="didascalia__riga" data-dida>Year by year.</span>
          <span class="didascalia__riga" data-dida>And counting.</span>
        </p>
      </div>
    </section>

    <section class="apertura apertura--fine">
      <h2 class="titolo titolo--medio">Thank you,<br>every one of you.</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>

Playground

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.

31 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “A number made of marks” from Animorio and fit it into my site

What it does

The clients of a made-up design studio, Orrin, on a warm white with black ink and a single blue. The screen stops on a huge, solid “100”. As you scroll, the number opens from left to right into a hundred thin vertical lines, one per client: each line is cut where it crosses the digit, so the number still reads, made of lines; the last one, the newest client, turns blue. Then the lines let go of the digits: they all stretch or shrink to the same length and line up in groups of ten, like tally marks, going a little too far as they arrive and settling. The groups drop one under the other and become a ten by ten grid. Then the marks lie down and fly to pile up into one bar per year: under the baseline the years rise out of a slot, and above every bar the count climbs as the marks land; the blue one ends on top of the last year. In the end the marks stand up again, go back to their columns, thicken all together until they close the number, which lands with a small elastic squash. At the bottom a single line changes its sentence at every step. Everything follows the scroll, forwards and backwards.

How it works

The digits read column by column

The script writes the number once on a canvas outside the page, at twice the size, and reads its pixels. It keeps only the columns that have ink (so no mark falls between two digits) and picks as many as there are clients, evenly spaced. For each one it notes where the column enters and leaves the ink: a column through a zero has two pieces, above and below the hole.

Five shapes for every mark

Every mark is a line through a point, at an angle, cut into K pieces along its length. Five shapes are prepared for every mark: the solid number, the number in lines, the row of tens, the grid and the bar of its year. Outside the number the K pieces lie on top of each other, so going from one shape to another only means blending numbers: position, angle, the ends of the pieces, thickness, how blue it is.

Five numbers and a delay

The timeline, tied to the scroll with scrub SCRUB, only moves five numbers from 0 to 1, one per change of shape, plus the one for the final squash. Every mark starts a little after the one before it (SPREAD) and uses different curves for its parts: power3.inOut for the flight, power2.inOut for turning, LAND for the length, which goes a little too far and settles. The drawing happens once per frame, in GSAP’s ticker.

The number from the lines, without steps

While they are inside the number, the marks are drawn on a second canvas outside the page, twice as wide as the gap between two lines and a little longer than they need to be; then the number is written over them with destination-in, which keeps only what is inside the digits. So the thickening lines become a number with smooth edges and not steps, and the real number can appear on top without the switch showing.

Years, counts and captions

The years and the counts are HTML elements over the canvas. The years rise out of an overflow hidden window with yPercent, while the --wd variable takes font-stretch from 70% to 100% (Archivo is variable in width too). Every count shows how many marks of its year have already landed and rises with the top of the bar. The caption at the bottom plays the same game as the years, one sentence at a time.

Values to change

NameFileDefaultWhat it changes
COUNTSscript.js[8, 14, 21, 26, 31]The new clients of every year, oldest first: one mark each, one bar per year, and their sum is the big number.
FIRST_YEARscript.js2021The year of the first bar.
WEIGHTscript.js800The weight of the big number: the fuller it is, the better the lines tell the shape of the digits.
LINEscript.js1.5How thick a mark is, in pixels.
LANDscript.js'back.out(2.2)'The curve each mark takes its length with: the number in brackets is how far it overshoots before settling.
SPREADscript.js0.55How far apart the marks leave: 0 all together, 0.9 one after the other.
SCRUBscript.js0.6How many seconds the drawing takes to catch up with the scroll.

Try them in the Playground

When to use it

For a number that counts people or things one by one: a studio’s clients, delivered projects, the members of a club, the seats sold for an event. It works up to a few hundred: there is one mark per unit, so with thousands of pieces the grid and the bars would no longer read.

On phones

The same, with adapted measures: the number takes almost the whole width, the row of tens goes on two lines and the bars get narrower.

With reduced motion

No flights and no bounces: at every step the drawing fades out and comes back already in its new shape (number in lines, row, grid, bars, solid number); captions and years take turns with a cross-fade.

Pitfalls

  • A canvas inside the page picks up some of the page’s type settings (here the tabular figures of font-feature-settings): the number written there sat two or three pixels away from the one read on the canvas outside the page, and at the end a shadow showed next to the digits. The number is written only on canvases outside the page, and the visible one copies their image.
  • Lines as wide as the gap between columns do not close the number: every column is measured at its centre, and on straight edges and curves gaps of half a column were left. The solid lines are twice as wide and a little longer, and the destination-in cut brings them back inside the digits.
  • If the real number appears while the last marks are still flying, a ghost number shows through. On the way back the marks fly during the first part of the step and only then, all still, they thicken and hand over to the number.
  • The canvas must be measured again on every ScrollTrigger refresh and after the font has arrived (document.fonts.load): measured with the fallback font, the columns ended up outside the real digits.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Archivo (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 9.2 KB; the libraries: GSAP + ScrollTrigger 45 KB.

Testing

Tested on 14 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

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.

All animations