Lab

The authoring harnesses. Not product — they exist to decide numbers by looking at things side by side: how many discrete poses, what to do with the spring's tail, how an unvalidated pair looks. What gets decided here is what ends up as the library's default.

Free-form morph — build your sequence

The core pairs subpaths by proximity — if two icons share nothing in common, there's no good geometric match to find. When that happens, the engine detects it on its own and uses a fade (opacity, no points to interpolate) instead of forcing a deformation that would look worse. Legs marked fade in the chain are those cases — that's not an error, it's the fallback working.

a-arrow-downa-arrow-upa-large-smallaccessibilityactivityadair-ventairplayalarm-clockalarm-clock-checkalarm-clock-minusalarm-clock-offalarm-clock-plusalarm-smokealbumalign-center-horizontalalign-center-verticalalign-end-horizontalalign-end-verticalalign-horizontal-distribute-centeralign-horizontal-distribute-endalign-horizontal-distribute-startalign-horizontal-justify-centeralign-horizontal-justify-endalign-horizontal-justify-startalign-horizontal-space-aroundalign-horizontal-space-betweenalign-start-horizontalalign-start-verticalalign-vertical-distribute-centeralign-vertical-distribute-endalign-vertical-distribute-startalign-vertical-justify-centeralign-vertical-justify-endalign-vertical-justify-startalign-vertical-space-aroundalign-vertical-space-betweenambulanceampersandampersandsamphoraanchorangleantennaanvilapertureapp-windowapp-window-macapplearchivearchive-restorearchive-xarmchairarrow-big-downarrow-big-down-dasharrow-big-leftarrow-big-left-dasharrow-big-rightarrow-big-right-dasharrow-big-uparrow-big-up-dasharrow-downarrow-down-0-1arrow-down-1-0arrow-down-a-zarrow-down-from-linearrow-down-leftarrow-down-narrow-widearrow-down-rightarrow-down-to-dotarrow-down-to-linearrow-down-uparrow-down-wide-narrowarrow-down-z-aarrow-leftarrow-left-from-linearrow-left-rightarrow-left-to-linearrow-rightarrow-right-from-linearrow-right-leftarrow-right-to-linearrow-uparrow-up-0-1arrow-up-1-0arrow-up-a-zarrow-up-downarrow-up-from-dotarrow-up-from-linearrow-up-leftarrow-up-narrow-widearrow-up-rightarrow-up-to-linearrow-up-wide-narrowarrow-up-z-aarrows-up-from-lineasteriskastroidat-signatomaudio-linesaudio-lines-xaudio-waveformawardaxeaxis-3dbabybackpackbadgebadge-alertbadge-centbadge-checkbadge-dollar-signbadge-eurobadge-indian-rupeebadge-infobadge-japanese-yenbadge-minusbadge-percentbadge-plus
  1. bell
  2. bell-ring
  3. heart
  4. star
  5. circle
  6. square
  7. user
  8. user-round

Amber: no valid geometric morph is available, so glyphFlow falls back to a fade.

Morph benchmark

One pair at a time, 4 variants side by side. The spring only decides the timing: zero animation loop — the keyframes are computed once and the browser interpolates them.

playbackcompareresolution

More steps track the path more closely, at the cost of a bigger keyframe array — fidelity against payload.

Technical details

Adaptive is the real default: it doesn't hand out an even count across all 1767 icons, only the pairs that actually rotate get more. Compare it against 20 steps on bell → bell-ring (should look identical) and against 10 on circle → square (fewer steps, same fidelity, because it barely rotates).

res is the sampling resolution: how many points each subpath is resampled to before the two shapes are paired up. It samples the OUTLINE, not time — it changes how faithfully the curve is followed, never how many frames play.

<gf-icon-morph>

The thin wrapper. A single [icon]: changing it triggers the morph from the previous value. The first render paints static — there's nowhere to transition from.

spring

Underdamped springs overshoot the target and come back. Hit "next" with bouncy and watch the overshoot — that's what didn't used to render.

Baked vs live

Same pair, two engines. Baked precomputes ~20 poses and WAAPI interpolates linearly between them. Live recomputes the exact position every frame — the difference shows most on pairs with real rotation.

baked (WAAPI)
live (rAF)

10 steps

keyframes
10
weight
27.0 KB
duration
737 ms
last leg
61%
deviation
0.001

15 steps

keyframes
15
weight
40.6 KB
duration
737 ms
last leg
55%
deviation
0.000

20 steps

keyframes
20
weight
54.1 KB
duration
737 ms
last leg
51%
deviation
0.000

30 steps

keyframes
30
weight
81.2 KB
duration
737 ms
last leg
45%
deviation
0.000

Adaptive default

keyframes
10
weight
27.0 KB
duration
737 ms
last leg
61%
deviation
0.001