Skip to content
animorio
IT
Back to the library

The ridge line background

Backgrounds, WebGL, HoverGSAP, WebGL, CanvasMediumCompressed weight: Demo 7.3 KBGSAP 28 KBFreeDownload the zip

A minimal-style WebGL animated background to put behind a headline: many thin ink lines one behind the other, like a ridge plot, lifted by a slow noise field; the lines in front hide the ones behind, and the pointer is a stone in a stream: the ridges near it rise and the line under it turns vermilion.

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>Halcyon Radio</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>
  <!-- a page background drawn by one WebGL shader: rows of thin ink lines, one behind the other like a ridge plot,
       each lifted by a slow field of noise; the lines in front hide the ones behind; the pointer is a stone in the
       stream: the ridges near it rise, and the line under it takes the one accent -->
  <main class="pagina" data-pagina>
    <canvas class="tela" aria-hidden="true" data-tela></canvas>

    <header class="testa">
      <p class="marchio" data-entra>Halcyon Radio</p>
      <p class="testa__nota" data-entra>Night broadcasts, 88.4</p>
    </header>

    <div class="centro" data-titolo>
      <h1 class="titolo" data-entra data-peso>Listen to the quiet.</h1>
      <p class="sotto" data-entra>Six hours of low signal, every night from one to seven.</p>
    </div>

    <p class="nota" data-entra data-nota>Move through the lines</p>
  </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.

17 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 ridge line background” from Animorio and fit it into my site

What it does

On a warm white sheet there are many thin ink lines, one behind the other from top to bottom, like mountain profiles seen one after another or the ridge plot of a radio signal. Each line rises into soft ridges, tall in the middle and flat at the sides, and the ridges change slowly, breathing, in a twelve-second round that comes back the same. The lines in front have paper under them, so where they rise they cover the lines behind: that is why the ridges look solid. On opening the lines rise from the front to the back and settle with a hair too much, then the name of the made-up radio station, Halcyon Radio, arrives with the headline «Listen to the quiet.», which comes in wide and light and narrows as it gains weight. The pointer is a stone in a stream: where it passes the nearby ridges rise in a wave, and the line running under it turns vermilion, the only colour on the page. When nobody moves it, a fake stone draws a slow figure of eight over the ridges. Behind the headline the lines fade, so the words can always be read.

How it works

A square and a shader

The page is a WebGL canvas with a single square covering it and a fragment shader that decides the colour of each pixel. For each pixel the shader goes through the lines one at a time, from the nearest (bottom) to the farthest (top), and works out where each one's ridge sits above that point.

The ridge of one line

Each line has its base and a height given by three-octave noise (fbm) read in x and in the line's index, multiplied by an envelope that keeps it tall in the middle and flat at the sides. The noise is read while moving around a circle of radius 0.55: after a full round, LOOP seconds, it comes back exactly the same, so the animation repeats with no jump.

Whoever is in front covers

Going from the front lines to the back ones, the shader remembers whether the pixel is already under the ridge of a nearer line, between its ridge and its base: in that case it is paper and the lines behind are not drawn. It is the painter's trick, done in a loop instead of with depth.

The stone in the stream

The pointer adds a Gaussian bump to each line, STONE_SIZE of the page wide and STONE tall, which weighs more on lines whose base is near the pointer. The line with the nearest base takes the accent colour. The stone follows the pointer on a measured spring on GSAP's ticker; after 2.4 seconds of calm the fake stone comes back, drawing a slow figure of eight in the same round as the noise.

The headline stays readable

The headline's position is measured from the DOM and passed to the shader as a rectangle: with a rounded-box distance (sdBox) and a wide smoothstep, the nearby lines fade until they almost vanish. So the headline sits over the background without a paper box.

Values to change

NameFileDefaultWhat it changes
LINESscript.js44How many lines on desktop; on phones one every 16 px of height, at least 22.
AMPLITUDEscript.js0.15How high the ridges rise, as a share of the page height.
DETAILscript.js3.2How dense the ridges are from side to side.
LOOPscript.js12How many seconds the noise and the fake stone take for a round that comes back the same.
STONEscript.js1.6How much the ridges rise near the pointer.
STONE_SIZEscript.js0.09How wide the stone is, as a share of the width.
LINE_WIDTHscript.js1.1The thickness of the lines, in px.
TITLE_CLEARscript.js0.84How much the lines behind the headline fade: 0 not at all, 1 they vanish.

Try them in the Playground

When to use it

As the background of the first screen of a radio station, a record label, a podcast, an observatory or a mountain travel agency; behind the headline of a data page or a product about signals, sound or landscape, when you want a living background that stays sober.

On phones

The same animation: fewer lines (one every 16 px of height), slightly lower ridges, a wider stone and less resolution for the shader. A finger sliding over the background is the stone; as soon as it lifts the fake stone comes back.

With reduced motion

The ridges are already in place and still: no breathing, no stone, no vermilion line. The name and the headline fade in.

Pitfalls

  • The lines are drawn front to back, not the other way round: that way one number is enough to remember whether the pixel is already covered by the paper of a nearer line, without a depth buffer.
  • Noise that flows in time never comes back the same and the preview video did not know when to stop: reading it on a circle closes the LOOP-second round exactly.
  • Without fading the lines behind the headline the words got lost in the ridges: now a distance from the headline's rectangle takes them almost to paper.
  • The shader runs a loop for every line and every pixel: on phones the resolution is held at 1.25 (1.5 on desktop) (1.5 on desktop) and there are fewer lines, so it stays smooth.
  • WebGL 1 wants loops with a fixed count: the loop goes up to 72 and breaks when the index leaves the real lines.

Libraries

GSAP 3.15.0, Archivo (font variabile) 5.3.0.

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

Testing

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