Motion craft
Distilled operating skills for daily-driver Claude models — few dense rules, executable gates over long prose.
npx -y skills add F-e-u-e-r/opus-pack --skill motion-craftAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Implementation-agnostic motion judgment for product UI. Load when you are adding, reviewing, or tuning animation in any framework - durations, easings, springs, staggers, entrances/exits, gesture handoff, reduced motion - when a spec says "smooth" or "delightful" with no numbers attached, or when you notice animation being judged by feel instead of against a budget. NOT for debugging one animation library's API (use its docs), for static visual decisions (ui-design-craft), or for running a design review end-to-end (design-review-gate).
SKILL.md
14.5 KB, as published. Nobody here has run it
Motion Craft
Every animation must serve feedback ("it worked"), continuity ("that's where it went"), or hierarchy ("look here"). An animation serving none of the three is removed, not tuned. When in doubt: shorter, subtler, or none.
1. Duration budgets
Numbers first; taste second. Defaults for product UI:
| Surface | Budget |
|---|---|
| Hover / press feedback | 90-160ms |
| Tooltip, micro popover | 80-200ms |
| Dropdown, select, small panel | 150-250ms |
| Accordion, tab switch | 160-240ms |
| Card / list item entrance | 180-350ms |
| Modal, drawer, sheet | 200-400ms |
| Route / page transition | 240-500ms |
- Standard interactions stay under 300ms; nothing in product UI exceeds 500ms. A 180ms dropdown reads as more responsive than a 400ms one.
- Exit = 65-75% of entrance. Leaving is confirmation, not an event. The rows above bound ENTRANCES; a rule-derived exit may drop below its row - that is the intent, not a violation.
- Distance scales duration: 100px is the base; 200px ~1.3x, 400px ~1.6x, full-screen ~1.8-2.0x. Small moves at long durations read as lag.
- Frequency scales duration DOWN. An action done 100 times a day approaches instant. Hard sub-rule: never animate keyboard-initiated actions - they repeat hundreds of times daily and animation makes them feel disconnected from the keystroke. ❌ "the command palette fades in over 250ms - it looks polished in the demo." ✅ keyboard-opened palette appears instantly; its pointer-opened twin may animate.
- Trigger for this section: any duration you are about to write, or any existing duration outside the table. Done when every duration in the diff sits inside its row's budget or carries a written justification.
2. Easing
| Direction | Curve | Why |
|---|---|---|
| Enter | ease-out | fast start = instant feedback, soft landing |
| Exit | ease-in | soft start, fast leave |
| On-screen move / morph | ease-in-out | smooth both ends |
| Spinners, progress, marquee | linear | mechanical processes read linear |
- Never linear for finite point-to-point movement; never ease-in for entrances. Continuous mechanical motion - spinners, progress bars, marquee loops - is the linear exception the table names, not a contradiction of it. An ease-in dropdown at 300ms feels slower than ease-out at the same 300ms: it delays movement in the exact frames the user watches most closely.
- Named defaults: Material 3 standard
cubic-bezier(0.2, 0, 0, 1); M3 emphasized-deceleratecubic-bezier(0.05, 0.7, 0.1, 1); Core Animation'skCAMediaTimingFunctionDefault/ CSSeaseiscubic-bezier(0.25, 0.1, 0.25, 1)- Apple's HIG publishes principles, not bezier tokens, so any "Apple HIG curve" value circulating online is reverse-engineered, not vendor-published. Two mislabels to refuse:(0.4, 0, 0.2, 1)is Material 2's standard routinely pasted as "M3", and(0.25, 0.1, 0.25, 1)labeled "the Apple HIG default" is the CSSeasecurve wearing a vendor costume.
3. Springs and gesture physics
- Spring parameters below are Framer Motion-convention coefficients (stiffness + damping). Two unit traps: React Spring parameterizes as tension/friction, not these; and a damping ratio (where <1.0 oscillates, 1.0 is critical) is a different unit again - an error that has reached published tables (this pack's own LottieFiles source conflates the two). Name which convention you are using.
- Critical damping (no overshoot) for mass 1 is
damping = 2 * sqrt(stiffness)- stiffness 400 needs damping 40, stiffness 300 needs ~35. The presets below are deliberately UNDERDAMPED (they overshoot a little), which per the settle rule places them on momentum-driven interactions only:
| Feel | Stiffness | Damping | Where it belongs |
|---|---|---|---|
| Snappy (mild overshoot) | ~400 | 25-30 | flick-driven UI |
| Standard (visible settle) | 250-350 | 18-24 | drag release |
| Bouncy (sparingly) | 150-250 | 10-15 | playful, earned |
- Springs must settle. Click-triggered UI defaults to critically damped (use the formula above); overshoot is earned by a flick, never by a click, and never appears on error paths. Prolonged wobble ("jello") is a defect, not personality.
- Momentum projection (where a flick should land): Apple ships the
exponential-decay form
projectedDistance = (velocity / 1000) * d / (1 - d)withd ~= 0.998, velocity in px per SECOND (the /1000 folds it onto the per-millisecond decay step; the dismissal rule below uses px/ms - mixing the two units is a 1000x error) - NOT the physics-textbookv^2 / (2 * deceleration). - Rubber-band overscroll:
(overshoot * dimension * c) / (dimension + c * |overshoot|)withc = 0.55- resistance grows the further past the bound. - Velocity handoff: when a gesture ends, the animation continues at the
finger's velocity:
relativeVelocity = gestureVelocity / (target - current)(libraries taking raw px/s can be handed the gesture velocity directly). Guard the zero/near-zero displacement case: whentarget - currentis ~0 there is nothing to animate - skip the spring instead of dividing by it. A visible seam between drag and animation is the tell this rule was skipped. - Momentum dismissal: velocity OR distance - either alone suffices. A
flick dismisses on velocity above ~0.11 px/ms (~110 px/s; the source's cheap
approximation is average
|distance| / elapsedMs; prefer the gesture's actual release velocity where the framework exposes it). A slow drag past the distance threshold still dismisses - velocity-only would snap a deliberate full drag back. The failure this rule exists to prevent is requiring distance from a fast flick.
4. Choreography
- Stagger: 30-80ms between items; total sequence under 500ms; stagger is decorative - it must never block interaction while playing.
- One thing leads. Everything animating at once with equal weight is noise; pick the hero element, let the rest follow or fade.
- Overshoot budget by context: success 5-10%; generic feedback 2-5%; celebration up to 25%; errors and destructive confirmations 0% - play nothing bouncy on the worst moment of the user's session.
- Asymmetric deliberate/response timing: where the user is deciding (press-and-hold, destructive confirm) the animation may run slow; the system's response snaps. Symmetric timing on a press-and-release interaction is a finding, not a style choice.
5. Performance traps
transformandopacityare the workhorses; paint-only properties (color, background-color, border-color) are acceptable for state feedback. What is BANNED is animating layout-triggering properties (width, height, top, left, margin, padding) - those are rewritten, not accepted.transition: allis banned. ❌transition: all 300ms ease- it animates every property that happens to change, layout-affecting ones you never intended included, plus whichever property a future edit adds; the failure signature is surprise animations and layout work appearing when unrelated styles change. ✅transition: transform 200ms ease-out, opacity 200ms ease-out.- Framer Motion's shorthand props (
x,y,scale) animate on the main thread via rAF rather than as compositor-run transforms (Kowalski's production finding; the observable symptom is dropped frames while the page is busy). Under load, use the fulltransformstring. - Updating an inheriting CSS variable on a parent recalculates style for
its children - the default for unregistered custom properties (a
registered
@propertywithinherits: falsesidesteps it) - so in a drawer with many items, drivetransformon the moving element directly instead of--offseton the container. - Animations are interruptible: new input retargets mid-flight (CSS transitions and springs retarget; keyframes restart from zero - wrong for toasts, toggles, anything triggered rapidly); no fill-mode or delay may block interaction.
- Never enter from
scale(0)- nothing real appears from nothing; enter fromscale(0.9-0.97)plus opacity. - Set
transform-originfor scale/rotate: popovers, dropdowns, and tooltips scale from their trigger, not center (modals are the exemption - they stay centered); SVG needstransform-box: fill-boxon a wrapping<g>. - Gate hover motion behind
@media (hover: hover) and (pointer: fine)- touch devices fire false hovers on tap.
6. Reduced motion is a floor, not a feature
- Every animation ships a
prefers-reduced-motionvariant. Reduced means fewer and gentler, not zero: keep opacity/color transitions that aid comprehension; drop movement - slide+fade -> fade; scale+fade -> fade; spring -> short tween; parallax and auto-playing loops -> removed. Transform-based full-screen motion is the highest-cost vestibular trigger - it is exactly what this media query exists for. - Motion is never the only signal of a state change: pair it with a static affordance (color, position, label) or reduced-motion users miss the change entirely.
7. Misquoted research - do not cite these wrong
These corrections are adapted from open-design's primary-literature review (Apache-2.0; adaptation notice in THIRD-PARTY-NOTICES). The papers were NOT re-opened for this pack - each line below is that review's checked claim, restated, not this pack's own reading of the source:
- "Skeleton screens feel 11% faster" - per that review, Harrison/Yeo/ Hudson (CHI 2010) measured backwards-decelerating ribbed progress bars (n=16), not skeletons; the mechanism does not transfer.
- "Doherty threshold = 400ms" - per that review, the source contains no 400ms figure; the lowest measured threshold is 300ms. And cite the source itself correctly: Doherty & Thadhani, "The Economic Value of Rapid Response Time", IBM technical report GE20-0752 (1982) - the "IBM Systems Journal 1982" venue and the "Thadani" spelling circulating online (and in the review this pack adapted) are themselves miscitations, corrected here.
- "Heer & Robertson recommend 300-1000ms transitions" - per that review, they tested 1.25s and 2s only, and recommend roughly one second per animated stage.
- Motion confirms state changes; it must not perform them. Optimistic UI first, animation second.
8. Pre-ship gate
Run against the built surface, not the source: trigger each interaction and watch it. Severity-tiered; every CRITICAL verified by observation before "done".
- CRITICAL: reduced-motion variant exists and was toggled on and
observed; nothing exceeds 500ms (unless the When-NOT spectacle
exception was invoked in writing - the purpose test and reduced-motion
floor still bind there); no spring fails to settle; no
keyboard-initiated action animates; no
transition: all. - HIGH: durations inside §1 budgets; easing direction per §2; exits faster than entrances; layout-property animation absent.
- MEDIUM: stagger within budget;
transform-originset for scale; consistent timings across sibling components; overshoot within §4 context budget.
Done when: every CRITICAL item observed passing, HIGH items pass or carry a written exception, and any failure names the rule it broke (not "feels off").
When NOT to use this skill
- Debugging one library's API surface -> that library's docs; this file owns budgets and judgment, not APIs.
- Static layout/type/color decisions ->
ui-design-craft. - Running a full design review with measurement and fix loop ->
design-review-gate(its motion pass applies this file's budgets). - Marketing hero choreography on a page whose brief explicitly buys spectacle: §1 caps may be exceeded there, deliberately and in writing - the purpose test and reduced-motion floor still apply.
Provenance
Composed 2026-07-19 for design-pack 0.1.0. Sources, all verified in their
repos at composition time: Emil Kowalski's emilkowalski/skills (MIT) -
duration budgets, keyboard rule, stagger numbers, Framer shorthand and CSS
variable performance traps, Apple-derived projection / rubber-band / velocity
handoff forms (his distillation of Apple WWDC material; formulas quoted from
his files); LottieFiles motion-design-skill (MIT) - element duration table,
distance-duration multipliers, exit ratio, stagger and overshoot budgets,
severity-tier gate shape (their damping-units conflation is corrected here,
not copied; §1's duration rows are envelope syntheses across the three
motion sources, not quotes of any single table); referodesign/refero_skill (MIT) - purpose triad, easing
direction table, reduced-motion mapping, transition: all ban. §7's
corrections and the M2/M3 mislabel are adapted from nexu-io/open-design's
craft/animation-discipline.md primary-source review (Apache-2.0; the
correction items keep that review's selection, figures, and framing - an
ADAPTATION carried with notice in THIRD-PARTY-NOTICES, not an ideas-only
borrow). The primary papers were not independently re-opened for this
pack, with one exception: the Doherty citation itself (report GE20-0752,
"Thadhani") is this pack's own correction of the review's miscite. greensock/gsap-skills was
surveyed and deliberately not mined: library-usage doctrine, out of scope
here. Numeric values (beziers, spring pairs, budgets) are the volatile
facts - re-verify beziers against the published Material 3 motion tokens
(m3.material.io) and, for Apple, the SwiftUI Animation API's actual values
(the HIG publishes no numeric curves); spring pairs against the Framer
Motion / Motion docs - on major vendor releases. Probe status: probe-tested 2026-07-19 on a
private over-budget motion-spec fixture (fresh weak-tier agent, n=1 per
arm, smoke grade): the bare arm caught ~3 of 7 planted violations, loosely
phrased - though it did catch the missing reduced-motion variant, recorded
honestly - while the ruled arm caught 7 of 7 with budget citations,
including the keyboard rule and the 500ms total-stagger cap the bare arm
lacked as concepts. A round-0 run was voided for a leaked in-fixture
answer key. Trail in the design-pack PR.