Nine parts of theory. Here is the order you would actually write it in.
The order is the content. Each step needs the one above it to already exist, which is not visible from outside and is where a first attempt at this usually stalls: people start at the interpolator, because that is the interesting part, and it has nothing to walk.
This site is closed source and there is no package to install. None of this is hard enough to need a dependency, and a you wrote yourself is one you can change when your icons change. The file names below are the ones this implementation uses. They are here to show how the pieces divide, not to be fetched.
1. A parser. Take a d string and produce a list of subpaths, each a list of
segments. This is the least glamorous part and the one most likely to have a bug in it.
Test it against a real icon set rather than examples you wrote. Lucide alone exercises the
H shorthand, an implicit lineto after a moveto (X is "M18 6 6 18"), a relative moveto
followed by an implicit relative lineto, negative numbers acting as their own separator
("m21 21-4.34-4.34"), and numbers with no leading zero (".56.56" in Heart).
One trap worth knowing before you hit it: arc flags cannot be tokenised generically.
a1 1 0 011 1 means flags 0 and 1 followed by the point 1,1, and a normal number
scanner reads 011 as eleven. That forces a hand-written scanner rather than
tokenise-then-parse.
2. A rig format and a validator. Slots, per-slot segment counts, and the icons. Write the validator early. It catches count mismatches, violations and cycles at author time, which is much cheaper than finding them by watching an animation.
3. An interpolator. Walk two icons' numbers, produce a frame at t. Twenty lines, and
the thing every other piece is measured against.
4. A serialiser. Frame to d string. The only subtlety is rounding, and it matters
more than it sounds: emit too many decimals and the output triples in size, too few and the
shape visibly steps.
5. The rest is optional. A compiler that bakes frames to CSS keyframes, a for reverse and interruption, an importer that fits arbitrary icons into a rig. Each is worth building and none is needed for a working morph.
Tick them off as you go. This is kept in your browser, separately from which chapters you have read, so resetting one does not touch the other.
| Piece | File |
|---|---|
| Parser and arc handling | lib/morph/compile/parse.ts |
| Rig format and validation | lib/morph/core/types.ts, core/geometry.ts |
| Interpolator | lib/morph/core/interpolate.ts |
| Serialiser | lib/morph/core/serialize.ts |
| Procrustes alignment | lib/morph/compile/align.ts |
| Polar sampling | lib/morph/compile/polar.ts |
| CSS emitter | lib/morph/compile/css.ts |
| Importer and confidence | lib/morph/compile/import.ts |
| Runtime driver | lib/morph/runtime/driver.ts |
| React binding | lib/morph/react/index.ts |
Three pieces were worked out from other people's projects rather than from scratch: the
alignment maths, the conversion from arcs to cubics, and the frame loop that drives every
animation. All of it MIT, and THIRD-PARTY-NOTICES.md at the root of this repository names
who wrote what.
The idea did not start here either. The colophon says where it came from.
Do not build a runtime solver. Good ones exist, they are MIT, and being 95% as good is being visibly worse. If you need arbitrary pairs at runtime, use one.
Do not build the studio before the compiler. A visual editor for sounds like the fun part and is worthless until there is something to correct.
Do not chase fill support. Everything here assumes stroke icons with an open path. Filled shapes bring winding rules and holes, which is a different problem wearing the same hat.
If you remember nothing else: correspondence is the problem, interpolation is arithmetic.
Every hard decision in this manual was about which stroke becomes which stroke. Once that is settled, animating between two shapes is averaging numbers, and the browser will do most of it for you.
The rest was working out where to put the answer.
Enough to go and build this yourself, in the order that works.