Skip to content
animorio
IT
Back to the library

The interference waves background on scroll

Scroll, BackgroundsGSAP, Canvas, CSS onlyMediumCompressed weight: Demo 7.4 KBGSAP + ScrollTrigger 45 KBLenis 5.3 KBFreeDownload the zip

Scroll inside the preview

A background to scroll through, in minimal style: on an almost pure black, two sources of circular waves drawn only as thin crests, like two stones in a pond seen from above. As you scroll the sources move apart and the interference pattern opens up: the crests light up where they add up and vanish on the lines of silence, and a thread of light runs along the fringes. The pointer is a third, vermilion source, and a tap flips its phase.

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>Antinode</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist@5.3.0/wght.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- a long section with a sticky stage: two sources of circular waves, drawn as thin crest lines on a canvas;
       scrolling moves the sources apart and the interference pattern changes; the pointer is a third, weak source -->
  <main class="corsa" data-corsa>
    <section class="palco" data-palco>
      <canvas class="onde" aria-hidden="true" data-onde></canvas>

      <header class="testa">
        <p class="marchio" data-entra>Antinode</p>
        <p class="testa__nota" data-entra>Acoustic design studio</p>
      </header>

      <div class="frasi" aria-live="polite">
        <p class="frase" data-frase><span class="frase__occhio">One source</span><span class="frase__testo">Every sound starts as a ring.</span></p>
        <p class="frase" data-frase><span class="frase__occhio">Two sources</span><span class="frase__testo">Where crests meet, it grows.</span></p>
        <p class="frase" data-frase><span class="frase__occhio">Further apart</span><span class="frase__testo">Where they cross, silence.</span></p>
      </div>

      <footer class="piede">
        <p class="piede__nota" data-entra data-cenno>Scroll to part the sources, tap to flip your own</p>
        <p class="piede__lettura" aria-hidden="true" data-entra>
          <span class="lettura__nome">Spacing</span>
          <span class="lettura__valore" data-distanza>0.0</span>
          <span class="lettura__unita">λ</span>
          <span class="lettura__fase" data-fase>In phase</span>
        </p>
      </footer>
    </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="https://cdn.jsdelivr.net/npm/lenis@1.3.26/dist/lenis.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.

27 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 interference waves background on scroll” from Animorio and fit it into my site

What it does

A long section with a still stage, the background of an invented acoustics studio, Antinode. When it opens, two stones drop in the same spot one after the other: two small crosses settle with a bounce and from there thin rings spread out to the edges. The rings are the wave crests and drift slowly outwards, lighter near the sources. As you scroll, the two sources separate along the long side of the stage, up to five and a half wavelengths: the light of each piece of crest is set by the real interference, full where the waves arrive together and nothing where they arrive opposed, so the lines of silence appear. The fringes where the waves add up are hyperbolas with their foci on the two sources: they are drawn faintly and a dashed thread of light runs along them. At three points of the run a sentence changes in the middle, over a soft black veil (One source, Two sources, Further apart), and a brighter wave passes with it; at the bottom the spacing reads in wavelengths. The pointer is a third, weaker source on a spring: its waves are the only vermilion ones, and a tap flips its phase with a small bounce (In phase becomes Opposite phase). When nobody moves it, a fake source wanders slowly over the stage.

How it works

The stage and the run

The section is 420lvh tall and the stage inside is sticky, 100lvh tall. A ScrollTrigger reads the progress from 0 to 1 (with Lenis for smooth scrolling) and gives the wanted spacing between the sources: together for the first 14%, then they separate on a smooth curve up to APERTURA wavelengths. The real spacing follows it on a spring, so the pattern never jumps.

The crests of one source

Each source draws its rings one wavelength apart, moving outwards at VELOCITA waves per second. Each ring is made of 7 px pieces; those outside the stage are skipped. The amplitude fades slowly with distance (1 over the square root of 1 + r / 3.4 wavelengths) and at the opening a soft edge runs outwards: before it arrives there is nothing.

The interference

Two equal waves reaching a point along paths r1 and r2 add up to 2 cos(k (r1 − r2) / 2). Each piece takes the absolute value raised to the power 1.6 as its light, and ends up in one of four bunches of light and width: four paths, four strokes per source. Where the value drops to zero the crests vanish: those are the lines of silence.

The fringes and the thread of light

The points where the path difference is a whole number of wavelengths lie on hyperbolas with their foci on the sources: x = a cosh u, y = b sinh u, with a half the difference and b² = c² − a². They are drawn as a single faint path, then again with a 7 px dash every 88 whose start moves forward FLUSSO px per second.

The pointer’s source

The pointer is a third source on a spring (MOLLA), with strength PUNTATORE: its rings are drawn in vermilion and fade away from it. A pointerdown takes its phase from 0 to π, or back, with elastic.out in 0.9 s: the rings slide by half a wave and go just past. Every new sentence and every tap send a brighter wave out of the sources. After 2.4 s without the real pointer, a fake source follows a slow curve.

Values to change

NameFileDefaultWhat it changes
ONDAscript.js0.07The wavelength, as a fraction of the stage’s short side.
VELOCITAscript.js0.55How many waves per second leave each source.
APERTURAscript.js5.5How far apart the sources end up at the end of the run, in wavelengths.
PUNTATOREscript.js0.6How strong the pointer’s source is compared with the other two.
FLUSSOscript.js38How fast the light runs along the fringes, in px per second.
MOLLAscript.js[70, 12]The spring of the pointer’s source: how stiff and how damped.
SPESSOREscript.js1The thickness of the crests nearest the sources, in px.

Try them in the Playground

When to use it

As a background to scroll through for an acoustics or sound design studio, a concert hall, a speaker or headphone company, a physics lab or a science museum, a page that tells a product in steps; in general behind short sentences when you want a dark background that changes as you go down. The line colour and the accent are set in the CSS.

On phones

The same animations with the sizes adapted: the wavelength is measured on the short side, and on a tall stage the sources separate vertically, so the pattern fills the whole box. The finger moves the third source and a tap flips its phase; the page still scrolls vertically.

With reduced motion

The pattern is still, with the sources at half their spacing and no pointer source: no spreading rings, no thread of light, no brighter waves. The sentences change on scroll with a fade.

Pitfalls

  • The isolines of the summed waves (marching squares) make lots of small ovals where the crests cross and the pattern gets crowded: it is better to draw each source’s rings and give each piece the light of the interference.
  • With the sources too far apart the fringes get dense and only little crosses are left: the spacing is measured in wavelengths and stops around five and a half.
  • The edge running out at the opening cannot travel at the wave speed, which is slow on purpose: it has its own, much faster speed, FRONTE.

Libraries

GSAP 3.15.0, ScrollTrigger 3.15.0, Lenis 1.3.26, Geist (font variabile) 5.3.0.

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

Testing

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