mcpField
R
reverse-engineer-animation

reverse-engineer-animation

github.com/mblodeDesign & UI169104 installsUpdated 1d ago
Repository

About reverse-engineer-animation

Reverse Engineer Animation is a skill for developers and designers who need to reproduce motion from a recording. It measures frames, tracks movement, fits curves, and produces implementation code with a handoff specification.

Key features

  1. 01Extracting frames and contact sheets
  2. 02Tracking motion and fitting curves
  3. 03Annotating timing and choreography
  4. 04Emitting code for listed UI frameworks
  5. 05Validating results against the recording

Use cases

  1. 01Reproducing a recorded interface transition
  2. 02Measuring separate open and close motions
  3. 03Fitting spring or bezier curves to motion
  4. 04Preparing a motion spec for implementation

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/mblode/agent-skills --skill reverse-engineer-animation

After installing, type/reverse-engineer-animationin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
choreography.md
code-output.md
curve-fitting.md
measurement-guide.md
scripts/
extract_frames.py
fit_curves.py
track_motion.py

Details

From the project README

Reverse Engineer Animation

  • IS: measuring motion that already exists in a recording (extract frames, track per frame, fit curves, annotate choreography), then emitting code and a handoff spec that reproduce it.
  • IS NOT: designing new motion from scratch, or reviewing/debugging motion code. Route both to ui-animation.

Contents

  • Reference files
  • Dependencies
  • Workflow (extract, vision pass, track, fit, annotate, emit, validate)
  • Gotchas
  • Validation
  • Related skills

Reference files

FileRead when
references/measurement-guide.mdDeciding what to measure, eye vs script, reading metrics.json, choosing an ROI
references/curve-fitting.mdReading fit_curves.py output, spring vs bezier, judging fit error, asymmetric open/close
references/code-output.mdEmitting code for CSS, Motion/Framer Motion, SwiftUI, React Native, or UIKit
references/choreography.mdMulti-element / multi-phase motion: staggers, blur-before-move, per-edge settling

Dependencies

  • ffmpeg: frame extraction (brew install ffmpeg). Required for step 1.
  • Python: pip install opencv-python numpy scipy for tracking + curve fitting (step 4).

Extraction degrades gracefully: with only ffmpeg you can still extract frames and reason visually. Tracking and fitting need the Python packages.

Workflow

Copy and track this checklist:

Reverse-engineer progress:
- [ ] Step 1: Extract frames + contact sheet (per direction if open differs from close)
- [ ] Step 2: Vision pass: identify element, effects, phases
- [ ] Step 3: Decide precision (eye-only vs scripted)
- [ ] Step 4: Track motion and fit curves (if escalating)
- [ ] Step 5: Annotate choreography (delays, asymmetry)
- [ ] Step 6: Emit code for the target(s)
- [ ] Step 7: Validate against the recording
Step 1: Extract frames

Run python3 scripts/extract_frames.py <video> <outdir>. On a multi-second recording, trim to just the transition with --start SECONDS --duration SECONDS; extracting the whole clip floods the contact sheet and dilutes tracking. If the interaction has both an open and a close, trim two windows and run the whole pipeline once per direction. They are almost never mirror images, so one measurement cannot serve both.

Match --fps to the source: probe with ffprobe -v 0 -select_streams v -show_entries stream=avg_frame_rate <video> and never sample above the source rate (see Gotchas). Open the generated contact_sheet.png first; it shows the whole timeline at once.

Step 2: Vision pass

View the contact sheet and name, in order:

  • The element(s) that move.
  • Every effect present: translate, scale (often anisotropic), opacity, blur, corner radius, shadow, color. Use the property checklist in references/measurement-guide.md.
  • The phases (e.g. backdrop blurs in, element tucks under the notch, over-stretches, then settles per-edge). Note which property leads and which lags.
Step 3: Decide precision
  • Simple fade or linear slide: read timing off the contact sheet and skip to step 5.
  • Elastic, springy, or multi-property motion: escalate to step 4. Eyeballing a spring is unreliable.
Step 4: Track and fit

Run python3 scripts/track_motion.py <outdir> to produce metrics.json. Pass --bbox X,Y,W,H to restrict detection to one element when several move (one run per element). Then run python3 scripts/fit_curves.py <outdir>/metrics.json to get spring params, cubic-bezier, and a fit error per property. If you extracted with a non-default --fps, pass the same --fps to fit_curves.py: its default is 30 and a mismatch rescales every duration and stiffness (see Gotchas). Read references/curve-fitting.md to interpret the numbers and pick the model. High error on both models means multi-phase motion: split the timeline and fit each segment.

Step 5: Annotate choreography

Load references/choreography.md. Build the timing-offset table (when each property starts and settles). Those lead/lag gaps and the over-stretch carry more of the feel than any single curve.

Step 6: Emit code

Substitute the fitted parameters into the templates in references/code-output.md for the requested target. Keep movement on transform/opacity. Emit two transitions when open and close differ. Produce the consolidated handoff motion spec (timing table + curves + snippet) from references/code-output.md so the result can be implemented without the video.

Step 7: Validate

Run the Validation checks below. The exit criterion is comparison evidence, never "looks right".

Gotchas

  • fit_curves.py defaults to --fps 30. Extract at --fps 60 and fit at the default, and every duration_ms doubles (a 500 ms transition reports as 1000 ms) while fitted stiffness drops to a quarter. Always pass the extraction fps to the fit.
  • Sampling above the source frame rate duplicates frames: a 24 fps GIF extracted at --fps 60 yields runs of identical values in metrics.json that plateau the progress curve and inflate both fit errors. Probe the source rate first and match it.
  • Screen recordings drop frames under load, and iOS/QuickTime captures are variable-frame-rate. Consecutive identical metrics.json rows are duplicated frames, not a pause in the animation. If plateaus dominate, re-record at a steadier frame rate instead of chasing the fit.
  • Fitting one global curve to multi-phase motion fails with high error on both models. Split into phases and compose keyframes (references/curve-fitting.md).
  • Tracking only position misses blur/opacity, which usually lead the move by ~100 ms. That lead is where the polish lives.
  • Open and close are never mirror images (open slower and springier, close faster and flatter). Measure each direction as its own clip; never reuse the open curve reversed.
  • Reporting spring params without checking the fit error: a bad fit gives confident-looking but wrong numbers; treat error > 0.08 as suspect.
  • Emitting code that animates layout props (width, height, top, left): reproduce the motion on transform/opacity/filter (defer to ui-animation rules).
  • Re-reading a script to reconstruct its logic instead of running it: the scripts are the canonical, deterministic path.

Validation

  • Re-derive: play the emitted animation, screen-record it, run it back through extract_frames.py, and compare contact sheets side-by-side with the original.
  • Slow to 0.1x in DevTools to confirm phase order (lead/lag) and the over-stretch survive.
  • Confirm the emitted code only animates transform, opacity, and filter.
  • Sanity-check fitted spring overshoot/zeta against what you saw; a clear bounce must not fit as a flat ease.

Related skills

  • ui-animation: turn the extracted spec into production-grade, interruptible motion and apply its easing defaults and anti-pattern rules.

Comments

Markdown supported