
Ink that reveals
WebGL, Hover
NewLifetime
A white plaster rosette on a white wall: at rest you can hardly see it. Where the pointer passes the light comes in low, every leaf and petal casts its shadow, and after a couple of seconds the plaster falls back asleep.
A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN.
The code for this animation is part of lifetime access.
The preview stays open: watch it, slow it down, try it on your phone.
Lifetime accessThe script draws the rosette on a 2D canvas in shades of grey, where lighter means higher: a ring, 44 beads, 60 leaves, 24 gradient petals and a button. Then it blurs it with three box-blur passes, horizontal and vertical: the height is max(wide blur, 0.6 × narrow blur), so the edges stay soft but the details survive. A third, medium blur slightly darkens the folds. Height and folds go into a 640 × 640 RG16F texture (448 on phones).
A second 2D canvas, 216 pixels wide and shaped like the wall, holds the trail. Every tick it is covered in black at alpha 1 − 0.85^(dt × 60) and the latest 200 points are redrawn in lighter mode: a radial stamp with alpha (1 − age/120)² × 0.13 and a radius that grows and shrinks with sin(π × life). The pointer adds ⌈30 × distance⌉ points per tick, so even a quick gesture leaves a continuous trail. It draws at most 44 times a second, and the loop stops when the wall leaves the screen or the tab is hidden.
The shader reads the trail with five samples and derives k = (smoothstep(0, 0.3, t) × smoothstep(0, 1, t))^0.7. From k come the depth of the relief (0.6 to 9) and the height of the light (z from 1.4 to 0.45). The normal comes from the height differences between neighbours, and the light is (ambient + n·L) / (ambient + L.z): divided by what the flat plane receives, so the flat wall always keeps the same white and only what has a slope changes. Highlights are not clipped abruptly: they approach white along an exponential curve.
For each point the shader walks towards the light, twelve steps of 2.5 five-hundred-and-twelfths of the relief, and measures how far the ray passes above the relief, divided by the distance. The smallest value, passed through smoothstep(−0.22, 0.22), says how much the point is in shadow: the penumbra widens with distance, as under a real light. With a high light the ray climbs fast and there is no shadow; with raking light the shadows lengthen.
| Name | File | Default | What it changes |
|---|---|---|---|
SPEGNE | script.js | 0.85 | How much of the trail survives every sixtieth of a second: higher, the plaster stays awake longer. |
FORZA | script.js | 0.13 | How much each pass of the pointer lights up. |
PROFONDO | script.js | [0.6, 9] | The depth of the relief asleep and awake. |
AMBIENTE | script.js | 0.9 | The diffuse light: higher, lighter shadows. |
rosone() | script.js | cornice, ghirlanda, fiore | The relief drawing: anything drawn in greys on a canvas becomes plaster, a logo or a word too. |
GESSO, --gesso | script.js, style.css | #EFECE6 | The wall colour: change it in both files, or the edge of the canvas shows. |
For a page that wants to reward exploring: a mark, a work, a symbol you only discover by passing over it. It works with any drawing in greys, a logo too.
The finger paints the light and a tap lights up its spot. The trail is smaller (128 pixels), drawn 36 times a second at density 1, and the wandering points light up more, because a finger does not pass all the time. Inside an iframe a vertical finger stays with the page.
No trail and no wandering points: the relief stays still under a half-low light, readable. A tap takes the light from straight to raking, and back, in six tenths of a second.
GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.
Weight: 21 KB of our own files.
Tested on 27 September 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.
You’re signed in as .
Your plan is free. When lifetime access arrives, it will switch on for this same account.