This is the 2D-native counterpart to the 3D FLIP page-transition lab. Rather than orbiting rendered page cards in a perspective scene, it plots the exact quantities that drive the transition: a top-down stage of the two pages and the shared "hero" block, a live readout of the FLIP transform's own Δx/Δy/scale numbers, and an easing-curve timeline you can scrub by hand. Same FLIP (First, Last, Invert, Play) technique underneath — the standard way browsers fake a continuous "shared element" morph across a route change without ever animating layout itself:
First: record start rect (x0, y0, w0, h0)
Last: record end rect (x1, y1, w1, h1)
Invert:
dx = x0 - x1, dy = y0 - y1
sx = w0 / w1, sy = h0 / h1
transform = translate(dx,dy) scale(sx,sy) // Last now LOOKS like First
Play:
animate transform → identity over e(t)
Only a GPU-cheap transform is ever animated — the browser never re-runs layout on every frame, which is why FLIP feels smooth even on complex pages. The "Invert offset / scale" panel plots exactly the (Δx,Δy,sx,sy) pair above as it decays from its inverted value toward identity (0,0,1,1).
The three easing curves e(t) driving that transform:
linear: e = t
ease-in-out: e = t<.5 ? 4t³ : 1-(-2t+2)³/2
spring: e = 1 - e^(-ζωt)[cos(ωd t) + (ζω/ωd)sin(ωd t)]
ωd = ω√(1-ζ²) (underdamped harmonic oscillator)
The spring curve is the same damped-harmonic-oscillator step response that governs a real mass on a spring — it overshoots past 1.0 and settles, which is why spring-based page transitions feel "alive" instead of mechanical. Watch the timeline panel: only the spring curve's dot ever crosses above the e=1.0 line.
Overlap controls how much the incoming page's enter animation starts before the outgoing page finishes its exit — 0% is a strictly sequential exit-then-enter, 100% runs both simultaneously, exactly like a CSS View Transition's cross-fade. The two shaded bands on the timeline panel mark exactly when each page's own local easing window (tA, tB) is active.