
To Spring Or Not To Spring
Audit motion code so gestures use springs, system feedback uses easing, and high-frequency UI skips animation noise—with file:line findings.
Install
npx skills add https://github.com/raphaelsalaja/skill --skill to-spring-or-not-to-springWhat is this skill?
- 4 rule categories: Spring Selection, Easing Selection, Duration, No Animation (prefixes spring-, easing-, duration-, non
- Decision framework: user-driven motion → spring; system-driven → easing; progress → linear; high-frequency → none
- Reviews specified files and reports violations in file:line format for agent or human fixes
- Covers gesture-driven interactions, state transitions, loading/progress, and fast toggles
Adoption & trust: 1 installs on skills.sh; 18 GitHub stars; 3/3 security scanners passed (skills.sh audits); trending (+100% hot-view momentum).
Recommended Skills
Journey fit
Motion implementation lives in UI code during product build—the canonical shelf is Build frontend where timing functions are chosen. Frontend is where springs, cubic-bezier easing, and duration constants are applied in components and interaction handlers.
Common Questions / FAQ
Is To Spring Or Not To Spring safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - To Spring Or Not To Spring
# To Spring or Not To Spring Review animation code for correct timing function selection based on interaction type. ## How It Works 1. Read the specified files (or prompt user for files/pattern) 2. Check against all rules below 3. Output findings in `file:line` format ## Rule Categories | Priority | Category | Prefix | |----------|----------|--------| | 1 | Spring Selection | `spring-` | | 2 | Easing Selection | `easing-` | | 3 | Duration | `duration-` | | 4 | No Animation | `none-` | ## Decision Framework Ask: **Is this motion reacting to the user, or is the system speaking?** | Motion Type | Best Choice | Why | |-------------|-------------|-----| | User-driven (drag, flick, gesture) | Spring | Survives interruption, preserves velocity | | System-driven (state change, feedback) | Easing | Clear start/end, predictable timing | | Time representation (progress, loading) | Linear | 1:1 relationship between time and progress | | High-frequency (typing, fast toggles) | None | Animation adds noise, feels slower | ## Rules ### Spring Selection Rules #### `spring-for-gestures` Gesture-driven motion (drag, flick, swipe) must use springs. **Fail:** ```tsx <motion.div drag="x" transition={{ duration: 0.3, ease: "easeOut" }} /> ``` **Pass:** ```tsx <motion.div drag="x" transition={{ type: "spring", stiffness: 500, damping: 30 }} /> ``` #### `spring-for-interruptible` Motion that can be interrupted must use springs. **Fail:** ```tsx // User can click again mid-animation <motion.div animate={{ x: isOpen ? 200 : 0 }} transition={{ duration: 0.3 }} /> ``` **Pass:** ```tsx <motion.div animate={{ x: isOpen ? 200 : 0 }} transition={{ type: "spring", stiffness: 400, damping: 25 }} /> ``` #### `spring-preserves-velocity` When velocity matters, use springs to preserve input energy. **Fail:** ```tsx // Fast flick and slow flick animate identically onDragEnd={(e, info) => { animate(target, { x: 0 }, { duration: 0.3 }); }} ``` **Pass:** ```tsx // Fast flick moves faster than slow flick onDragEnd={(e, info) => { animate(target, { x: 0 }, { type: "spring", velocity: info.velocity.x, }); }} ``` #### `spring-params-balanced` Spring parameters must be balanced; avoid excessive oscillation. **Fail:** ```tsx transition={{ type: "spring", stiffness: 1000, damping: 5, // Too low - excessive bounce }} ``` **Pass:** ```tsx transition={{ type: "spring", stiffness: 500, damping: 30, // Balanced - settles quickly }} ``` ### Easing Selection Rules #### `easing-for-state-change` System-initiated state changes should use easing curves. **Fail:** ```tsx // Toast notification using spring <motion.div animate={{ y: 0 }} transition={{ type: "spring" }} /> // Feels restless for a simple announcement ``` **Pass:** ```tsx <motion.div animate={{ y: 0 }} transition={{ duration: 0.2, ease: "easeOut" }} /> ``` #### `easing-entrance-ease-out` Entrances must use ease-out (arrive fast, settle gently). **Fail:** ```css .modal-enter { animation-timing-function: ease-in; } ``` **Pass:** ```css .modal-enter { animation-timing-function: ease-out; } ``` #### `easing-exit-ease-in` Exits must use ease-in (build momentum before departure). **Fail:** ```css .modal-exit { animation-timing-function: ease-out; } ``` **Pass:** ```css .modal-exit { animation-timing-function: ease-in; } ``` #### `easing-transition-ease-in-out` View/mode transitions use ease-in-out for neutral attention. **Pass:** ```css .page-transition { animation-timing-function: ease-in-out; } ``` #### `easing-linear-only-progress` Linear easing only for