A morph has to decide what path each point takes between its two positions. The obvious answer is a straight line, and for most pairs it is also the right one. For a rotation it is visibly wrong.
Interpolating coordinates directly means every point travels the straight line between where it starts and where it ends. When the correct motion is a rotation, that straight line is the chord of the arc the point should have travelled, and a chord is shorter than its arc.
The shape therefore shrinks on the way across and grows back at the end.
| Pair | Linear | Polar | Cost |
|---|---|---|---|
| arrow-right to arrow-down | 204 B / 1217 B 2 kf / 9 kf |
At 180 degrees the two endpoints swap places, so the chord passes through the centre and the shape collapses to a single point mid-flight.
| Pair | Linear | Polar | Cost |
|---|---|---|---|
| arrow-right to arrow-left | 198 B / 2301 B 2 kf / 17 kf |
The alignment between the two shapes is solved once, at build time, into a rotation, a scale and a . Each part is then interpolated in the space where it is linear: the angle linearly, the scale logarithmically, and the leftover deformation as a plain lerp in the aligned frame.
If the two shapes are the residual is zero, the bracket is constant, and the motion is a pure rotation.
None of that maths ships. The compiler samples the polar path at build time and emits the samples as ordinary keyframes, and the browser interpolates between adjacent ones, which is all it was ever going to do.
The sample count is chosen per pair against a deviation budget, so a pair with no rotation still costs two keyframes and only real curvature pays for more.
Progress does not have to come from the driver. seek renders the pair frozen at any value,
which is what a drag or a scroll position would drive.
If two shapes are not congruent there is no rigidity to preserve, and the rotation term is
decoration. The compiler checks the residual and falls back to two keyframes, which in
lib/morph is compileAuto, the one entry point that decides between the two routes for
you rather than making you pick.
An imported search to x, a circle becoming a line with a residual of 0.88, drops from
17 keyframes to 2 with no visible loss.