Skip to content

fix(mix): make animation transitions target-correct#965

Open
leoafarias wants to merge 2 commits into
mainfrom
fix/animation-transition-correctness
Open

fix(mix): make animation transitions target-correct#965
leoafarias wants to merge 2 commits into
mainfrom
fix/animation-transition-correctness

Conversation

@leoafarias

@leoafarias leoafarias commented Jul 11, 2026

Copy link
Copy Markdown
Member

Related issue

Closes #964 — Fix animation transition lifecycle and target correctness (P0).

Description

Repairs the curve, spring, phase, and keyframe animation drivers as one
lifecycle-contract change so interrupted transitions hold the visible value,
removing a phase/keyframe config reaches the new target immediately, phase
delays use the correct transition index, and phase completion fires exactly
once. Ships 43 regression tests that fail on main and pass with the fix.

Changes

  • Interrupted delay: CurveAnimationDriver holds the displayed spec
    (_tween.begin) during a delay instead of snapping back to _initialSpec.
  • Driver replacement: a centralized _outgoingConfigFor() reuses an
    outgoing config only for curve/spring; removing a phase/keyframe config
    disposes the old driver and shows the new target on the same update.
  • Phase timeline: delay placement uses the destination transition's config
    for both the check and its weight (including last → first).
  • Completion: phase completion fires once via PhaseAnimationConfig.onEnd
    (registered once on the controller); the leaking curveConfigs.last.onEnd
    path is removed and onEnd is exposed on phaseAnimation().
  • Validation: phase/keyframe configs are validated by their drivers —
    validate() runs in the driver constructor and updateDriver, before the
    controller runs — covering empty phases, count mismatch, negative
    durations/delays, zero-duration loops, and duplicate track ids. Configs stay
    const-constructible.
  • Tests: +43 regression tests across the full 5×5 driver matrix,
    interrupted delays, listener accumulation, delay boundaries, and validation
    (config-level and driver-wiring).

Review Checklist

  • Testing: 2772 tests pass; the new regression tests fail on main and
    pass with the fix; dart analyze and dcm analyze --fatal-style --fatal-warnings are clean.
  • Breaking Changes: yes — phase completion now fires once via
    phaseAnimation(onEnd:); the previously-leaking curveConfigs.last.onEnd
    path is no longer read. Called out here for release notes.
  • Documentation Updates: API dartdoc for phaseAnimation / onEnd
    updated; no README changes needed.
  • Website Updates: the btwld/mix-docs site should note the phase
    onEnd behavior change — separate repo, tracked as a follow-up.

Additional Information (optional)

The onEnd change is a bug fix: a probe showed the old reachable path fired
1 + rebuilds times (3× after two updates) while the dedicated field was dead;
the fix makes it fire exactly once through a discoverable param. Config
validation lives in a driver-invoked validate() rather than the constructors
so the public const construction path is preserved.

Repair curve, spring, phase, and keyframe driver transitions as one
lifecycle-contract change so they always render the requested target.

- Curve delay holds the currently displayed spec (tween begin) instead of
  snapping back to the driver's immutable initialSpec on interruption.
- Removing a phase/keyframe config disposes the old driver and exposes the
  new target on the same update; only curve/spring are reused for an
  animate-out, centralized in _outgoingConfigFor.
- Phase delay placement uses the destination transition's config for both
  the delay check and its weight (incl. last -> first).
- Phase completion fires exactly once via PhaseAnimationConfig.onEnd,
  registered once on the controller; the leaking curveConfigs.last.onEnd
  path is removed and onEnd is exposed on phaseAnimation().
- Phase/keyframe configs validate inputs at construction (empty phases,
  count mismatch, negative durations/delays, zero-duration loops,
  duplicate track ids).

Adds 41 regression tests (full old->new driver matrix, interrupted
delays, listener accumulation, delay boundaries, validation) that fail on
origin/main and pass with the fix.
@github-actions github-actions Bot added the mix label Jul 11, 2026
Restore `const` on PhaseAnimationConfig and KeyframeAnimationConfig by moving
their invariant checks into a `validate()` method that the phase/keyframe
drivers invoke in both their constructor and updateDriver. Invalid configs
still fail before controller execution, while downstream const construction
keeps compiling. KeyframeTrack keeps its own segment assert (it was never
const). Adds driver-level tests proving each driver rejects an invalid config
before running.

Addresses code-review feedback on const compatibility.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix animation transition lifecycle and target correctness

1 participant