ImageMelt

One picture bleeding through another around the cursor, with a torn edge rather than a crossfade.

move the cursor over it

Paste into Claude Code, Cursor or any agent. Pinned to a tag, so it will not change under you.

Options

radius 0.34

0.02 to 1.4, good: 0.2 to 0.6

How far the second picture reaches from the cursor, as a share of the element's height. Small is a hole you drag about; past about 1 the second picture fills the frame whenever the cursor is anywhere on it, which turns the item into a plain hover swap.

feather 0.05

0.002 to 0.3, good: 0.02 to 0.1

How soft the boundary is. Keep it well under `displace` or the softening swallows the tear and you are back to a crossfade, which is the whole thing this is trying not to be.

displace 0.1

0 to 0.4, good: 0.05 to 0.18

How far the noise pushes the boundary about, and how hard the two pictures shear past each other at it. The single most important number here: at 0 it is a circle with a soft edge, and it is this that makes it a tear.

fringe 0.35

0 to 2, good: 0.2 to 0.6

How far red and blue come apart at the seam. Only at the seam, which is the point: it reads as the tear splitting the light rather than as a fault in the screen.

grain 5.5

0.5 to 30, good: 3 to 10

How big the torn shapes are. Low gives a few long tongues of the second picture; high gives a ragged lace. Around 5 the shapes are about the size of a hand, which is what reads as something being pulled apart.

drift 0.5

0 to 4, good: 0.2 to 1

How far the tear wanders while nothing is happening. Small: this is the breathing that stops an untouched frame being a still, not an animation in its own right.

period 12

2 to 60 s, good: 8 to 24

Seconds for one turn of that wander. The idle loop closes exactly on it, which is what lets the item be recorded without a cursor in the frame.

maxDpr 2

1 to 3

Device pixel ratio ceiling. Six texture samples per pixel, so this is the performance control.

reducedMotionTime 0

0 to 60 s

The single frame shown when the user prefers reduced motion. The pointer still works under reduced motion, because responding to a deliberate action is not the kind of movement the setting is about; this only freezes the idle wander.

What it needs

Category
Pointer, an effect
Dependencies
None at all
Browser
WEBGL2
Frame budget
~0.5 ms · 1 context
Pinned to
v0.13.0
  • The version of this on every agency site is a hover: you point at a card and the first image displaces into the second over about half a second. That cannot be done here, because easing a hover toward a target is a running total and renderAtTime has to answer for any moment on its own
  • So the transition is driven by where the cursor is rather than by how long it has been there. The second picture bleeds out from under it, which is a function of the pointer and the time, both of which the runtime replays exactly
  • The boundary is displaced by noise before it is drawn, not blurred afterwards. A soft edge is a crossfade with extra steps; an edge that wanders by a few per cent of the frame is something coming apart
  • The two pictures are pulled in opposite directions across the seam, so there is shear across it and the eye reads two separate sheets rather than one dissolve
  • The channels come apart at the boundary and nowhere else. A fringe over the whole frame is a broken monitor; a fringe only where the picture is being torn is the tear doing it
  • Distance from the cursor is measured with the aspect put back, so the front is a circle on screen rather than an ellipse. Squashed fronts are the commonest sign of an effect working in UV space without thinking about it
  • Two octaves of noise. One is too smooth to read as torn, and the interpolation between lattice corners is cubic rather than linear: linear leaves visible straight creases running through the tear along the lattice
  • The idle state still moves. The noise drifts a whole number of turns over the period, so a take with no cursor in it is a loop rather than a still
  • Both <img> elements stay in the document, hidden. If the host has only one, it is used for both and the picture tears into itself, which is a reasonable thing for a single-image host to do
  • Pointer effects need a scripted cursor path for recording, or the take is a still with nothing happening in it
  • Six samples of the pictures per pixel: three for each side of the seam, once per colour channel. The channel split is what costs, and it is the thing that makes the tear read
  • Two octaves of value noise, which is eight hashes per pixel
  • Nothing is allocated per frame and each picture is uploaded once