Skip to content

DevTools: inspect in-flight animations (phase, target, group, timings) #87

Description

@jonlaing

Motivation

Animation bugs are hard to debug from console warnings alone — the "Animation timeout reached" message tells you something went wrong but not what: which lifecycle phase stalled, which slot the element belongs to, whether the transition ever started, whether an animation group's gate was still closed, or how long each phase actually took. A DevTools view of live animations would collapse most of this into a glance.

What to expose

For every animation currently in progress or recently completed:

  • Target element (with data-effex-key + slot identity)
  • Kind: enter / exit
  • Phase: waiting-for-connectionwaiting-for-paint (hydration only) → applying-enterFromreflowapplying-enterTowaiting-for-eventcleanupdone / timeout
  • Timing: how long spent in each phase
  • Config: the resolved AnimationOptions for this animation (enter, enterFrom, enterTo, exit, exitTo, timeout, stagger delay)
  • Group membership: if animate.group is set, which group + current pending count + gate state
  • Ended by: transition / animation / timeout / skip (from waitForAnimationEvent)

Recent completions (last N, ring buffer) are as valuable as in-flight ones — most animation issues manifest as "the animation ran but didn't do what I expected."

Instrumentation points

Roughly maps 1:1 to lifecycle boundaries we already have:

  • forkSlotEnter / forkSlotRemoval (packages/dom/src/Control/slotAnimation.ts) — start of an animation; emit a "created" event with target, kind, resolved config.
  • runEnterAnimation / runExitAnimation (packages/dom/src/Animation/core.ts) — phase transitions; emit between addBeforeReflow / forceReflow / removeAfterReflow / waitForAnimationEnd / removeAfterAnimation.
  • waitForAnimationEvent (packages/dom/src/Animation/helpers.ts) — emit which resolution path fired (transition / animation / timeout / skip).
  • Animation groups (packages/dom/src/Animation/groups.ts) — emit register / gate-open / complete transitions.

Proposed shape

Same opt-in pattern as #86: a Context.Tag for an AnimationInspector service, unused by default, an Instrumented layer that plumbs into window.__EFFEX_DEVTOOLS__.animations for the panel to read. Zero cost when the tag isn't provided.

Emit events rather than snapshots — the panel can build its own state model (in-flight vs. historical) rather than the runtime being responsible for retention semantics.

Considerations

  • Overhead. Phase-transition emit is on every animation. Should be cheap (single function call) and ideally batched via queueMicrotask if the panel needs it.
  • Interruption. If a slot's scope closes mid-animation (route change during transition), the fiber is interrupted. That interruption should emit a phase change so the panel doesn't show a phantom in-flight animation forever.
  • Correlation. Enter and exit animations on the same key (during a re-mount) should be groupable in the UI — need a stable key that survives the slot re-creation.
  • Reduced-motion. Users with reduced-motion preference get skip short-circuits. Panel should show these as "skipped (reduced motion)" rather than making them look like bugs.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    devtoolsDeveloper tooling: inspection, debugging, DevTools panels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions