Skip to content
animorio
IT
Back to the library

A grid that assembles itself

Scroll, TextGSAP, CSS onlyMediumCompressed weight: Demo 5.9 KBGSAP + ScrollTrigger 45 KBFreeDownload the zip

Scroll inside the preview

As you scroll, six columns come down from the top, separate, squeeze inside the margins and at the end a title, a picture and text fall into them; each column shows its width, which changes as the grid assembles.

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="it">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>La griglia che si monta</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main>
    <section class="apertura">
      <p class="nota" data-nota>Scorri: le colonne scendono, si separano, si stringono dentro i margini, e alla fine ci cadono dentro le cose.</p>
      <h1 class="apertura__titolo">Una griglia si monta in tre mosse.</h1>
    </section>

    <!-- la scena: alta cinque schermi, il palco resta fermo (sticky) e lo scorrimento muove tutto -->
    <section class="scena" data-scena aria-label="Come si monta una griglia">
      <div class="palco" data-palco>
        <div class="griglia" data-griglia aria-hidden="true"></div>

        <div class="passi" data-passi>
          <i class="passi__segno" data-segno aria-hidden="true"></i>
          <ol class="passi__elenco">
            <li class="passo" data-passo>Colonne</li>
            <li class="passo" data-passo>Intercolonnio</li>
            <li class="passo" data-passo>Margine</li>
            <li class="passo" data-passo>Contenuto</li>
          </ol>
        </div>

        <!-- i contenuti che alla fine cadono nelle colonne -->
        <div class="blocco blocco--titolo" data-blocco><span>Il foglio di settembre</span></div>
        <div class="blocco blocco--figura" data-blocco>
          <svg viewBox="0 0 200 160" preserveAspectRatio="xMidYMid slice" aria-hidden="true" focusable="false"><rect width="200" height="160" fill="#E9DFC9"/><circle cx="148" cy="48" r="20" fill="#E3A33F"/><path d="M0 104Q50 86 100 98T200 92V160H0Z" fill="#8FA36A"/><path d="M0 126Q60 112 120 124T200 118V160H0Z" fill="#5E7A45"/><path d="M34 98V70M34 70q-10-8-14-20q12 4 14 20q2-16 14-20q-4 12-14 20" stroke="#3D5A2E" stroke-width="3" fill="none"/></svg>
        </div>
        <div class="blocco blocco--testo" data-blocco><i></i><i></i><i></i><i></i><i></i><i></i></div>
        <div class="blocco blocco--testo blocco--corto" data-blocco><i></i><i></i><i></i><i></i></div>

        <p class="didascalia" data-didascalia aria-live="polite"></p>
      </div>
    </section>

    <section class="chiusura">
      <h2 class="chiusura__titolo">La griglia resta, anche quando non si vede.</h2>
      <p class="chiusura__testo">Le colonne danno la misura, l’intercolonnio le tiene staccate, il margine le tiene lontane dal bordo. Poi le cose si appoggiano a quei bordi, e la pagina sembra in ordine senza che nessuno sappia perché.</p>
    </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.

36 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 grid that assembles itself” from Animorio and fit it into my site

What it does

A layout lesson in four moves, inside a scene that stays still while you scroll. The columns start as a black strip at the top, come down to the bottom and meanwhile go from black to grey; then they separate and the gutter appears between them, brick red; then they squeeze and the margin appears at the sides, blue. Each column shows its width in pixels, which drops as the grid assembles. At the top left the steps, with the small square sliding onto the current one; at the bottom a large caption, whose letters rise from their mask at every move. At the end the columns fade into guides and a title, a picture and two text blocks fall into them, each on the edges of its columns.

How it works

A single number

The scene is five screens tall and the stage is sticky. A tween takes an object { p } from 0 to 1 tied to scrolling with scrub 0.6, and on every update one function redraws everything from p: each move has its own window (columns 0.02 to 0.22, gutter 0.27 to 0.45, margin 0.5 to 0.68, content 0.72 to 0.96), run through power2.inOut.

The width of a column

With n columns, gutter g and margin m, each column is (W − 2m − (n − 1)g) / n wide, and column i starts at m + i(width + g). While g and m grow from zero the formula stays the same: the columns separate and squeeze by themselves, and the label in the middle shows the right number. Below 760 px there are four columns.

Labels that read on anything

Steps, widths and caption are white with mix-blend-mode: difference, so dark on the paper and light on the black. The sticky stage is a group of its own, and the difference only mixes with what is inside it: that is why it has its own background, the same as the page.

Things fall into place

Each piece of content has a starting column, how many columns it spans and a height. Its x comes from the same formula as the columns, and its fall has a window inside the last move, staggered by 0.14, run through bounce.out: scrolling back up, it rises again.

Values to change

NameFileDefaultWhat it changes
GRANDE, PICCOLAscript.js6/16/32, 4/12/16Columns, gutter and margin on a wide screen and on a phone.
MOSSEscript.js4 finestreWhere each move starts and ends, as fractions of the scene.
POSTIscript.js4 contenutiWhere the content falls: starting column, how many columns, height.
--canale, --bordostyle.css#C4553B, #5B7FA6The colours of the gutter and the margin.

Try them in the Playground

When to use it

To explain a method step by step, on a design site or a page about how you work: the grid is a pretext, the phases of a project can rise in place of the columns.

On phones

On a phone the grid has four columns, a 12 px gutter and a 16 px margin, and the content falls in another order; the caption says so.

With reduced motion

No held scene: the grid is already assembled and full, all the steps are lit and the caption shows the last move.

Pitfalls

  • mix-blend-mode inside a sticky element only blends with its own group: without a background on the stage the white labels stay white on the paper.
  • A ScrollTrigger with scrub but no animation passes the raw progress to onUpdate: to get the lag you must animate an object { p } with a tween.
  • Computing the columns by rounding the width instead of the edges makes the gutters jump by a pixel while they open.
  • If the screen goes from wide to narrow the grid changes its number of columns: it is rebuilt in onRefreshInit, before ScrollTrigger measures again.

Libraries

GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.

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

Testing

Tested on 28 September 2026

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

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