Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Reviews animation and motion code against a high craft bar derived from Emil Kowalski's design engineering philosophy. Default to flagging; approval is earned.
.claude/skills/nexu-io-review-animations/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✗→✓ | ▲ Improved | 41% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 98% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-05 | ✗→✓ | ▲ Improved | -49% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 326% | 0% |
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.
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.
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.
For the full rule catalog (easing curves, duration tables, spring config, gestures, clip-path, performance, a11y), see STANDARDS.md. Load it whenever a finding needs a precise value or citation.
Every animation in the diff is measured against these. A violation is a finding.
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.transform-origin), not center. Never animate from scale(0) — start from scale(0.9–0.97) + opacity (Modals are exempt — they stay centered.)transform and opacity only. Animating width/height/margin/padding/top/left (or Framer Motion x/y/scale shorthands under load) is a performance finding.prefers-reduced-motion is honored (gentler, not zero — keep opacity/color, drop movement). Hover animations are gated behind @media (hover: hover) and (pointer: fine).Flag these on sight, hard:
transition: all (unbounded property animation)scale(0) or pure-fade entrances with no initial transformease-in on any UI interaction; weak built-in easing on a deliberate animationtransform-origin: center on a trigger-anchored popover/dropdown/tooltipwidth/height/margin/padding/top/left)x/y/scale props on motion that runs while the page is busyprefers-reduced-motion handling on movement:hover motionWhen proposing fixes, prefer earlier moves over later ones:
ease-in→ease-out/custom curve; use a strong cubic-bezier.transform-origin; replace scale(0) with scale(0.95)+opacity.transform/opacity; shorthand → full transform string; WAAPI for programmatic CSS.@starting-style for entry, spring for "alive" elements.Two parts, in this order.
A single markdown table. One row per issue. Never a "Before:/After:" list.
| Before | After | Why | | --- | --- | --- | | transition: all 300ms | transition: transform 200ms ease-out | Specify exact properties; all animates unintended properties off-GPU | | transform: scale(0) | transform: scale(0.95); opacity: 0 | Nothing appears from nothing — scale(0) looks like it came from nowhere | | ease-in on dropdown | ease-out + custom curve | ease-in delays the moment the user watches most; feels sluggish | | transform-origin: center on popover | var(--radix-popover-content-transform-origin) | Popovers scale from their trigger, not center (modals are exempt) |
Group remaining commentary by impact tier, highest first. Omit empty tiers.
Close with an explicit decision:
scale(0)/ease-in on UI, or a non-GPU animation with an easy GPU fix.Be specific and cite file:line. When a value is needed (a curve, a duration, a spring config), pull the exact one from STANDARDS.md rather than approximating.
@starting-style/WAAPI for predetermined motion; JS/springs for dynamic, interruptible, gesture-driven motion.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-16 | fail→pass | 19,049 | 9,927 | -48% | 1 | 1 | 0% | 2,560 | 3,603 | +41% | 0 | 0 | — |
case-04 | fail→pass | 7,124 | 2,070 | -71% | 1 | 1 | 0% | 1,145 | 2,267 | +98% | 0 | 0 | — |
case-01 | fail→fail | 41,497 | 5,574 | -87% | 1 | 1 | 0% | 4,007 | 2,635 | -34% | 0 | 0 | — |
case-02 | fail→fail | 29,916 | 16,628 | -44% | 1 | 1 | 0% | 4,521 | 4,200 | -7% | 0 | 0 | — |
case-03 | fail→pass | 25,352 | 29,213 | +15% | 1 | 1 | 0% | 4,822 | 7,635 | +58% | 0 | 0 | — |
case-05 | fail→pass | 60,540 | 7,560 | -88% | 1 | 1 | 0% | 5,725 | 2,937 | -49% | 0 | 0 | — |
case-06 | fail→pass | 7,025 | 1,933 | -72% | 1 | 1 | 0% | 530 | 2,257 | +326% | 0 | 0 | — |
case-07 | pass→pass | 14,081 | 11,753 | -17% | 1 | 1 | 0% | 2,241 | 3,660 | +63% | 0 | 0 | — |
case-08 | pass→pass | 10,709 | 12,197 | +14% | 1 | 1 | 0% | 1,485 | 3,704 | +149% | 0 | 0 | — |
case-09 | pass→pass | 12,258 | 7,425 | -39% | 1 | 1 | 0% | 1,893 | 3,114 | +65% | 0 | 0 | — |
case-10 | fail→pass | 14,864 | 7,902 | -47% | 1 | 1 | 0% | 2,066 | 3,404 | +65% | 0 | 0 | — |
case-11 | fail→pass | 15,001 | 12,865 | -14% | 1 | 1 | 0% | 2,333 | 3,726 | +60% | 0 | 0 | — |
case-12 | pass→pass | 15,562 | 10,534 | -32% | 1 | 1 | 0% | 2,534 | 3,341 | +32% | 0 | 0 | — |
case-13 | fail→pass | 14,276 | 7,999 | -44% | 1 | 1 | 0% | 2,271 | 3,213 | +41% | 0 | 0 | — |
case-14 | fail→pass | 9,371 | 10,893 | +16% | 1 | 1 | 0% | 1,470 | 3,789 | +158% | 0 | 0 | — |
case-15 | fail→fail | 15,756 | 19,263 | +22% | 1 | 1 | 0% | 2,597 | 4,991 | +92% | 0 | 0 | — |
case-17 | pass→pass | 19,225 | 16,225 | -16% | 1 | 1 | 0% | 2,610 | 4,240 | +62% | 0 | 0 | — |
case-18 | fail→pass | 12,346 | 8,671 | -30% | 1 | 1 | 0% | 1,632 | 3,055 | +87% | 0 | 0 | — |
case-19 | fail→pass | 22,790 | 15,082 | -34% | 1 | 1 | 0% | 2,872 | 3,844 | +34% | 0 | 0 | — |
case-20 | pass→pass | 15,909 | 12,039 | -24% | 1 | 1 | 0% | 2,198 | 3,729 | +70% | 0 | 0 | — |
case-21 | pass→pass | 10,124 | 7,559 | -25% | 1 | 1 | 0% | 1,372 | 2,947 | +115% | 0 | 0 | — |
case-22 | fail→pass | 11,490 | 4,184 | -64% | 1 | 1 | 0% | 1,720 | 2,403 | +40% | 0 | 0 | — |
case-23 | fail→pass | 13,838 | 10,936 | -21% | 1 | 1 | 0% | 2,071 | 3,423 | +65% | 0 | 0 | — |
case-24 | fail→pass | 28,460 | 9,855 | -65% | 1 | 1 | 0% | 2,904 | 3,307 | +14% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +58 percentage points is the difference between those two pass rates over the 24 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.