IconMorphPlan class
Recipe for a IconicMorph — how the source glyph becomes the target.
The choreography the user feels — a travelling "worm", not a cross-fade:
- One real line of the SOURCE is the hero — e.g. the user's shoulders arc, picked by sourceAnchor. The worm rests on it.
- Its head launches along the line's own tangent and flies a smooth quintic-Hermite curve (flightLaunch, flightLand, flightBow, flightBias) over to the entry of a real TARGET line — e.g. the face's smile, picked by heroAnchor — arriving along the target's tangent so it eases in, never cutting across.
- The worm slides onto the target, the tail catching up (headLead) and drawing the smile on. Mechanically: a fixed-length window slides by arc length along one master path (source → flight → target).
- Meanwhile the source's other contours (the head ring) leave — by default they un-draw / retract (MorphExit.trim) rather than fade — and the target's others (brackets, eyes, nose) draw on (MorphAssemble — trim / scale / 3D flip), assembling the new icon around the line that travelled.
Everything is a tunable here so the SAME engine drives any pair of icons.
This is pure data — the geometry it produces lives in MorphGeometry, the
painting in IconicMorphPainter.
- Annotations
Constructors
- IconMorphPlan({Duration duration = IconMotion.iconMorph, Curve curve = IconicEase.flight, int samples = 200, Offset? heroAnchor, int? heroTargetIndex, Offset? sourceAnchor = const Offset(12, 20), int? sourceIndex, double flightLaunch = 1.5, double flightLand = 1.5, double flightBow = -0.40, double flightBias = 0.5, double flightRunway = 2.0, double headLead = 2.2, double headFade = 0.45, double flipStart = 0.55, double flipStagger = 0.1, double exitTaper = 0.5, double exitFade = 0.75, double assembleFade = 0.35, double taperFloor = 1, double assembleTaper = 0.18, double perspective = 0.0028, MorphAssemble assemble = MorphAssemble.trim, MorphExit exit = MorphExit.trim, bool flipSource = false, bool flipTarget = false})
-
const
Properties
- assemble → MorphAssemble
-
How the ARRIVING (target) non-hero contours assemble — MorphAssemble.trim
(draw-on, the default), MorphAssemble.scale (zoom in), or
MorphAssemble.flip3d (the 3D flip). Governs the NEW glyph only.
final
- assembleFade → double
-
Emergence span (0..1) — the share of an arriving contour's own draw
over which its ALPHA ramps from nothing to full. The mirror of exitFade.
final
- assembleTaper → double
-
Nib press-down (0..1) — the fraction of an arriving contour's draw-on
(MorphAssemble.trim) over which its stroke weight ramps from taperFloor
up to full, the mirror of exitTaper. Like it, inert unless taperFloor
is lowered below 1. Default 0.18.
final
- curve → Curve
-
The worm's temporal ease — the velocity profile the head and tail ride
along the master path. Defaults to IconicEase.flight (peak velocity at
the first frame, long soft settle — the signature). Direction-aware: a
reverse play mirrors it so the worm still launches fast and lands slow
going backward. Swap in IconicEase.snap for a spring launch or any
Curve of your own.
final
- duration → Duration
-
Total play time. Prefer IconMotion constants for consistent timing.
final
- exit → MorphExit
-
How the LEAVING (source) non-hero contours disappear — MorphExit.trim
(un-draw / retract, the default), MorphExit.fade (alpha fade), or
MorphExit.scale (shrink + fade). Governs the OLD glyph only, independent
of assemble.
final
- exitFade → double
-
Dissolve span (0..1) — a leaving contour's ALPHA fades to nothing over
the last
1 - exitFadeof the whole animation. This is the whole vanish. Default 0.75 = a quarter of the morph, ≈160 ms at the default duration.final - exitTaper → double
-
Pen-lift taper (0..1) — the point in a leaving contour's exit after which
its STROKE WEIGHT starts easing down toward taperFloor.
final
- flightBias → double
-
Bow position — where along the flight the flightBow hump peaks (0..1;
0.5 = mid). Shift toward 0 to fatten the launch side, toward 1 the landing.
final
- flightBow → double
-
Lateral bow — signed swing perpendicular to the head→entry chord, as a
fraction of the gap (≈ -0.8…0.8; 0 = no swing). When the two tangents
near-oppose, a straight flight has to reverse hard through the middle (the
"sharp turn"); a bow swings the whole path wide to ONE side instead, turning
that reversal into a single broad arc. Sign picks the side (CW vs CCW); you
own the magnitude so it never balloons. Added as a bump that's flat at both
ends, so it never disturbs the launch/landing tangents.
final
- flightLand → double
-
Landing breathing — the quintic landing-velocity as a fraction of the
gap (≈0.15–0.9). Higher = it eases IN more gradually onto the target tangent
(a longer, gentler touchdown). Split from flightLaunch so take-off and
landing can breathe independently.
final
- flightLaunch → double
-
Launch breathing — the quintic launch-velocity as a fraction of the
head→entry gap (≈0.15–0.9). Higher = the flight eases OUT more gradually off
the source tangent (a longer, gentler take-off runway).
final
- flightRunway → double
-
Runway — a STRAIGHT breathing segment (viewBox units, e.g. ~20 at a 24
viewBox) along the tangent at EACH end before the curve is allowed to bend.
The launch leaves dead-straight for this far, then curves; the landing
arrives dead-straight for the last stretch. 0 = the curve bends immediately
off the tangent (no straight runway). Clamped to ≤ 45% of the head→entry gap.
final
- flipSource → bool
-
Reverse the resolved SOURCE hero line (swap its head/tail) AFTER the default
"head on the right" orientation — so the worm launches from the other end of
the source line. Use per-direction when the default end reads wrong.
final
- flipStagger → double
-
Per-contour flip-in delay (auto-normalized to the contour count).
final
- flipStart → double
-
When the target's non-hero contours start flipping in (0..1).
final
- flipTarget → bool
-
Reverse the resolved TARGET hero line (swap entry/head) AFTER the default
"entry on the left" orientation — so the worm lands lying the other way.
final
- hashCode → int
-
The hash code for this object.
no setteroverride
- headFade → double
-
Window
0..headFadeover which the source's non-hero contours LEAVE as the morph runs — it caps whichever exit choreography is active (un-draw, fade, or shrink), NOT just a fade. Default 0.45; the trim un-draw then caps at 0.35 and fade/scale at 0.18, so a smaller headFade tightens the active exit.final - headLead → double
-
How much the worm's head leads its tail in time (>1). 1 = head and tail
move together (it slides rigidly); higher = the head launches ahead and the
tail catches up, so the worm stretches out over the flight and draws the
target on as the tail lands.
final
- heroAnchor → Offset?
-
Viewbox-space point used to pick the hero TARGET contour: the contour whose
centroid is nearest this anchor becomes the morph's destination line — e.g.
Offset(12, 16)for a mouth. Order-independent, so it's the robust selector.final - heroTargetIndex → int?
-
Explicit hero target contour index — wins over heroAnchor when set.
final
- perspective → double
-
3D perspective strength for the flip-in (used only when assemble is
MorphAssemble.flip3d; see
Projector3D).final - runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- samples → int
-
Points the hero source + target lines are each resampled to. More = a
smoother morph at a little more cost. >= 2.
final
- sourceAnchor → Offset?
-
Viewbox-space point used to pick the hero SOURCE contour — the line that
morphs into the target. Defaults to the glyph's lower edge
Offset(12, 20), e.g. the user's shoulders arc.final - sourceIndex → int?
-
Explicit hero source contour index — wins over sourceAnchor when set.
final
- taperFloor → double
-
Ink floor (0..1) — how thin a taper may ever take the stroke, at either
end. Default 1: stroke weight is never touched.
final
Methods
-
copyWith(
{Duration? duration, Curve? curve, int? samples, Offset? heroAnchor, int? heroTargetIndex, Offset? sourceAnchor, int? sourceIndex, double? flightLaunch, double? flightLand, double? flightBow, double? flightBias, double? flightRunway, double? headLead, double? headFade, double? flipStart, double? flipStagger, double? exitTaper, double? exitFade, double? assembleFade, double? taperFloor, double? assembleTaper, double? perspective, MorphAssemble? assemble, MorphExit? exit, bool? flipSource, bool? flipTarget}) → IconMorphPlan -
Returns a copy with selected fields overridden. Useful for tuning a base
plan without mutating it — e.g. a slider can override
flightBowwhile keeping all other fields from the original. -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
resolveHeroTarget(
List< IconContour> targets) → int - Which target contour the source morphs INTO.
-
resolveSource(
List< IconContour> sources) → int - Which source contour is the one that morphs (the rest fade out).
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
override