agentsclimarketplace

Animations

Skill Shankulkarni/react-native-ai-plugin/plugins/rn-ai/skills/animations

Use when implementing animations or gestures -- GPU-only properties, Reanimated v3 worklets, useDerivedValue, GestureDetector press states, layout animations, React Compiler compatibility.From its SKILL.md

Install
npx -y skills add Shankulkarni/react-native-ai-plugin --skill animations

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 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.

SKILL.md

4.2 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it

Animations + Gestures

Reanimated v3 + Gesture Handler v2. New Architecture only. No RN core Animated API.

CRITICAL -- Only GPU-Accelerated Properties

// ❌ Causes layout recalculation every frame
width, height, top, left, margin, padding

// ✅ GPU-accelerated -- animate freely
transform: [{ translateX }, { translateY }, { scale }, { rotate }]
opacity

Core Imports

import Animated, {
  useSharedValue, useAnimatedStyle, useDerivedValue,
  useAnimatedReaction, withSpring, withTiming, withSequence,
  withDelay, withRepeat, runOnJS, interpolate,
  interpolateColor, Extrapolation, cancelAnimation,
  FadeIn, FadeOut, SlideInRight, ZoomIn,
} from 'react-native-reanimated'
import { Gesture, GestureDetector } from 'react-native-gesture-handler'

// Always Animated.View from reanimated -- never from react-native

Animated Press State

function AnimatedCard({ onPress, children }: { onPress?: () => void; children: ReactNode }) {
  const scale = useSharedValue(1)
  const opacity = useSharedValue(1)

  const tap = Gesture.Tap()
    .onBegin(() => {
      scale.value = withSpring(0.96, { damping: 15, stiffness: 300 })
      opacity.value = withTiming(0.85, { duration: 80 })
    })
    .onFinalize((_, success) => {
      scale.value = withSpring(1, { damping: 15, stiffness: 300 })
      opacity.value = withTiming(1, { duration: 120 })
      if (success && onPress) runOnJS(onPress)()
    })

  const style = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
    opacity: opacity.value,
  }))

  return (
    <GestureDetector gesture={tap}>
      <Animated.View style={style}>{children}</Animated.View>
    </GestureDetector>
  )
}

useDerivedValue vs useAnimatedReaction

// ✅ useDerivedValue -- compute a new value (runs on UI thread)
const rotation = useDerivedValue(() => `${progress.value * 360}deg`)
const clamped = useDerivedValue(() =>
  interpolate(raw.value, [0, 1], [0.8, 1.2], Extrapolation.CLAMP)
)

// ✅ useAnimatedReaction -- side effects only (call JS, haptics)
useAnimatedReaction(
  () => progress.value,
  (current, prev) => {
    if (current >= 1 && prev !== null && prev < 1) runOnJS(onComplete)()
  },
)

Layout Animations

// Entering/exiting animations on mount/unmount
<Animated.View entering={FadeIn.duration(300)} exiting={FadeOut.duration(200)}>
  <Text>Fades in</Text>
</Animated.View>

<Animated.View entering={SlideInRight.springify().damping(15)}>
  <Card />
</Animated.View>

// List item animations
<FlashList
  renderItem={({ item, index }) => (
    <Animated.View entering={FadeIn.delay(index * 50)}>
      <PostCard {...item} />
    </Animated.View>
  )}
/>

Pan Gesture (Swipe to Dismiss)

function SwipeToDismiss({ onDismiss, children }: { onDismiss: () => void; children: ReactNode }) {
  const x = useSharedValue(0)
  const THRESHOLD = 100

  const pan = Gesture.Pan()
    .onUpdate((e) => { x.value = e.translationX })
    .onEnd((e) => {
      if (Math.abs(e.translationX) > THRESHOLD) runOnJS(onDismiss)()
      else x.value = withSpring(0)
    })

  const style = useAnimatedStyle(() => ({
    transform: [{ translateX: x.value }],
    opacity: interpolate(Math.abs(x.value), [0, THRESHOLD], [1, 0.5], Extrapolation.CLAMP),
  }))

  return (
    <GestureDetector gesture={pan}>
      <Animated.View style={style}>{children}</Animated.View>
    </GestureDetector>
  )
}

Spring Presets

const SPRING = {
  snappy: { damping: 20, stiffness: 400 },
  bouncy: { damping: 10, stiffness: 200, mass: 0.8 },
  gentle: { damping: 30, stiffness: 150 },
}

// Usage
scale.value = withSpring(1, SPRING.snappy)

Worklet Rules

  • No console.log in worklets -- crashes New Architecture UI thread
  • No closures over JS objects -- pass primitives only
  • No async/await -- worklets are synchronous
  • No React hooks -- worklets run on UI thread
// ✅ Worklet-safe utility
function clamp(value: number, min: number, max: number): number {
  'worklet'
  return Math.min(Math.max(value, min), max)
}

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.