Skip to content
animorio
IT
Back to the library

The halftone transition

TransitionsGSAP, CanvasMediumCompressed weight: Demo 6.2 KBGSAP 28 KBFreeDownload the zip

A page change in the minimal style: from the point of the click a printer's halftone screen, dots on a grid turned 45 degrees, prints the next page's colour in a wave that fades from small dots to dots that touch. Then the new page comes out of the solid colour through holes in the same screen, its text appearing first as dots and then whole; last, the ink of the headline dries.

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 halftone transition</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage>
    <!-- the first page, on paper -->
    <section class="page page--a is-on" data-page="a" aria-label="Press">
      <header class="bar">
        <span class="brand">Raster</span>
        <nav class="nav" aria-label="Pages">
          <a href="#press" aria-current="page">Press</a>
          <a href="#papers" data-go="b">Papers</a>
        </nav>
      </header>
      <div class="main">
        <h1 class="big" data-big>Printed matter.</h1>
        <div class="below">
          <p class="lede">A small offset and riso press. Posters, zines and books, printed one dot at a time.</p>
          <a class="go" href="#papers" data-go="b" data-autoclic>
            <span class="go__t">See the papers</span>
            <svg class="go__arrow" viewBox="0 0 26 12" aria-hidden="true"><path d="M1 6h22M18.5 1.5 23.5 6l-5 4.5"/></svg>
          </a>
        </div>
      </div>
      <footer class="foot">
        <span>Print studio</span>
        <span>Screen 45 degrees, 85 lines</span>
      </footer>
    </section>

    <!-- the second page, in ink -->
    <section class="page page--b" data-page="b" aria-label="Papers" aria-hidden="true">
      <header class="bar">
        <span class="brand">Raster</span>
        <nav class="nav" aria-label="Pages">
          <a href="#press" data-go="a">Press</a>
          <a href="#papers" aria-current="page">Papers</a>
        </nav>
      </header>
      <div class="main">
        <h2 class="big" data-big>On paper.</h2>
        <ul class="list" aria-label="Papers">
          <li class="row"><span>Uncoated</span><span class="row__soft">Warm white</span><span class="row__end">120 g</span></li>
          <li class="row"><span>Cotton</span><span class="row__soft">Soft, thick</span><span class="row__end">300 g</span></li>
          <li class="row"><span>Newsprint</span><span class="row__soft">Grey, light</span><span class="row__end">52 g</span></li>
        </ul>
        <a class="go go--back" href="#press" data-go="a" data-autoclic>
          <svg class="go__arrow" viewBox="0 0 26 12" aria-hidden="true"><path d="M25 6H3M7.5 1.5 2.5 6l5 4.5"/></svg>
          <span class="go__t">Back to the press</span>
        </a>
      </div>
      <footer class="foot">
        <span>Print studio</span>
        <span>Screen 45 degrees, 85 lines</span>
      </footer>
    </section>

    <!-- the halftone screen: dots that print the next page's colour, then holes that print its text -->
    <canvas class="screen" data-screen aria-hidden="true"></canvas>
  </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.

35 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 halftone transition” from Animorio and fit it into my site

What it does

The site of a small made-up offset and risograph press, Raster, in two pages: the first paper-coloured, Printed matter., the second black as ink, On paper., with three papers (Uncoated, Cotton, Newsprint) and their weights. On load the page is printed out of the paper: the text appears through holes that widen in a wave from the middle, first as dots and then solid, and the headline's letters start a little heavy and narrow and dry with a spring. A click on See the papers starts a black halftone screen from the point of the click: the dots are born tiny and grow one after another moving away, so the front of the wave is a printed gradient, sparse dots ahead and dots that touch behind, until the whole screen is solid black. Under the black the pages swap, and the second one comes out of the black through the holes of the same screen, again from the point of the click: the light words appear as dots and then whole, and the headline On paper. dries letter by letter. A click on Back to the press does the same with a paper-coloured screen.

How it works

The screen at 45 degrees

The centres of the dots are a square lattice turned 45 degrees, like the screen of a black and white print: x = (i − j) · s and y = (i + j) · s, with s = CELL / √2, keeping only the points that fall on the screen. They are worked out once per measure and kept in a Float32Array. The full radius is 0.74 · CELL, just over half the cell's diagonal, so full dots touch and cover everything.

The wave and the printed gradient

Each dot starts when the wave reaches it: its timing is its distance from the click over that of the farthest corner. The radius grows with power2.inOut over a window FRONT wide of the whole time, so at any moment the front of the wave shows every radius at once, from the dot just born to the full one: the gradient of a halftone print.

Printing the new page from the holes

In the second half the canvas is filled with the solid colour and the dots are drawn with globalCompositeOperation destination-out: they are holes. Under it the new page is already there, in the same colour, so through the holes only its text shows, as dots, until the holes touch and the canvas is empty. Each frame is a single path with thousands of arcs and a single fill.

The ink that dries

The headline is split into letters, inline-blocks whose font-weight and font-stretch are tied to two variables (Anybody runs from 50 to 150 in width and from 100 to 900 in weight). As the page comes out of the holes the letters start at weight 900 and width 58 and spring back to 780 and 62 with elastic.out, staggered: ink spreading under the press and then drawing back.

Resizing, phone and reduced motion

The starting point is kept as a share of the screen and the lattice is worked out again on every resize, even halfway: the canvas takes the new size and the wave carries on from the same point. The canvas follows the screen's density up to 2. On a phone the screen is finer (four fifths of CELL). With reduced motion the pages swap with a fade.

Values to change

NameFileDefaultWhat it changes
CELLscript.js14The pixels between two dots of the screen; a phone uses four fifths.
COVERscript.js0.8The seconds the dots take to print the colour over the whole page.
PRINTscript.js0.9The seconds the holes take to print the new page out of the colour.
FRONTscript.js0.4How wide the printed gradient at the front of the wave is, as a share of the time.
SPEEDscript.js1The speed of everything: 2 is twice as fast, 0.5 half as fast.

Try them in the Playground

When to use it

To go from one page to another on a site that has to do with print: a print shop, a risograph studio, a publisher, a magazine, a poster archive, a black and white photographer. It works best between a light page and a dark one, because the screen prints the very colour of the page that is arriving.

On phones

The same wave with a finer screen: from the point of the tap the dots cover the tall screen and the new page comes out of the holes, with the same curves and timing.

With reduced motion

No screen: the new page fades in over the first one, with its headline already dry.

Pitfalls

  • A single colour covering and then drawing back would have hidden the new page until the end: the second half does not draw the colour back but punches holes in it, and the new page's text shows at once through them.
  • The autopilot's click (el.click()) has no coordinates: then the wave starts from the middle of the link.
  • With the full radius equal to half the cell's diagonal, tiny specks of empty would stay between four full dots, because of the antialiasing: the full radius is a little larger, 0.74 · CELL.
  • The headline split into letters would lose the space between the words: a lone space in an inline-block collapses, so it becomes a no-break space.

Libraries

GSAP 3.15.0, Anybody (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 6.2 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