iconic_morph library
iconic_morph
Path-level icon animation for Flutter — morph one SVG icon into another, plus 3D constant-stroke spins, draw-on, trace, and idle loops — drawn from your own SVGs. No Rive, no Lottie, no new assets, and ZERO external dependencies (the SVG path parser and the 4×4 matrix math are vendored in-tree).
import 'package:iconic_morph/iconic_morph.dart';
// Morph the bundled demo icons (works out of the box):
IconicMorph(MorphIcons.user, MorphIcons.face);
// Or bring your own SVG — an asset path or a raw string:
IconicMorph.svg(myUserSvg, myFaceSvg);
// A single icon, animated (3D unlock spin):
IconicAnimatedIcon(MorphIcons.lock, effect: const IconSpin3D.unlock());
Classes
- IconAnimationProfile
- A declarative animation profile for ONE icon — how it introduces itself, how it idles at rest, and the plan other glyphs use to morph into it.
- IconAnimations
- The central, declarative registry binding icons → IconAnimationProfile.
- IconBlink
-
An idle blink — the "eye" contours briefly squash shut and reopen on a
loop, with a long rest gap between blinks, so a face glyph feels alive at rest
(e.g.
MorphIcons.face). Everything else is drawn untouched. - IconBreathe
- A gentle idle "breathe" — the icon scales up and back about its center, on a loop. Cheapest effect in the set: it strokes the crisp un-flattened path once and only applies a uniform Canvas.scale, so there is no per-point transform.
- IconContour
- One contour (subpath) of an icon, pre-flattened to a polyline with the cumulative arc-length at each point. This is the data every transform-based effect (3D spin, trim draw-on) walks — sampled ONCE at load and cached, so the paint loop never touches Path.computeMetrics (which crosses into native Skia and is not free).
- IconConverge
- A calm "assemble" entrance: each contour drifts in from a small outward offset — along its own direction from the icon center — while fading up, so a multi-stroke glyph settles into place piece by piece. Softer than the 3D IconSpin3D.flipIn: nothing rotates, the glyph just condenses into focus.
- IconDetailSpin
- A "knock" press animation composed per-contour on one timeline:
- IconEffect
-
A pure, immutable icon-animation strategy. Given parsed IconGeometry and a
raw linear progress
t(0..1 from the controller), it paints ONE frame. - IconEffectPainter
-
The CustomPainter behind every IconEffect. Handles repaint wiring
(driven by the animation controller via
super(repaint:)— no widget rebuild), canvas scaling to viewBox space so effects paint at a constant stroke width, and shouldRepaint comparisons. Pass this to a CustomPaint widget when you want direct control; otherwise IconicAnimatedIcon manages it for you. - IconGeometry
- Parsed, sampled, cached geometry for an icon — the input to every IconEffect. Built from the icon's SVG via the in-package zero-dep reader parseSvgPathData (arcs and smooth curves handled) and sampled into contours. The raw path is kept for effects that want crisp un-flattened geometry (e.g. a breathe scale).
- IconGridPop
- A staggered pop for a grid-style glyph (e.g. a circle + two squares + a plus). Each piece scales up about its own centre and settles in reading order — circle first, then the squares, then the plus — and the plus ALSO does a constant-stroke 3D turn about its own centre as it pops. Snappy; rests as the plain icon (restValue 0), so the pop is an emphasis on tap, not an entrance.
- IconicAnimatedIcon
- An icon that animates via a IconEffect (3D spin, trim draw-on, breathe, and more). Pass an asset path and an effect; the widget handles geometry loading, caching, and animation control.
- IconicAnimatedIconController
- Imperative handle to replay a IconicAnimatedIcon from a parent (a button tap, a list-row appear, a "replay" control). Call play to (re)start the effect from the beginning — interrupt-safe, so rapid taps restart cleanly. stop settles the icon to its rest frame.
- IconicEase
- The engine's easing vocabulary — the handful of velocity profiles its motion is tuned around, named by FEEL so a caller picks a word, not a four-number cubic.
- IconicMorph
- Morphs one icon into another by re-drawing path geometry per frame — no Rive, no Lottie, no new assets, the same engine as IconicAnimatedIcon. Pass from and to asset paths and an optional plan to tune the flight.
- IconicMorphHero
- A persistent, "alive" hero glyph that lives ONCE across screens/steps and AUTO-TRANSITIONS between icons without ever remounting — so there is no flicker, stutter, or replay-from-scratch when the surrounding page changes.
- IconicMorphPainter
-
The painter behind IconicMorph. Holds only the prebuilt MorphGeometry
(no recompute here) + the animation knobs, and repaints off the controller via
super(repaint:). Each frame is one cheap arc-length window walk. - IconicMorphSequence
-
A chain of morphs — one persistent glyph that flows through a string of
icons in order (
A → B → C → …), morphing from each to the next, resting briefly on each. The scalable answer to "morph 2, 3, or more icons": pass the list, get a single living glyph that walks it. - IconicShapeMorph
- Drop-in widget: morph sibling icon from into to as a SHAPE morph. Rests on from; plays once on load (or via controller); reduced motion settles straight on to. For a morph that lives inside a larger stateful glyph (several destinations, bespoke rest states), drive ShapeMorphPainter with your own controller instead — this widget is the one-shot convenience.
- IconicSpringCurve
-
A critically-damped spring as a Curve — the exact displacement profile a
platform spring animation follows, folded into curve space so any plain
AnimationControllercan ride it. - IconImage
- Renders a static (un-animated) icon by stroking its SVG path at a constant width — the same geometry the animated effects use, so it stays pixel-consistent with every IconicAnimatedIcon at rest.
- IconInboxRiffle
-
A realistic two-sheet riffle for a stacked-tray glyph (e.g.
inbox-04): the BACK sheet and FRONT sheet deal out and return in a nested ping-pong — the back leaves first and returns last, the front nested inside (back-out → front-out → front-in → back-in) — while every moving sheet is occluded by whatever sits in front of it. Each sheet is masked OUTSIDE the silhouettes of the sheets/tray drawn after it, so the back sheet truly slides BEHIND the stack (sinking behind the front sheet + the planted tray, then rising back up from below into its slot) instead of floating over it. - IconLineShrink
- Shrinks each of the glyph's contours along its long axis by shrink viewBox units (both ends pull in toward the center) and lets it spring back, one at a time in top-to-bottom order. Works well on glyphs with horizontal bars (e.g. a hamburger menu) — each bar briefly shortens in sequence, a clean ripple with no spin.
- IconLockEngage
- One-shot "lock engages" — the lock physically CLICKS shut without changing icon (no morph): the whole glyph gives a quick grow-and-settle (a clunk), a small damped vertical bob, and the center keyhole "dot" spins as if a mechanism turned. Use to confirm a passcode is set / something locked; pair with a medium haptic for the physical intent.
- IconMorphPlan
-
Recipe for a
IconicMorph— how the source glyph becomes the target. - IconMotion
-
Motion durations for the icon-animation engine. Every effect's default
durationreads from here, so timing stays consistent and easy to tune in one place. - IconSequence
- Composes effects on a single timeline — e.g. "draw the icon on, then flip it in 3D". Each IconStep receives a LOCAL t re-normalized to its window and paints additively onto the same canvas. This is the seam that scales the engine from a handful of effects to rich, choreographed sequences.
- IconShuffle
- A path-level shuffle that works on the glyph's OWN contours — it does NOT move the whole icon. Each contour (e.g. the inbox lid / body / tray) is dealt down + faded out and immediately respawns from above + fades in, in a staggered top→bottom cascade — the icon's layers riffle through themselves like a shuffled stack.
- IconSpin3D
- True 3D rotation with a constant stroke width.
- IconStep
- One step of an IconSequence: an effect that plays over the start..end window of the parent's normalized timeline. Windows may overlap (cross-fade); after its window a step holds at local t = 1 (its settled frame).
- IconTrace
- A verify pulse — a soft glowing node runs along the icon's own centerline (a short bright tail trailing behind it) and exits, leaving the plain icon. Because the glow follows the sampled path geometry rather than a flat diagonal, the light visibly travels the glyph's actual shape — around a shield and out through its check, down a lock's shackle — reading as the icon being energized / authenticated, not a generic sheen sliding over it. Sibling to the constant-stroke 3D spin: both exploit the centerline the engine already samples, so it works on every icon with no per-icon authoring.
- IconTrimDraw
- Trim-path "draw-on" — the icon is drawn as if by a pen, growing from 0 to its full length. Walks the pre-sampled polylines + cumulative arc-length (no per-frame Path.computeMetrics), interpolating the final partial segment so the leading edge moves smoothly rather than snapping point to point.
- IconWeightPulse
- A stroke-weight "emphasis" pulse — the line swells from its base width to a touch heavier and settles back, with an optional hair of scale. Impossible with a baked bitmap icon (the weight is re-stroked each frame) and calmer than a bounce: a quiet "saved / confirmed" beat.
- MorphGeometry
- All morph geometry that depends only on (from, to, plan) — the precomputed hero lines, quintic flight curve, master polyline + arc-length table, and the source/target contour lists. Built once per (icon, plan) change and handed to the painter so per-frame repaints do zero geometry work.
- MorphIcons
-
Demo icons bundled with the package — three glyphs that work out of the box
for morphing examples (
user → face → lock). No setup required: - PathMorph
- Pure geometry utilities for icon morphing — no Flutter widget dependencies, so they are unit-testable on the VM.
- Projector3D
- Projects an icon's centerline points through a perspective+rotation matrix, returning a screen-space Path to stroke at a constant width.
- ShapeMorphGeometry
- The precomputed shape-morph: still chrome, bending pairs, and the contours that leave or arrive. Pure and immutable — build once per (from, to, spec) and hand it to a ShapeMorphPainter; never rebuild per frame.
- ShapeMorphPainter
-
Paints a ShapeMorphGeometry at the clock's current value: still chrome
with its ink lerping, pairs bending point-for-point with theirs, exits and
enters trimming under the StrokeTaper laws. Drive it with any
Animation<double>— an IconicShapeMorph for the drop-in case, or your own controller when the morph is one voice inside a larger stateful glyph. - ShapeMorphPair
- One paired feature: same-count, direction-aligned point lists — the line that bends from from into to.
- ShapeMorphSpec
- The SHAPE morph — the engine's second morph instrument, for icons that are SIBLINGS rather than strangers.
- StrokeTaper
-
The weight law for a trim-path end — how the ink's THICKNESS behaves while
a stroke draws on or un-draws. The companion to the arc-length window
(
PathMorph.trimmedRange), which only ever owns the ink's LENGTH.
Enums
- MorphAssemble
- How a morph's ARRIVING (target non-hero) contours assemble around the travelling hero line — the bits of the NEW glyph that aren't the line that flies. Decoupled from how the OLD glyph leaves (MorphExit).
- MorphExit
- How a morph's LEAVING (source non-hero) contours disappear — the bits of the OLD glyph that aren't the source hero line. Decoupled from MorphAssemble (how the new glyph arrives) so entrance and exit choreograph independently.
- Spin3DAxis
- Which way a glyph tumbles in depth.
Constants
- kIconStrokeWidth → const double
- Default stroke width in viewBox units (2px at a 24-unit viewBox). Matches the typical stroke weight SVG icons are authored at, so an animated re-stroke is weight-for-weight identical to the static IconImage. Painters are parameterized so individual effects can override, but this constant is the shared default.
Functions
-
appendContourUpTo(
Path path, IconContour c, double upTo) → void -
Appends the first
upToarc-length units of contourcontopath, interpolating the final partial segment so the leading edge moves smoothly. Re-closes a fully-drawn closed contour so its final join is a miter rather than an open round-cap seam. -
tintStroke(
Paint base, double alpha, {Color? toward, double towardT = 0}) → Paint -
Returns a copy of
basewith its alpha multiplied byalpha, optionally lerpedtowardTof the way towardtoward(for a glow or lighten effect). Returnsbaseunchanged when alpha is 1 and no lerp is requested, so the common fully-opaque path allocates nothing.
Typedefs
-
IconGeometryResolver
= Future<
({bool isFill, List< Function(String asset)String> pathData, double viewBox})?> -
Supplies an icon's geometry from your own store — the return shape of
IconGeometry.resolver.
pathDatais the rawdattribute(s) from the icon's<path>element(s),viewBoxis the square viewBox edge length, andisFillmarks a filled glyph (vs a stroked outline). Returnnullfor an asset to fall back to the default SVG-asset loader.