
The gravitational lens background
WebGL, Backgrounds, Hover
NewFree
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.
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>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
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 siteThe 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.
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.
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 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'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.
| Name | File | Default | What it changes |
|---|---|---|---|
LINES | script.js | 44 | How many lines on desktop; on phones one every 16 px of height, at least 22. |
AMPLITUDE | script.js | 0.15 | How high the ridges rise, as a share of the page height. |
DETAIL | script.js | 3.2 | How dense the ridges are from side to side. |
LOOP | script.js | 12 | How many seconds the noise and the fake stone take for a round that comes back the same. |
STONE | script.js | 1.6 | How much the ridges rise near the pointer. |
STONE_SIZE | script.js | 0.09 | How wide the stone is, as a share of the width. |
LINE_WIDTH | script.js | 1.1 | The thickness of the lines, in px. |
TITLE_CLEAR | script.js | 0.84 | How much the lines behind the headline fade: 0 not at all, 1 they vanish. |
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.
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.
The ridges are already in place and still: no breathing, no stone, no vermilion line. The name and the headline fade in.
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.
Tested on 22 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.