
Stacking certificates
Hover, Images
NewFree
In the minimal style: a picture made only of black horizontal lines, like a banknote engraving, swelling where it is dark. The lines are cut thin from left to right, then a wave runs down and each takes its weight, and a pear appears; then the mountain, then the moon, one line at a time. The pointer parts the lines like a lens.
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 picture engraved in lines</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage" data-stage>
<header class="top">
<p class="mark">Burin</p>
<p class="note">Line engravings</p>
</header>
<!-- the plate: a picture made only of horizontal lines that swell where it is dark. The lines are cut, then
take their weight; one picture flows into the next line by line. The pointer parts the lines like a lens -->
<figure class="plate" data-plate role="img">
<canvas class="lines" data-lines aria-hidden="true"></canvas>
<figcaption class="cap" aria-live="polite">
<span class="cap__title" data-title></span>
<span class="cap__meta" data-meta></span>
</figcaption>
</figure>
</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.
18 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 picture engraved in lines” from Animorio and fit it into my siteEvery picture is drawn by the script on a hidden canvas, in greys, and read once with getImageData: for each pixel how dark it is, from 0 (paper) to 1 (ink). Then for every line and for 180 points along it the script averages the band that belongs to it, so nothing falls between two lines.
Every line is a filled polygon: its top and bottom edges are 0.55 pixels apart where the picture is light and up to THICK of the space between two lines where it is dark. It is drawn on every frame on the visible canvas, by GSAP's ticker.
Every line knows which picture it comes from and which one it is going to, and has a number p from 0 to 1. A timeline takes it to 1 with elastic.out, one line after the other from the top in SWEEP seconds: the thickness goes past the right one and comes back. At the start the lines come 'from blank' and a first round cuts them (their length goes from 0 to 1, from the left).
The pointer is followed with quickTo, and a strength that rises on a spring (elastic.out) moves every point of the lines by dy/σ × e^(−d²/2σ²), with σ = LENS: the lines above go up, those below go down, smoothly, and an empty lens opens. The line closest to the pointer is drawn in the accent.
The title is in Fraunces, a variable serif: its weight sits in a CSS variable read by font-variation-settings. When the picture changes it goes to 100 and fades, changes text and comes back to 560 with elastic.out while the wave runs down.
| Name | File | Default | What it changes |
|---|---|---|---|
PICTURES | script.js | 3 immagini | The pictures drawn by the script, one after the other: the title and the small line. |
LINES | script.js | 74 | How many lines make the plate (a few fewer on a phone). |
THICK | script.js | 0.9 | The thickest line, as a part of the space between two lines. |
SWEEP | script.js | 1.1 | The seconds the wave takes to run down the plate. |
HOLD | script.js | 2.6 | The seconds a picture stays before the next one. |
LENS | script.js | 64 | The size of the lens the pointer opens, in pixels. |
PART | script.js | 2.2 | How far the lens pushes the lines apart, in line spaces (0 = no lens). |
For those who sell or show prints, engravings and illustrations: the shop window of an art print studio, an exhibition page, the opening of an illustrator's portfolio, a gallery that wants the tone of printed paper. Also the page of a paper product, a bank or a mint.
The same animation with the sizes adapted: the plate is almost as wide as the screen and has fewer lines, each a little thicker. The lens opens under the finger.
Nothing is cut or swells and there is no lens: the picture is already engraved, and one gives way to the next with a fade.
GSAP 3.15.0, Fraunces (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 7.0 KB; the libraries: GSAP 28 KB.
Tested on 19 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.