Skip to content
animorio
IT
Back to the library

The figures that light up

Scroll, TextGSAP, CSS onlyEasyCompressed weight: Demo 6.6 KBGSAP + ScrollTrigger 45 KBFreeDownload the zip

Scroll inside the preview

Four pale cards with a figure each, which counts up from zero as it arrives. Then the scroll lights them one at a time: the pale veil lifts off a room, the words turn white and the card before goes back to sleep.

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>The figures that light up</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/instrument-serif@5.3.0/index.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/instrument-serif@5.3.0/400-italic.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-condensed@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the about section of a made-up interior studio. Four pale cards with a figure each count up from zero when they
       arrive; then, as you scroll, one card at a time lights up: the pale veil lifts off a room and the words turn
       white, and the card before goes back to sleep -->
  <main>
    <section class="apertura">
      <p class="etichetta">The studio</p>
      <h1 class="titolo">Nothing in a room<br>is there by chance.</h1>
      <p class="testo">Scroll down to read us in four figures.</p>
    </section>

    <section class="racconto" data-racconto>
      <div class="palco">
        <header class="testa">
          <p class="etichetta etichetta--parentesi">
            <svg viewBox="0 0 6 16" aria-hidden="true"><path d="M5 1H1v14h4" fill="none" stroke="currentColor" stroke-width="1"/></svg>
            in figures
            <svg viewBox="0 0 6 16" aria-hidden="true"><path d="M1 1h4v14H1" fill="none" stroke="currentColor" stroke-width="1"/></svg>
          </p>
          <h2 class="titolo titolo--medio">About us.</h2>
        </header>

        <div class="finestra" data-finestra>
          <ol class="carte" data-carte>
            <li class="carta" data-carta>
              <div class="carta__stanza" data-stanza="5"></div>
              <div class="carta__buio"></div>
              <div class="carta__velo" data-velo></div>
              <p class="carta__testo" data-testo><span>Years in Seville</span><b class="carta__cifra" data-cifra="12">12</b></p>
            </li>
            <li class="carta" data-carta>
              <div class="carta__stanza" data-stanza="18"></div>
              <div class="carta__buio"></div>
              <div class="carta__velo" data-velo></div>
              <p class="carta__testo" data-testo><span>Years in practice</span><b class="carta__cifra" data-cifra="19">19</b></p>
            </li>
            <li class="carta" data-carta>
              <div class="carta__stanza" data-stanza="33"></div>
              <div class="carta__buio"></div>
              <div class="carta__velo" data-velo></div>
              <p class="carta__testo" data-testo><span>Homes in Spain</span><b class="carta__cifra" data-cifra="41">41</b></p>
            </li>
            <li class="carta" data-carta>
              <div class="carta__stanza" data-stanza="52"></div>
              <div class="carta__buio"></div>
              <div class="carta__velo" data-velo></div>
              <p class="carta__testo" data-testo><span>Homes abroad</span><b class="carta__cifra" data-cifra="96">96</b></p>
            </li>
          </ol>
        </div>

        <p class="testo testo--sotto">Proportion sets the structure, material sets the tone, and light shapes the space.</p>
      </div>
    </section>

    <section class="apertura apertura--fine">
      <h2 class="titolo titolo--medio">Start with a conversation.</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.

29 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 “The figures that light up” from Animorio and fit it into my site

What it does

The about section of a made-up interior studio, told in four figures: years in Seville, years in practice, homes in Spain, homes abroad. The four cards arrive pale, cream-coloured, with the words in a warm grey, and each figure, in a large italic, counts up from zero the first time it is seen: fast at first and slower at the end. Then the screen stops and the scroll lights the cards one after another: the cream veil lifts and underneath there is a room, darkened so the words read, and the words turn white. As the next card lights up, the one before goes out. The last one stays lit. On a phone the cards are wide and the row slides sideways, so the lit card is always in the middle.

How it works

Three layers

Each card has four layers one over the other: the drawn room, a half black veil, the cream veil and the words. When asleep, the cream veil covers everything and the words are the --spenta colour; when lit, the cream veil is transparent and the words are LIT. The black veil never moves: it is there only so white words read over the room.

The figures that count

An IntersectionObserver watches the cards and, when one is on screen by at least COUNT_AT, makes its figure count up from zero once only: a tween on a number, in COUNT_TIME seconds with power1.out, that writes the rounded value at every step. It is the same curve as the site, 1 minus the square of what is left.

One card per beat

The section is 420lvh tall and the stage inside it is sticky. A timeline with ScrollTrigger, from START to the end of the section with scrub SCRUB, lights card number i at beat i, over one beat, and puts it out at beat i + 1, while the next one lights up. The last one has no putting out, so it stays lit. The curves are EASE.

The colour of the words

The words go from one colour to the other with a tween on color. The starting value is read from --spenta with getComputedStyle, so changing the colour in the CSS also changes the one the card goes back to when it goes out.

On a phone

Below 768 pixels the cards are three quarters of the screen wide and sit in a row wider than the screen. gsap.matchMedia adds to the same timeline, at the same beat as each lighting, a sideways move that brings the card to the middle, with power2.inOut and without leaving the edges of the row.

Values to change

NameFileDefaultWhat it changes
SCRUBscript.js0.8How long the cards take to catch up with the scroll (0.8 on the site).
STARTscript.js'top -20%'When the first card lights up (top -20% on the site).
EASEscript.js'power2.out'The curve of the veil and the words (power2.out on the site).
COUNT_TIMEscript.js1How many seconds a figure takes to count (1 on the site).
COUNT_ATscript.js0.2How much of a card must show before its figure counts (0.2 on the site).
LITscript.js'#ffffff'The colour of the words on a lit card.

Try them in the Playground

When to use it

For the figures of a studio, a company, an association: years, projects, people, cities. Four figures is the right number; with more cards the section must be made longer.

On phones

The same, with wide cards and the row sliding sideways along with the scroll, one card in the middle at a time.

With reduced motion

The figures are already written and all four cards are already lit, with no counting and no movement; on a phone the row scrolls under the finger.

Pitfalls

  • If the card has a CSS transition on its colour, as on the site, and GSAP changes the colour every frame, the two chase each other: the colour arrives late and slides. One or the other.
  • The figure must be written as zero before the card shows, not when the count starts: otherwise for a moment you read the final figure and then the zero.
  • On a phone the grid stage widens to hold the row and the sideways move becomes zero: it needs grid-template-columns: minmax(0, 1fr).
  • The sideways positions must be given as functions: the measures of the cards change when the fonts arrive and when the phone is turned.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Instrument Serif 5.3.0, Roboto Condensed (font variabile) 5.3.0.

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

Testing

Tested on 8 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