Use when adding animations or gestures to a React Native + Expo app: scale/opacity/translation transitions, layout animations (FadeIn/SlideIn/FadeOut), shared-value driven motion, swipe-to-delete, pan/pinch/long-press gestures, scroll-linked animations. Triggers on: "anima questo", "swipe to X", "fade in/out", "pinch zoom", "scroll-driven animation". Not for: styling (rn-styling), navigation transitions (Expo Router handles those — see rn-expo-router), CSS-only on web (Next.js stack).
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Use when adding animations or gestures to a React Native + Expo app: scale/opacity/translation transitions, layout animations (FadeIn/SlideIn/FadeOut), shared-value driven motion, swipe-to-delete, pan/pinch/long-press gestures, scroll-linked animations. Triggers on: "anima questo", "swipe to X", "fade in/out", "pinch zoom", "scroll-driven animation". Not for: styling (rn-styling), navigation transitions (Expo Router handles those — see rn-expo-router), CSS-only on web (Next.js stack).
rn-animations-gestures — guardrail for animations + gestures in RN/Expo
The 5 rules (non-negotiable)
Reanimated 4 is the default. Never the legacy Animated API from react-native for new code.
Gestures via Gesture Handler 2. Never PanResponder. Use Gesture.Pan(), Gesture.Pinch(), Gesture.Tap(), Gesture.LongPress() with <GestureDetector>.
Worklets run on the UI thread — they CANNOT access React state directly. To call back to JS use runOnJS(fn)(args). Inside worklets, only shared values, locals, and runOnUI/runOnJS are safe.
Layout animations for enter/exit/move. Use entering={FadeIn}, exiting={FadeOut}, layout={Layout.springify()} from react-native-reanimated — they handle their own worklets correctly.
useDerivedValue for computed shared values. Never useMemo on a shared value — useMemo runs on JS thread.
Quick decision tree
"What's the right tool — Reanimated or just CSS-like transitions?" → references/decision-tree.md
"How do I structure a worklet-driven animation?" → references/patterns.md
"What native module setup do I need?" → both Reanimated 4 + RNGH 2 are already in rn-bootstrap's install-stack.sh. No extra setup needed.
Common anti-patterns (NEVER do)
❌ import { Animated } from "react-native" — use react-native-reanimated's Animated instead.
❌ setMyState(newValue) from inside a worklet — wrap in runOnJS(setMyState)(newValue).
❌ Reading props.foo directly inside useAnimatedStyle — capture into a shared value first.
❌ PanResponder — deprecated for new code. Gesture Handler 2.
❌ Animating height: 'auto' — impossible on the UI thread (no measure). Either measure with onLayout or use LayoutAnimation from Reanimated.
❌ Chaining withTiming(...) inside useEffect without cancelAnimation — leaks on unmount.