Skip to content
animorio
IT
Back to the library

The moiré rings background

Backgrounds, HoverGSAP, Canvas, CSS onlyMediumCompressed weight: Demo 5.8 KBGSAP 28 KBFreeDownload the zip

An animated background to put behind a heading or a section: two families of hairline concentric rings in ink on warm white paper. The centre of the first drifts slowly, the centre of the second follows the pointer on a spring, and where the rings cross, moiré fringes appear, fanning out and sweeping across the paper. 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>Loupe</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/newsreader@5.3.0/opsz.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/newsreader@5.3.0/opsz-italic.css">
  <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 background: two families of hairline concentric rings on a canvas behind the page; one drifts slowly, the
       other follows the pointer, and where they overlap the moire fringes bloom and sweep across the paper -->
  <main class="pagina" data-pagina>
    <canvas class="fondo" aria-hidden="true" data-fondo></canvas>

    <header class="testa">
      <p class="marchio">Loupe</p>
      <p class="testa__nota">Opticians since 1984</p>
    </header>

    <section class="eroe">
      <div class="blocco" data-blocco>
        <p class="occhiello" data-entra>Eyewear, fitted by hand</p>
        <h1 class="titolo">
          <span class="riga"><span class="riga__dentro" data-riga>Look <em class="accento">twice,</em></span></span>
          <span class="riga"><span class="riga__dentro" data-riga>then see clearly.</span></span>
        </h1>
        <div class="azione" data-entra>
          <a class="pillola" href="#">
            <span class="pillola__scritta" data-testo="Book an eye test">Book an eye test</span>
            <svg class="pillola__freccia" viewBox="0 0 16 16" aria-hidden="true"><path d="M2.5 8h10.5M9 3.8 13.2 8 9 12.2" /></svg>
          </a>
        </div>
      </div>
    </section>
  </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.

22 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 moiré rings background” from Animorio and fit it into my site

What it does

A whole page in warm white paper, the background of an invented optician, Loupe. Behind everything, on a canvas, two families of very thin concentric ink rings, one every nine pixels, fading towards the corners to leave the paper empty. In the middle the heading: Eyewear, fitted by hand, then two lines in Newsreader (Look twice, then see clearly.) with the word twice in vermilion italics, the only colour, and a black pill (Book an eye test) with its arrow; at the top the brand in italics and Opticians since 1984. The centre of the first family drifts slowly round the middle of the page; the centre of the second follows the pointer on a spring, and the second family breathes, a little wider and a little narrower. Where the rings cross, moiré fringes appear: darker and lighter bands fanning out between the two centres and sweeping over the whole sheet at every move of the pointer. Behind the heading the rings lighten in a soft oval. When nobody moves the pointer, a fake pointer wanders round the page on a curve that comes back the same. When the page opens the two families spread from their centres like a ripple, one after the other, and the fringes appear where they meet; the heading lines rise from their window, gaining weight.

How it works

Two families of rings

On a full-page canvas (devicePixelRatio capped at 2) each family is a series of concentric circles, one every PASSO pixels, out to the furthest corner. The moiré is not programmed: it appears by itself where two regular sets of thin lines overlap with their centres slightly apart, because the rings now coincide and now fall into the gaps of the other family.

Twelve strokes per family

Towards the edges the rings fade: from half of LONTANO (a fraction of the diagonal) to LONTANO the opacity drops to zero. To avoid changing globalAlpha for every ring, the rings go into twelve Path2D objects by opacity and each group is drawn with one stroke: twenty-four strokes per frame in all.

The centre on the pointer and the breathing

The centre of the second family follows the pointer on a spring (MOLLA) integrated by hand on GSAP's ticker; the spacing of its rings changes by RESPIRO per cent with a sine tied to the round's phase. Moving a centre by a few pixels makes the fringes travel a long way: moiré is a magnifying glass for movement.

The eraser behind the heading

After the rings the context switches to destination-out and fills an oval with a radial gradient (the context stretched with scale), solid in the middle and clear at the edge: behind the words the rings lighten by CALMA with no hard edge.

The opening, the fake pointer, the pause

A timeline takes the largest radius of the two families from 0 to 1, the second half a second later, with the last ninety pixels faded like the edge of a ripple. The heading lines rise with back.out while the weight goes from 250 to 400. After 2.4 seconds without the real pointer the centre follows a Lissajous curve tied to the round; IntersectionObserver and visibilitychange stop everything when the page is not visible.

Values to change

NameFileDefaultWhat it changes
PASSOscript.js9The distance between rings, in px (a little less on a phone).
SPESSOREscript.js1The thickness of the rings, in px.
GIROscript.js24How many seconds the drifting centre takes to come round to the same place.
DERIVAscript.js0.14How far that centre strays from the middle of the page, as a fraction of the page.
RESPIROscript.js0.035How much the second family widens and narrows (0.035 means 3.5%).
MOLLAscript.js[55, 12]The spring of the centre that follows the pointer: how stiff and how damped.
LONTANOscript.js0.52How far the rings reach before fading out, as a fraction of the page diagonal.
CALMAscript.js0.9How much the rings lighten behind the heading (0 not at all, 1 they vanish).

Try them in the Playground

When to use it

As the background of the first screen of an optician or an eyewear brand, a design studio, a kinetic art gallery, a recording studio or an electronic music festival; in general behind a short heading when you want a light sheet that barely moves and surprises you when the mouse moves. The colour of the rings and the accent are set in the CSS.

On phones

The same animations with the sizes adapted: the rings are a little closer and the heading smaller, with the eraser following it. The finger moves the centre of the second family while it touches and drags; when it lifts the fake pointer comes back.

With reduced motion

The rings are still, already spread, with the fringes in place: no drift, no spring, no opening. The heading, the small line and the pill fade in.

Pitfalls

  • Rings out to the corners, all solid, filled the page with ink and the moiré turned into noise: with the rings fading towards the edges the corners stay empty and the fringes read in the middle.
  • Changing globalAlpha ring by ring needed hundreds of strokes per frame: grouped into twelve opacity levels the rings are twenty-four strokes in all.
  • Two families with the same centre make no moiré at all: the fake pointer walks a curve that always stays a little away from the first family's centre.

Libraries

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

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