Animation regression testing v0.1.0-alpha

Your code changed.See how yourinterface moves.

MotionPR drives your app in Chromium, records every animation and scroll as data, compares it with an approved baseline, and opens a report where both versions play on one clock.

npm install -D @erenthedeveloper0/motionpr@alpha

Baseline 320 ms · cubic-bezier(0.16, 1, 0.3, 1)Candidate 560 ms · ease-in-out

The demo app's navigation panel as MotionPR captured it, 5× slower: one light per version rides the horizon with its real timing, and the arc opens as far as they differ.

  • Native CSS
  • WAAPI
  • GSAP
  • Anime.js
  • Lenis

01 The change review cannot see

One line in a pull request.
A different interface in your hands.

styles.css · nav-panel
.nav-panel {
  transform: translateX(100%);
-  transition: transform 320ms var(--expo-out);
+  transition: transform 560ms ease-in-out;
}

The diff reads like a tidy-up. MotionPR replays both versions on one clock and measures what changed:

The navigation panel of the demo app: baseline 320 ms on cubic-bezier(0.16, 1, 0.3, 1), candidate 560 ms on ease-in-out. MotionPR reported a duration and an easing change (warnings).

Real output · demo app · scenario navigation · checkpoint open

02 How it works

Capture. Analyze. Compare.
Inspect. Report.

  1. Step 1 · Capture

    Real input, in a real browser.

    MotionPR opens each scenario in Chromium, injects its agent before your scripts run, and drives the page with clicks, hovers, key presses and wheel events. Every CSS transition, CSS animation and Web Animation is discovered as it starts; GSAP, Anime.js and Lenis report through adapters.

  2. Step 2 · Analyze

    Replayed at exact times, not recorded.

    When motion settles, the window is replayed deterministically: native animations through paused clones, engines with callbacks muted. Computed styles, geometry and frames are sampled at chosen times, so the same build gives the same data on every run.

  3. Step 3 · Compare

    Matched by identity. Compared as curves.

    Records are paired across versions by element identity, type and name. Durations, delays, easing curves (65 samples each), staggers, trajectories, timelines, scroll metrics and settled pixels are compared, and every difference is graded by a named rule.

  4. Step 4 · Inspect

    Both versions, one clock.

    The offline report plays baseline (blue) and candidate (peach) side by side, with each animation's delay, duration and easing on a shared timeline, and the largest deviation marked on the curve.

  5. Step 5 · Report

    An answer your CI understands.

    A Markdown summary in the pull request's run, the report as an artifact, and an exit code: 0 within thresholds, 1 for a regression, 2 for an error. Uncertainty is reported as uncertain, never as a failure.

03 Measured, not guessed

55 differences.
Every one intended. Nothing else.

The demo app ships in two variants with eleven deliberate motion changes across every engine. This is MotionPR's real comparison of the two: filter it the way you would a pull request. The repository's end-to-end suite checks that every change is found and nothing else is reported.

1 critical, 35 warnings, 18 info, 1 uncertain.

04 Engines

The browser's animations, natively.
Your engine's, through one line.

No setup · recorded automatically · verified in Chromium

styles.cssCSS
.nav-panel {
  transform: translateX(100%);
  transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}
.nav-open .nav-panel {
  transform: translateX(0);
}
  • warningDuration 320ms → 560ms (+240ms, +75%)
  • warningEasing cubic-bezier(0.16, 1, 0.3, 1) → ease-in-out (max deviation 70% of progress at 27% time)
  • infotranslateX path deviates up to 278.99px at 26% progress
Native CSS integration

05 Easing analysis

Curves, not strings.

ease and cubic-bezier(0.25, 0.1, 0.25, 1) are the same curve; ease-out and a tuned bezier can feel nothing alike. MotionPR compares 65 samples of each curve. This lab runs MotionPR's own easing code in your browser.

06 Scroll motion

A scroll is not an animation.
It is measured like one should be.

Smooth scrolling maps time to position. MotionPR records it live, never replays it, and compares distance, settle time, the shape of the movement, peak velocity and overshoot. Below: the demo's Lenis scroll at lerp 0.1 and 0.06, as recorded.

07 Continuous integration

Least privilege.
Most signal.

npx motionpr init --github writes a workflow that needs only contents: read, pins every action to a commit SHA, and uploads the report even when the job fails.

0
Within thresholds
1
A difference reached comparison.failOn
2
Configuration or execution error
Set up GitHub Actions
npx motionpr run · real output, shortened
◐ motionpr 0.1.0-alpha  ·  run

  → 1 scenario from motionpr.config.mjs
  → Web server ready at http://localhost:4173 (263 ms)
  ✔ menu-open@default  1 checkpoint · 1 animation · 2.0s

  Baseline 20261113-215354-f7d6  →  Current 20261113-215403-2778

  ✖ menu-open@default  1 critical · 1 warning · 1 info
      ✖ Duration 300ms → 600ms (+300ms, +100%)
      ▲ Easing cubic-bezier(0.16, 1, 0.3, 1) → ease-in-out
      ● translateX path deviates up to 195.3px at 26% progress

  Result  FAILED  fail on: critical
  exit code 1

Review motion like code.

Open source, MIT licensed, runs on your machine. No account, no backend, no telemetry.

npm install -D @erenthedeveloper0/motionpr@alpha