shapcnGitHub

JavaScript

The examples that import shape-aware-morph use the npm package. It is in progress. See Install.

The package exports a plan API that does not touch the DOM, and a small DOM layer. Only the functions listed on this page are stable. The package also exports internal helpers. Do not rely on them.

planMorph

planMorph(from, to, opts?) plans a morph from one icon to another. It returns a plan. from and to are icon names. The plan does not touch the DOM.

import { registerLucide, planMorph } from 'shape-aware-morph';

await registerLucide();
const plan = planMorph('mic', 'mic-off', { easing: 'spring' });
const entries = plan.frame(0.5);   // drawing entries at the middle of the morph
console.log(entries.length, Object.keys(entries[0]));

plan.frame(t) takes a time t from 0 to 1. It returns an array of drawing entries. Each entry has a path string d, an opacity, and a widthScale. It also has the fields key, slot, depth, and occluder.

The next example draws one frame as SVG. It reads d, opacity, and widthScale. It ignores occluder, so overlapping strokes do not mask each other. MorphIcon draws with the masks.

import { registerLucide, planMorph } from 'shape-aware-morph';

await registerLucide();
const plan = planMorph('mic', 'mic-off');
const paths = plan.frame(0.5)
  .map((e) => `<path d="${e.d}" opacity="${e.opacity}" stroke-width="${2 * e.widthScale}"/>`)
  .join('');
const svg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">${paths}</svg>`;
console.log(svg.length > 0);

plan.snapshot(t) returns the exact picture at time t. Pass it to planMorph as the start point, to continue from the middle of a morph.

Options

OptionDefaultMeaning
easingeaseInOutCubicAn easing name (see Element) or a function from t to a number.
stagger0A number from 0 to 0.99.
occlusionnonenone, mask, or fill.
objectsfalsefalse, 'containers', 'single', or true (same as 'single').

The export DEFAULTS holds every engine knob with its default value, frozen. The export easings maps the easing names to functions.

planAlive

planAlive(name, opts?) returns a plan for the alive animation. It has the same frame(t) as planMorph, and a kind field. The icon looks the same at frame(0) and at frame(1). The kind is one of radiate, ripple, swing, or pop.

import { registerLucide, planAlive } from 'shape-aware-morph';

await registerLucide();
console.log(planAlive('bell').kind);   // 'swing'
console.log(planAlive('sun').kind);    // 'radiate'

alive

alive(el, opts?) wires the alive animation to an element in code. It plays on pointer enter and on keyboard focus. el is a MorphIcon or a <morph-icon> element. It returns a function that removes the listeners.

<button type="button" aria-label="Notifications"><morph-icon name="bell" size="32"></morph-icon></button>
<script type="module">
  import { defineMorphIcon, registerLucide, alive } from 'shape-aware-morph';

  await registerLucide();
  defineMorphIcon();
  const icon = document.querySelector('morph-icon');
  const stop = alive(icon);   // call stop() to remove the listeners
  console.log(typeof stop);
</script>

The attribute hover="alive" does the same without code.

defineMorphIcon

defineMorphIcon(tagName = 'morph-icon') defines the custom element and returns its class. It returns the existing class if the tag is already defined. It returns null when there is no DOM, for example in Node.

<script type="module">
  import { defineMorphIcon } from 'shape-aware-morph';

  defineMorphIcon('my-icon');   // <my-icon> works like <morph-icon>
  console.log(customElements.get('my-icon') !== undefined);
</script>

registerIcons

registerIcons(map) adds icons to the registry. The icons join the Lucide family: 24 grid, stroke width 2. The map goes from a name to an icon node. An icon node is a list of [tag, attributes] pairs.

<script type="module">
  import { defineMorphIcon, registerLucide, registerIcons } from 'shape-aware-morph';

  await registerLucide();
  registerIcons({
    'my-dash': [['path', { d: 'M5 12h14' }]],
  });
  defineMorphIcon();

  const icon = document.createElement('morph-icon');
  icon.setAttribute('name', 'my-dash');
  document.body.append(icon);
  setTimeout(() => icon.setAttribute('name', 'plus'), 500);
</script>

Other exports

These exports are listed in the package README and typed in index.d.ts.

ExportWhat it does
registerLucide()Loads the Lucide icons into the registry. Returns a Promise of the icon map.
planEffect(name, direction, effect, opts?)Plans an appear ('in') or disappear ('out') effect.
MorphIconThe class behind the element. new MorphIcon(target, opts) works on an <svg> or a container.
getIconNames(withShapes?)Lists the registered icon names.
iconToSVG(nameOrNode, opts?)Returns static SVG markup of an icon.
registerFamilyFile(json)Registers a family spec.
registerFamilyIcons(family, icons)See Icons.
registerSVGs(svgs, opts?)See Icons.
DEFAULTS, easingsThe engine defaults and the easing functions.

Markdown version