Skip to content

Ways to morph

Soft, even and index, the three ways side by side, the four steps that make soft what it is, and a frame as anchors and handles.

@cesarvenzac/morphv1.0.0

morph(from, to, way) takes a way to morph, or { way, extra }. Soft is the default and the reason for the package; the other two are here to compare, and for the drawings they suit.

  • In order

  • Evenly

  • Softly

Icons
SlowTracePoints
The three ways side by side on Lucide's icons.

Soft

Pieces are paired by their shape, each moved whole (its place, size and turn apart from its shape), blurred along its length so a corner arrives rounded, and drawn as a few fitted cubic curves, sharp only at an end's own corners near that end. It's "soft", and what morph does unless told otherwise.

Even

"even" resamples each outline into points a unit apart, matches them for the least travel and moves them in straight lines, drawn as a polygon: flubber's way.

Index

"index" pairs path commands in the order they were written, as most morphing libraries do. It's right when both sides were drawn alike, the same commands in the same order; otherwise points cross over.

Steps

Soft is even with four steps on, each switchable alone, to see what each does:

import { EVENLY, morph } from "@cesarvenzac/morph";

morph(Plus, X, { ...EVENLY, shape: true }); // even, paired by shape
  • shape: pair points by the shape they make, not by how far they travel.
  • whole: move each piece whole, its place, size and turn apart from its shape.
  • round: blur each outline along its length, most halfway, so a corner arrives rounded.
  • curves: draw fitted cubics rather than a polygon, sharp only at an end's own corners.

SOFTLY is all four on, soft itself, and EVENLY none.

Anchors and handles

shapes(t) is the frame as an editor shows a path: each piece's nodes, an anchor with its in and out handles, whether it's closed, its width, and an island's holes. Between 0 and 1, at is drawn from them, so the two agree; at 0 and 1 at is each side exactly, and shapes the way's own take on it. nodesData(nodes, closed) writes nodes back as path data. points(t) is each part's outline before it's drawn as curves, for measuring.

import { nodesData } from "@cesarvenzac/morph";

for (const shape of m.shapes(t)) {
  outline(nodesData(shape.nodes, shape.closed)); // the path
  for (const node of shape.nodes) dot(node.at); // its anchors
}

Why each step is there, measured, is in Morphs without spikes.