animejs-mastery

安装量: 45
排名: #16407

安装

npx skills add https://github.com/frogody/app.isyncso --skill animejs-mastery

Anime.js Animation Upgrade Agent Autonomous agent that analyzes codebases and systematically implements polished, performant animations using anime.js. Agent Workflow Execute these phases sequentially. Work autonomously—don't ask for permission between steps. Phase 1: Codebase Analysis

1. Identify framework and structure

find . -name "package.json" -o -name ".tsx" -o -name ".jsx" -o -name ".vue" -o -name ".svelte" | head -20

2. Check if anime.js is installed

grep -r "animejs|anime.js" package.json 2

/dev/null || echo "NOT_INSTALLED"

3. Map component structure

find . -type f \ ( -name ".tsx" -o -name ".jsx" -o -name ".vue" \ ) -path "/components/*" | head -50 Install anime.js if missing: npm install animejs

For TypeScript projects:

npm install --save-dev @types/animejs Phase 2: Opportunity Identification Scan the codebase for these high-impact animation opportunities: Priority Pattern to Find Animation Type P0 Page/route transitions Fade + slide sequences P0 Loading states, spinners Smooth pulsing/rotation P1 Lists rendering data Staggered entrance P1 Modals/dialogs/drawers Scale + fade entrance P1 Form submissions Success/error feedback P2 Buttons, CTAs Hover/press micro-interactions P2 Cards, tiles Hover lift effects P2 Data visualizations Number counting, chart reveals P3 Icons, badges Attention pulses P3 Tooltips, popovers Soft entrance Search patterns:

Find loading states

grep -rn "loading|isLoading|skeleton|Spinner" --include = ".tsx" --include = ".jsx"

Find modals/dialogs

grep -rn "Modal|Dialog|Drawer|Sheet" --include = ".tsx" --include = ".jsx"

Find lists with map

grep -rn ".map(" --include = ".tsx" --include = ".jsx" | grep -i "item|card|row"

Find buttons

grep -rn "<button|<Button|onClick" --include = ".tsx" --include = ".jsx"

Find route transitions

grep -rn "Route|router|navigate|Link" --include = ".tsx" --include = ".jsx" Phase 3: Create Animation Utilities Create a shared animation utilities file first: // src/lib/animations.ts (or utils/animations.ts) import anime from 'animejs' ; // Respect user preferences export const prefersReducedMotion = ( ) => typeof window !== 'undefined' && window . matchMedia ( '(prefers-reduced-motion: reduce)' ) . matches ; // Safe animate wrapper export const safeAnimate = ( targets : anime . AnimeParams [ 'targets' ] , params : Omit < anime . AnimeParams , 'targets'

) => { if ( prefersReducedMotion ( ) ) { return anime ( { targets , ... params , duration : 0 } ) ; } return anime ( { targets , ... params } ) ; } ; // Staggered list entrance export const staggerIn = ( selector : string , delay = 50 ) => safeAnimate ( selector , { translateY : [ 20 , 0 ] , opacity : [ 0 , 1 ] , delay : anime . stagger ( delay ) , duration : 400 , easing : 'easeOutQuad' , } ) ; // Modal entrance export const modalIn = ( selector : string ) => safeAnimate ( selector , { scale : [ 0.95 , 1 ] , opacity : [ 0 , 1 ] , duration : 200 , easing : 'easeOutQuad' , } ) ; // Button press feedback export const buttonPress = ( element : HTMLElement ) => safeAnimate ( element , { scale : [ 1 , 0.97 , 1 ] , duration : 150 , easing : 'easeInOutQuad' , } ) ; // Success animation export const successPop = ( selector : string ) => safeAnimate ( selector , { scale : [ 0 , 1.1 , 1 ] , opacity : [ 0 , 1 ] , duration : 400 , easing : 'easeOutBack' , } ) ; // Error shake export const errorShake = ( selector : string ) => safeAnimate ( selector , { translateX : [ 0 , - 8 , 8 , - 8 , 8 , - 4 , 4 , 0 ] , duration : 400 , easing : 'easeInOutQuad' , } ) ; // Fade out (for exits) export const fadeOut = ( selector : string ) => safeAnimate ( selector , { opacity : [ 1 , 0 ] , translateY : [ 0 , - 10 ] , duration : 200 , easing : 'easeInQuad' , } ) ; // Number counter export const countUp = ( element : HTMLElement , endValue : number , duration = 1000 ) => { const obj = { value : 0 } ; return anime ( { targets : obj , value : endValue , round : 1 , duration , easing : 'easeOutExpo' , update : ( ) => { element . textContent = obj . value . toLocaleString ( ) ; } , } ) ; } ; // Skeleton pulse export const skeletonPulse = ( selector : string ) => safeAnimate ( selector , { opacity : [ 0.5 , 1 , 0.5 ] , duration : 1500 , loop : true , easing : 'easeInOutSine' , } ) ; Phase 4: React Hook Pattern Create reusable hooks for React projects: // src/hooks/useAnimation.ts import { useEffect , useRef , useCallback } from 'react' ; import anime from 'animejs' ; import { prefersReducedMotion } from '@/lib/animations' ; export function useStaggeredEntrance < T extends HTMLElement

( deps : unknown [ ] = [ ] ) { const containerRef = useRef < T

( null ) ; useEffect ( ( ) => { if ( ! containerRef . current || prefersReducedMotion ( ) ) return ; const children = containerRef . current . children ; anime ( { targets : children , translateY : [ 20 , 0 ] , opacity : [ 0 , 1 ] , delay : anime . stagger ( 50 ) , duration : 400 , easing : 'easeOutQuad' , } ) ; } , deps ) ; return containerRef ; } export function useButtonFeedback ( ) { const handlePress = useCallback ( ( e : React . MouseEvent < HTMLElement

) => { if ( prefersReducedMotion ( ) ) return ; anime ( { targets : e . currentTarget , scale : [ 1 , 0.97 , 1 ] , duration : 150 , easing : 'easeInOutQuad' , } ) ; } , [ ] ) ; return { onMouseDown : handlePress } ; } export function useHoverLift < T extends HTMLElement

( ) { const ref = useRef < T

( null ) ; useEffect ( ( ) => { const el = ref . current ; if ( ! el || prefersReducedMotion ( ) ) return ; const enter = ( ) => { anime . remove ( el ) ; anime ( { targets : el , translateY : - 4 , boxShadow : '0 8px 30px rgba(0,0,0,0.12)' , duration : 200 , easing : 'easeOutQuad' , } ) ; } ; const leave = ( ) => { anime . remove ( el ) ; anime ( { targets : el , translateY : 0 , boxShadow : '0 2px 8px rgba(0,0,0,0.08)' , duration : 200 , easing : 'easeOutQuad' , } ) ; } ; el . addEventListener ( 'mouseenter' , enter ) ; el . addEventListener ( 'mouseleave' , leave ) ; return ( ) => { el . removeEventListener ( 'mouseenter' , enter ) ; el . removeEventListener ( 'mouseleave' , leave ) ; } ; } , [ ] ) ; return ref ; } export function useCountUp ( endValue : number , duration = 1000 ) { const ref = useRef < HTMLElement

( null ) ; useEffect ( ( ) => { if ( ! ref . current ) return ; const obj = { value : 0 } ; anime ( { targets : obj , value : endValue , round : 1 , duration : prefersReducedMotion ( ) ? 0 : duration , easing : 'easeOutExpo' , update : ( ) => { if ( ref . current ) { ref . current . textContent = obj . value . toLocaleString ( ) ; } } , } ) ; } , [ endValue , duration ] ) ; return ref ; } Phase 5: Implementation Checklist Work through components systematically. For each component: Identify the animation opportunity (entrance, interaction, feedback) Add necessary imports Implement using utilities/hooks Test reduced-motion behavior Verify 60fps performance Implementation order: Animation utilities file React hooks (if React project) P0: Page transitions, loading states P1: Lists, modals, form feedback P2: Buttons, cards P3: Icons, tooltips Phase 6: Common Implementation Patterns List component with staggered entrance: function ItemList ( { items } ) { const listRef = useStaggeredEntrance < HTMLUListElement

( [ items ] ) ; return ( < ul ref = { listRef }

{ items . map ( item => ( < li key = { item . id } style = { { opacity : 0 } }

{ item . name } </ li

) ) } </ ul

) ; } Button with press feedback: function AnimatedButton ( { children , onClick , ... props } ) { const feedbackProps = useButtonFeedback ( ) ; return ( < button { ... props } { ... feedbackProps } onClick = { onClick }

{ children } </ button

) ; } Card with hover lift: function Card ( { children } ) { const cardRef = useHoverLift < HTMLDivElement

( ) ; return ( < div ref = { cardRef } className = " card "

{ children } </ div

) ; } Modal with entrance animation: function Modal ( { isOpen , children } ) { const modalRef = useRef < HTMLDivElement

( null ) ; useEffect ( ( ) => { if ( isOpen && modalRef . current ) { modalIn ( modalRef . current ) ; } } , [ isOpen ] ) ; if ( ! isOpen ) return null ; return ( < div ref = { modalRef } className = " modal " style = { { opacity : 0 } }

{ children } </ div

) ; } Performance Rules ALWAYS animate (GPU-accelerated): translateX , translateY , translateZ scale , rotate opacity NEVER animate (triggers layout): width , height padding , margin top , left , right , bottom Timing guidelines: Type Duration Easing Micro-interaction 100-200ms easeOutQuad Button feedback 150ms easeInOutQuad Modal entrance 200-250ms easeOutQuad List stagger 50-100ms between easeOutQuad Page transition 300ms easeOutQuint Output Format After implementation, provide a summary:

Animation Upgrade Summary

Files Created

src/lib/animations.ts - Core utilities - src/hooks/useAnimation.ts - React hooks

Components Updated | Component | Animation Added | Priority | |


|

|

| | ItemList | Staggered entrance | P1 | | Modal | Scale + fade in | P1 | | Button | Press feedback | P2 |

Performance Notes

All animations use transform/opacity only

Reduced motion respected globally

Average animation duration: 200ms Reference Files For detailed API documentation: references/api-reference.md For additional patterns: references/patterns.md

返回排行榜