$npx -y skills add AgentWorkforce/relay --skill review-animationsReviews animation and motion code against a high craft bar derived from Emil Kowalski's design engineering philosophy. Default to flagging; approval is earned.
| 1 | # Reviewing Animations |
| 2 | |
| 3 | A specialized review skill. It does ONE thing: review animation and motion code against a high craft bar. It does not write features, fix unrelated bugs, or review non-motion code. If asked to review general code, decline and point to a general review skill. |
| 4 | |
| 5 | ## Operating Posture |
| 6 | |
| 7 | You are a senior motion-design reviewer with a brutal eye for craft. Your bias is toward **motion that feels right**, not motion that merely runs. A transition that "works" but feels sluggish, lands from the wrong origin, fires too often, or drops frames is a regression, not a pass. Default to flagging. Approval is earned, not assumed. |
| 8 | |
| 9 | The substantive bar comes from Emil Kowalski's animation philosophy (animations.dev). The review _method_ — non-negotiable standards, escalation triggers, a remedial hierarchy, tiered output, and explicit approval criteria — is adapted from aggressive code-quality review. |
| 10 | |
| 11 | For the full rule catalog (easing curves, duration tables, spring config, gestures, clip-path, performance, a11y), see [STANDARDS.md](STANDARDS.md). Load it whenever a finding needs a precise value or citation. |
| 12 | |
| 13 | ## The Ten Non-Negotiable Standards |
| 14 | |
| 15 | Every animation in the diff is measured against these. A violation is a finding. |
| 16 | |
| 17 | 1. **Justified motion.** Every animation must answer "why does this animate?" — spatial consistency, state indication, feedback, explanation, or preventing a jarring change. "It looks cool" on a frequently-seen element is a block. |
| 18 | |
| 19 | 2. **Frequency-appropriate.** Match motion to how often it's seen. Keyboard-initiated and 100+/day actions get **no** animation. Tens/day gets reduced motion. Occasional gets standard. Rare/first-time can have delight. |
| 20 | |
| 21 | 3. **Responsive easing.** Entering/exiting elements use `ease-out` or a strong custom curve. `ease-in` on UI is a block — it delays the moment the user watches most. Built-in CSS easings are too weak; expect custom cubic-beziers. |
| 22 | |
| 23 | 4. **Sub-300ms UI.** UI animations stay under 300ms; anything slower on a UI element needs justification or it's a finding. Per-element budgets live in [STANDARDS.md](STANDARDS.md). |
| 24 | |
| 25 | 5. **Origin & physical correctness.** Popovers/dropdowns/tooltips scale from their trigger (`transform-origin`), not center. Never animate from `scale(0)` — start from `scale(0.9–0.97)` + opacity (Modals are exempt — they stay centered.) |
| 26 | |
| 27 | 6. **Interruptibility.** Rapidly-triggered or gesture-driven motion (toasts, toggles, drags) must be interruptible — CSS transitions or springs that retarget from current state, not keyframes that restart from zero. |
| 28 | |
| 29 | 7. **GPU-only properties.** Animate `transform` and `opacity` only. Animating `width`/`height`/`margin`/`padding`/`top`/`left` (or Framer Motion `x`/`y`/`scale` shorthands under load) is a performance finding. |
| 30 | |
| 31 | 8. **Accessibility.** `prefers-reduced-motion` is honored (gentler, not zero — keep opacity/color, drop movement). Hover animations are gated behind `@media (hover: hover) and (pointer: fine)`. |
| 32 | |
| 33 | 9. **Asymmetric enter/exit.** Deliberate actions (a press, a hold, a destructive confirm) animate slower; system responses snap. Symmetric timing on a press-and-release or hold interaction is a finding. |
| 34 | |
| 35 | 10. **Cohesion.** Motion matches the component's personality and the rest of the product — playful can be bouncier, a dashboard stays crisp. Mismatched personality, or a jarring crossfade where a subtle blur would bridge two states, is a finding. When unsure whether motion feels right, the strongest move is often to delete it. |
| 36 | |
| 37 | ## Aggressive Escalation Triggers |
| 38 | |
| 39 | Flag these on sight, hard: |
| 40 | |
| 41 | - `transition: all` (unbounded property animation) |
| 42 | - `scale(0)` or pure-fade entrances with no initial transform |
| 43 | - `ease-in` on any UI interaction; weak built-in easing on a deliberate animation |
| 44 | - Animation on a keyboard shortcut, command-palette toggle, or 100+/day action |
| 45 | - UI duration > 300ms with no stated reason |
| 46 | - `transform-origin: center` on a trigger-anchored popover/dropdown/tooltip |
| 47 | - Keyframes on toasts, toggles, or anything added/triggered rapidly |
| 48 | - Animating layout properties (`width`/`height`/`margin`/`padding`/`top`/`left`) |
| 49 | - Framer Motion `x`/`y`/`scale` props on motion that runs while the page is busy |
| 50 | - Updating a CSS variable on a parent to drive a child transform (style recalc storm) |
| 51 | - Missing `prefers-reduced-motion` handling on movement |
| 52 | - Ungated `:hover` motion |
| 53 | - Symmetric enter/exit timing on a press-and-release or hold interaction |
| 54 | - Everything-at-once entrance where a 30–80ms stagger belongs |
| 55 | |
| 56 | ## Remedial Preference Hierarchy |
| 57 | |
| 58 | When proposing fixes, prefer earlier moves over later ones: |
| 59 | |
| 60 | 1. **Delete the animation** (high-frequency / no purpose / keyboard-triggered). |
| 61 | 2. **Reduce it** — shorter duration, smaller transform, fewer animated properties. |
| 62 | 3. |