Skip to content
animorio
IT
Back to the library

The line that fills the square

SVGGSAPMediumCompressed weight: Demo 5.6 KBGSAP 28 KBFreeDownload the zip

A loader in the minimal style: a thin line draws a U inside a square, then every bend opens into a smaller U, fold after fold, until the line passes through all 1,024 cells without ever crossing itself (the Hilbert curve). Underneath, the cell count gets narrower as it gets longer; at the end a second, electric blue line runs through the whole curve and counts the files packed.

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 line that fills the square</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>
  <main class="stage" data-stage aria-label="Tessel is packing your files. Click to start again.">
    <!-- one line folds itself into the square, corner by corner, then a second line runs through it in the accent -->
    <svg class="scene" data-scene aria-hidden="true">
      <path class="frame" data-frame d="" pathLength="1" />
      <path class="marks" data-marks d="" />
      <path class="line" data-line d="" />
      <path class="pack" data-pack d="" pathLength="1" />
    </svg>

    <div class="caption" data-caption>
      <span class="caption__name" data-name>Tessel</span>
      <span class="caption__count">
        <span class="caption__num" data-num>4</span>
        <span class="caption__label" data-label>cells</span>
      </span>
    </div>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.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.

15 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 line that fills the square” from Animorio and fit it into my site

What it does

On a warm white page a very thin grey square and its four corner marks draw themselves; inside, a black line a pixel and a half thick traces an upside-down U that touches the four cells of the square. Underneath, on the left, the name of the made-up app, Tessel; on the right a large number, 4, and the word cells. Then the line folds: every corner of the U opens into a smaller U, and the fold runs along the line from its start, bottom left, to its end, bottom right; every stretch lands a hair past its place and comes back. The folds happen four times (16, 64, 256, 1,024 cells) and the line gets a little thinner every time, never crossing itself. The number underneath counts the cells while the line folds, gains weight and narrows on the width axis with every extra digit, so it always takes the same room. When the square is full the number fades and comes back in electric blue from zero with the word packed, while a second blue line runs through the whole curve and covers it cell by cell up to 1,024. After a breath the blue line leaves from its tail, the curve folds back down to the first U and rubs itself out; then it all starts again. A click starts it over.

How it works

The curve, just once

The Hilbert curve is worked out once at the finest order with the classic d2xy function, which turns a point’s index into its cell. The coarser orders are the same list taken every 4th, 16th, 64th… point, with the coordinates divided by 2, 4, 8: the Hilbert curve visits the sub-cells of each cell one after the other, so every group of four consecutive points always shares the same parent.

A fold is a point sliding

To go from order k to k+1 every new point starts at the centre of its parent’s cell (point j>>2 of the order before) and slides to the centre of its own. Each point’s progress is offset along the line (WAVE), so the fold runs from the start to the end, and goes through back.out(SPRING): every corner goes a hair past and comes back.

A number that keeps its room

The counter is variable Archivo: GSAP tweens the number with a snap to whole numbers, the weight and a --w variable tied to font-stretch. The width goes down from 125 to 76 as the digits go from one to four, so the number never pushes the word next to it.

The line that packs

The blue line is a copy of the final path with pathLength=1: its stroke-dasharray is «0 tail head−tail 2», so tweening two numbers is enough to bring it in from the start and send it out from the tail. The file count follows it with the same duration.

Loop, click and reduced motion

It is all one paused timeline which, on onComplete, sets the state back to zero and plays again: the preview video sees the whole loop. The path is only rebuilt when the order, the fold or the size change, and on resize the square is worked out again in pixels, even halfway through a fold. With reduced motion the full square, in blue, with 1,024 packed, fades in and stays.

Values to change

NameFileDefaultWhat it changes
NAMEscript.js'Tessel'The app’s name, under the square on the left.
ORDERscript.js5How many times the line folds (3 to 6): 5 is 1,024 cells, 6 is 4,096.
DRAWscript.js1.1The seconds the first U takes to draw itself.
FOLDscript.js1.05The seconds of each fold.
WAVEscript.js0.55How far the fold travels along the line: 0 = every corner at once.
SPRINGscript.js1.4How far every corner goes past its place before it settles: 0 = it stops dead.
PACKscript.js2.6The seconds the blue line takes to run through the whole curve.
HOLDscript.js1.6The seconds the full square stays before it folds back.

Try them in the Playground

When to use it

As the loader of an app that stores, sorts or syncs files, a backup service or a warehouse; as the wait during a long import; as the picture on a page that explains how a system puts things in order without leaving gaps.

On phones

The same animation with the sizes adapted: the square takes nearly the whole width, the line stays at least a pixel thick even with the smallest cells, and the name and the number stay underneath, lined up with the edges of the square.

With reduced motion

Nothing moves: the full square, with the blue curve and 1,024 packed underneath, fades in and stays.

Pitfalls

  • The coarse orders must not each be worked out with their own d2xy: different orders can come out turned or mirrored against each other, and then the parent j>>2 would not sit under its four children and the fold would make stretches jump. Taking them all from the fine one, a point every 4^n, the parent is always right.
  • The number’s blue is not set with gsap.set(color: 'var(--accent)'): GSAP tries to tween the colour and a CSS variable is not a colour. A class does it.
  • At order 6 there are 4,096 points: the path is only rebuilt when something really changes (a key made of order, fold and size), so nothing is worked out again during the pauses.

Libraries

GSAP 3.15.0, Archivo (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 5.6 KB; the libraries: GSAP 28 KB.

Testing

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