---
name: animaciones-react-native-reanimated
description: Guia practica para implementar animaciones fluidas a 60fps en React Native usando Reanimated, ejecutando worklets directamente en el hilo nativo de UI sin pasar por el puente JavaScript. Cubre valores compartidos, gestos, transiciones de layout y efectos basados en scroll.
license: Apache-2.0
metadata:
  id: 66a0b630
  slug: animaciones-react-native-reanimated
  titulo: "Animaciones 60fps en React Native con Reanimated"
  servicio: Web
  categoria_recurso: Web-Desarrollo
  tipo: referencia
  nivel: intermedio
  idioma: es
  idioma_original: en
  acceso: gratis
  precio_eur: 0
  plataformas: [React Native, Expo, iOS, Android]
  dependencias: [react-native-reanimated, react-native-gesture-handler, babel-preset-expo]
  licencia: { spdx: Apache-2.0, redistribuible: true, uso_comercial: true }
  fuente:
    repo: TerminalSkills/skills
    url: https://github.com/TerminalSkills/skills/tree/main/skills/react-native-reanimated
    commit: 77fa015
    autor: TerminalSkills
    nombre_original: react-native-reanimated
    duplicados_en: []
  seguridad: { veredicto: seguro, riesgo: bajo, escaneado: "2026-06-14", motor: "grep-estatico+auditor-llm" }
  ficha:
    que_hace: "Proporciona patrones listos para animar componentes React Native a 60fps sin caidas de frames mediante el hilo nativo."
    como_lo_hace: "Usa worklets de Reanimated con useSharedValue y useAnimatedStyle para ejecutar logica de animacion directamente en el UI thread via JSI."
  content_hash: "66a0b6306c69121af0f8dea1b87645a97abcba3de0244642a84c44bc368ffaaf"
  version: 1.0.0
---

# React Native Reanimated

## Overview

Reanimated runs animations on the native UI thread — no JS bridge bottleneck, no dropped frames. Animations stay at 60fps even when your JavaScript thread is busy. It uses "worklets" — small JavaScript functions that execute on the UI thread via JSI. The standard for production-quality animations in React Native: gesture-driven interactions, layout transitions, scroll-based effects, and shared element transitions.

## When to Use

- Any animation in React Native beyond simple opacity/transform
- Gesture-driven interactions (swipe to delete, drag to reorder, pinch to zoom)
- Scroll-driven animations (parallax headers, sticky elements)
- Layout animations (items entering/leaving lists)
- Shared element transitions between screens

## Instructions

### Setup

```bash
npx expo install react-native-reanimated react-native-gesture-handler
```

```javascript
// babel.config.js — Add the Reanimated plugin (MUST be last)
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    plugins: ["react-native-reanimated/plugin"],  // Must be last!
  };
};
```

### Shared Values and Animated Styles

```tsx
// components/FadeIn.tsx — Basic animation with shared values
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withTiming,
  withSpring,
} from "react-native-reanimated";
import { useEffect } from "react";

export function FadeInCard({ children }) {
  const opacity = useSharedValue(0);
  const translateY = useSharedValue(20);

  useEffect(() => {
    opacity.value = withTiming(1, { duration: 600 });
    translateY.value = withSpring(0, { damping: 15 });
  }, []);

  const animatedStyle = useAnimatedStyle(() => ({
    opacity: opacity.value,
    transform: [{ translateY: translateY.value }],
  }));

  return (
    <Animated.View style={animatedStyle} className="bg-white rounded-xl p-4 shadow-lg">
      {children}
    </Animated.View>
  );
}
```

### Gesture Animations

```tsx
// components/SwipeToDelete.tsx — Swipe gesture with animation
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  runOnJS,
} from "react-native-reanimated";
import { Gesture, GestureDetector } from "react-native-gesture-handler";

export function SwipeToDelete({ onDelete, children }) {
  const translateX = useSharedValue(0);

  const pan = Gesture.Pan()
    .onUpdate((event) => {
      // Only allow left swipe
      translateX.value = Math.min(0, event.translationX);
    })
    .onEnd((event) => {
      if (event.translationX < -150) {
        // Swipe far enough — delete
        translateX.value = withSpring(-400);
        runOnJS(onDelete)();
      } else {
        // Snap back
        translateX.value = withSpring(0);
      }
    });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }],
  }));

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

### Layout Animations

```tsx
// components/AnimatedList.tsx — Items animate in/out automatically
import Animated, { FadeInDown, FadeOutLeft, LinearTransition } from "react-native-reanimated";

export function AnimatedList({ items, onRemove }) {
  return (
    <Animated.FlatList
      data={items}
      itemLayoutAnimation={LinearTransition}
      renderItem={({ item, index }) => (
        <Animated.View
          entering={FadeInDown.delay(index * 100).springify()}
          exiting={FadeOutLeft.duration(300)}
          className="bg-white p-4 mx-4 my-1 rounded-lg"
        >
          <Text>{item.title}</Text>
          <Pressable onPress={() => onRemove(item.id)}>
            <Text className="text-red-500">Remove</Text>
          </Pressable>
        </Animated.View>
      )}
    />
  );
}
```

### Scroll-Driven Animations

```tsx
// components/ParallaxHeader.tsx — Parallax effect on scroll
import Animated, {
  useAnimatedScrollHandler,
  useSharedValue,
  useAnimatedStyle,
  interpolate,
} from "react-native-reanimated";

export function ParallaxHeader() {
  const scrollY = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (event) => {
      scrollY.value = event.contentOffset.y;
    },
  });

  const headerStyle = useAnimatedStyle(() => ({
    height: interpolate(scrollY.value, [-100, 0, 200], [400, 300, 100]),
    opacity: interpolate(scrollY.value, [0, 200], [1, 0.3]),
    transform: [
      { translateY: interpolate(scrollY.value, [0, 200], [0, -50]) },
    ],
  }));

  return (
    <>
      <Animated.View style={headerStyle} className="bg-blue-600">
        <Text className="text-white text-3xl font-bold">My App</Text>
      </Animated.View>
      <Animated.ScrollView onScroll={scrollHandler} scrollEventThrottle={16}>
        {/* Content */}
      </Animated.ScrollView>
    </>
  );
}
```

## Examples

### Example 1: Build a card swipe interface

**User prompt:** "Build a Tinder-style card swipe interface with smooth animations."

The agent will create a card stack with pan gestures, rotation based on swipe direction, spring animations for snap-back, and layout transitions for card removal.

### Example 2: Animated bottom sheet

**User prompt:** "Create a bottom sheet that can be dragged up and snaps to positions."

The agent will use pan gestures with snap points, shared values for height, and spring animations for smooth snapping.

## Guidelines

- **Shared values for animation state** — `useSharedValue` runs on UI thread
- **`useAnimatedStyle` for dynamic styles** — recalculated on UI thread
- **`withSpring` for natural motion** — `withTiming` for precise duration
- **`runOnJS` to call JS from worklets** — bridge back to JS thread when needed
- **Gesture Handler integration** — `Gesture.Pan()`, `Gesture.Pinch()`, etc.
- **Layout animations are declarative** — `entering`, `exiting` props on Animated components
- **`interpolate` for value mapping** — map scroll position to opacity, scale, etc.
- **Babel plugin must be last** — `react-native-reanimated/plugin` at end of plugins array
- **Don't access JS objects in worklets** — only shared values and primitives
- **`scrollEventThrottle={16}`** — 60fps scroll events for smooth animations
