Shape morph wipe

When to use
Use when the next shot should grow out of a shape already on screen (a status dot, an avatar, a button) and become the frame: the mask is born as that shape, grows as a circle, then widens and squares off into a rounded card and on past the frame edges. Unlike iris-wipe, the shape itself changes on the way. The detail that sells it is the order: size first, shape second. The circle stays round for the first third, then the width outruns the height and the corners tighten, so the viewer sees a circle turn into a card, not a box that was always a box. Clip: shape-morph-wipe.mp4. Demo: demo/shape-morph-wipe.html.
The code
import '../../core/engine/page-api.js';
import { easeFn } from '../../core/motion/presets.js';
const E = easeFn('land'), W = innerWidth, H = innerHeight, clamp = (u) => Math.min(1, Math.max(0, u));
const whip = easeFn('swap');
const grow = (u) => 0.35 * u + 0.65 * whip(u), lerp = (p, q, u) => p + (q - p) * u;
const r = dot.getBoundingClientRect(), o = { x: r.left + r.width / 2, y: r.top + r.height / 2, d: r.width };
const T0 = 0.4, DUR = 0.85, PAD = 0.04 * H; // PAD: the box ends past every edge, so no corner shows shot A
vawe.onFrame((t) => {
const u = clamp((t - T0) / DUR), g = grow(u);
const h = lerp(o.d, H + 2 * PAD, g); // a circle of diameter h grows first
const w = h + (W - H) * grow(clamp((u - 0.3) / 0.7)); // then it widens into the frame's shape
const cx = lerp(o.x, W / 2, g), cy = lerp(o.y, H / 2, g);
const rad = (Math.min(w, h) / 2) * lerp(1, 0.07, E(clamp((u - 0.35) / 0.55))); // round, then a card corner
next.style.visibility = t < T0 ? 'hidden' : 'visible';
next.style.clipPath = `inset(${cy - h / 2}px ${W - cx - w / 2}px ${H - cy - h / 2}px ${cx - w / 2}px round ${rad}px)`;
nextInner.style.transform = `scale(${lerp(1.12, 1, E(u))})`; // the new shot settles inside the window
prev.style.transform = `scale(${lerp(1, 0.94, g)})`; // the old shot steps back under it
});Easing and timing
The clip runs 1.5 s. The look is swiss.
The clip uses 2 named eases 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 |
swap | 75% influence, speed 0 | 75% influence, speed 0 |
Notes
inset(... round r) is one clip shape that is a circle when the box is square and r is half its side, and a card when r is small, so one property carries the whole morph. Start from a shape at least 4 percent of the frame high, or the first third is invisible. The new shot's content moves toward the viewer (1.12 to 1) while the old one moves away (1 to 0.94): two depths, one direction.
Looks (ground, type, radius, accent) live in demo/demo.css; this snippet keeps neutral tokens.
Sound
Sound: none; the shape grows from a dot the eye is already on, and the new shot's own entrance takes the cue.





