A streaming chart · TanStack Charts
The trend indicator is a morph riding the series: when it turns, the shape and the color turn with it, and icon, line and area share one accent driven by the data. Nudge the drift and watch the flip.
canvasTarget turns any canvas or 2D context into a morph target. The icon stops being a DOM node and becomes pixels you own: a GPU texture inside a map, a sprite composited into a chart, a favicon, an OffscreenCanvas in a worker.
The trend indicator is a morph riding the series: when it turns, the shape and the color turn with it, and icon, line and area share one accent driven by the data. Nudge the drift and watch the flip.
Every pin is a Mapbox StyleImage whose pixels come from a morphing 2D canvas: place it, watch it learn its address, hover it, save it. Saving rolls a wave through the map's own texture, pins included.
One adapter call around the plain DOM driver. Everything else in the demos above (tinting, dirty flags, StyleImage plumbing) is host-side compositing of the pixels this produces.
import { createMorph } from "morphicons/dom";
import { canvasTarget } from "morphicons/adapters";
import { Flag, MapPin } from "lucide"; // data, not components
const sprite = document.createElement("canvas");
sprite.width = sprite.height = 64;
const morph = createMorph(
canvasTarget(sprite, { color: "#fff", onWrite: () => map.triggerRepaint() }),
MapPin,
);
morph.morphTo(Flag, "smooth");
// the canvas is pixels you own: a Mapbox StyleImage, a chart badge,
// a WebGL texture, a favicon, an OffscreenCanvas in a worker
Mapbox GL and the chart runtime load only inside this tab, and only as their card scrolls into view: the core showcase stays as light as the library it demos. The save wave is Canvas UI's Ripple shader (MIT + Commons Clause), adapted to sample the map's own canvas.