Liquid wipe

When to use
Use when the cut should feel organic: a gooey edge floods the frame from one side onto the next shot. Eight bars with round heads run in from the left, each at its own speed, and a blur followed by a hard alpha contrast (the goo filter) fuses them into one wet edge with lumps and meniscus between rows. The detail that sells it is the second edge: an accent band leads the next shot by 7 percent of the width, so the liquid has a body and a colour of its own. Clip: liquid-wipe.mp4. Demo: demo/liquid-wipe.html.
The code
import { rng } from '../../core/motion/springs.js';
import { EASE, easeFn } from '../../core/motion/presets.js';
const E = easeFn('land'), rand = rng(5), N = 8, rh = H / N, R = rh * 0.8, blur = rh * 0.42;
const rows = Array.from({ length: N }, (_, i) => ({ y: (i + 0.5) * rh, lag: rand() * 0.22, dur: 0.85 + rand() * 0.25 }));
const prog = (row, t) => Math.min(1, Math.max(0, (t - 0.25 - row.lag) / row.dur));
const front = (row, t) => -R - 3 * blur + (W + 2 * R + 6 * blur + W * 0.14) * E(prog(row, t)); // starts fully outside the frame
const goo = (t, lead) => { // an SVG image used as a CSS mask: bars + round heads, blurred, then alpha x24 - 10
const shapes = rows.map((r) => { const x = front(r, t) + lead * Math.min(1, prog(r, t) * 6);
return `<rect x="-20" y="${r.y - rh * 0.85}" width="${Math.max(0, x + 20)}" height="${rh * 1.7}"/><circle cx="${x}" cy="${r.y}" r="${R}"/>`; }).join('');
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}"><filter id="g" x="0" y="0" width="100%" height="100%" color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="${blur}"/><feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 24 -10"/></filter><g fill="#fff" filter="url(#g)">${shapes}</g></svg>`;
return `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}")`;
};
vawe.onFrame((t) => { shotB.style.maskImage = goo(t, 0); rim.style.maskImage = goo(t, W * 0.07); }); // rim: an accent full-frame div under BEasing and timing
The clip runs 1.4 s. The look is field.
The clip uses one named ease from core/motion/presets.js. Each is a pair of After Effects handles: influence is how far along the segment the handle reaches, and speed is how fast the value moves at the key, as a multiple of the segment's average speed. Motion in the docs explains both.
| Ease | Leaving a key | Arriving at a key |
|---|---|---|
land | 12% influence, speed 4.8 | 75% influence, speed 0 |
Notes
Stack three layers: shot A, the accent rim, shot B; the last two carry the mask. Rows that start apart (a 0.22 s seeded lag, 0.85 to 1.1 s each) give the lumps; rows that start together give a straight wipe. The alpha contrast (x24 - 10) is what makes the blur read as liquid and not as a soft edge: with a plain blur the edge looks like a feathered mask. Start the fronts a full blur radius outside the frame, or a pale seam shows at the edge on the first frame. Shot A drifts 6 percent away and B settles from 1.08x, so both shots move under the edge. The mask is a pure function of time: no random, no state.
Looks (ground, type, radius, accent) live in demo/demo.css; this snippet keeps neutral tokens.
Sound
Sound: none; the flood is soft and wet to the eye, and a cue on it is a whoosh on every cut.





