본문으로 건너뛰기
cccskills
무료GitHub에 공개

mobile-animation-reanimated

React Native Reanimated 4 - shared values, animated styles, spring/timing/decay, layout animations, gesture integration, scroll-driven animations, interpolation, worklets, CSS animations

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(7)

  • SKILL.md18.7 KB
  • examples/core.md10.3 KB
  • examples/gestures.md7.4 KB
  • examples/layout-animations.md6.3 KB
  • examples/scroll-animations.md7.0 KB
  • metadata.yaml560 B
  • reference.md7.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

React Native Reanimated Patterns

Quick Guide: Reanimated 4 is New Architecture only (requires react-native-worklets as a separate dependency). Use useSharedValue + useAnimatedStyle for all animations. Animations run on the UI thread via worklets -- never block the JS thread. Use withSpring (physics-based) or withTiming (duration-based) for transitions, layout animations (entering/exiting) for mount/unmount, and useScrollOffset (renamed from useScrollViewOffset) for scroll-driven animations. Reanimated 4 also introduces CSS animations/transitions as a declarative alternative to the worklet API.


<critical_requirements>

CRITICAL: Before Using This Skill

(You MUST use Animated components (Animated.View, Animated.Text, etc.) for any animated styles -- passing animated styles to regular components causes errors)

(You MUST keep static styles in StyleSheet.create and only animate dynamic properties in useAnimatedStyle -- animating static values wastes UI thread resources)

(You MUST NOT mutate shared values inside useAnimatedStyle callbacks -- read only, or you cause infinite loops)

(You MUST use react-native-worklets as a separate dependency in Reanimated 4 -- the worklet Babel plugin moved from react-native-reanimated/plugin to react-native-worklets/plugin)

</critical_requirements>


Auto-detection: Reanimated, react-native-reanimated, useSharedValue, useAnimatedStyle, withSpring, withTiming, withDecay, Animated.View, Animated.Text, Animated.ScrollView, entering, exiting, FadeIn, FadeOut, SlideIn, interpolate, interpolateColor, useScrollOffset, GestureDetector, Gesture.Pan, worklet, layout animation, shared value, energyThreshold, CSS animation, react-native-worklets

When to use:

  • Animating view properties (opacity, transforms, colors) on the UI thread
  • Adding entering/exiting animations when components mount/unmount
  • Building gesture-driven animations (drag, swipe, pinch)
  • Creating scroll-driven header collapse, parallax, or sticky effects
  • Interpolating values across ranges (position to opacity, scroll to scale)
  • Implementing spring physics or timing-based transitions

When NOT to use:

  • Simple boolean show/hide without animation (conditional rendering suffices)
  • Static layouts that never change at runtime
  • Animated.Value from React Native core (use Reanimated's shared values instead)

Key patterns covered:

  • Shared values (useSharedValue) + animated styles (useAnimatedStyle)
  • Animation functions: withTiming, withSpring, withDecay
  • Layout animations: entering/exiting with predefined builders
  • Gesture integration: Gesture.Pan + shared values + withDecay
  • Scroll-driven animations with useScrollOffset
  • Interpolation: interpolate and interpolateColor
  • Worklet functions and the 'worklet' directive
  • CSS animations and transitions (Reanimated 4 declarative API)

Detailed Resources:


<philosophy>

Philosophy

Reanimated runs animations on the UI thread via worklets, keeping the JS thread free for business logic. The core model: shared values are reactive state that bridges JS and UI threads, animated styles derive visual properties from shared values, and animation functions (withSpring, withTiming, withDecay) drive transitions between values.

Reanimated 4 key changes from 3.x:

  • New Architecture only -- drops Legacy Architecture (bridge) support entirely
  • react-native-worklets as a separate package -- Babel plugin moved from react-native-reanimated/plugin to react-native-worklets/plugin
  • CSS animations/transitions -- declarative API for state-driven animations (use CSS for simple state transitions, worklets for gesture/scroll-driven)
  • energyThreshold replaces restDisplacementThreshold/restSpeedThreshold in withSpring
  • useScrollOffset replaces useScrollViewOffset (deprecated alias remains)
  • Threading functions moved to react-native-worklets: runOnJS -> scheduleOnRN, runOnUI -> scheduleOnUI

When to use CSS animations vs worklets:

  • CSS animations/transitions -- state-driven, declarative, less code, better optimizable by Reanimated
  • Worklets -- gesture-driven, scroll-driven, complex orchestration, frame-by-frame control

Backward compatibility: All v2/v3 shared value and animation APIs work unchanged in v4. CSS animations and worklet-based animations work simultaneously and interchangeably.

</philosophy>
<patterns>

Core Patterns

Pattern 1: Shared Values and Animated Styles

The fundamental building blocks. useSharedValue creates reactive state on the UI thread. useAnimatedStyle derives styles that update when shared values change.

import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withTiming,
} from "react-native-reanimated";

const EXPANDED_HEIGHT = 200;
const COLLAPSED_HEIGHT = 60;
const ANIMATION_DURATION = 300;

function CollapsibleCard() {
  const height = useSharedValue(COLLAPSED_HEIGHT);

  const animatedStyle = useAnimatedStyle(() => ({
    height: height.value,
  }));

  const toggle = () => {
    height.value = withTiming(
      height.value === COLLAPSED_HEIGHT ? EXPANDED_HEIGHT : COLLAPSED_HEIGHT,
      { duration: ANIMATION_DURATION }
    );
  };

  return (
    <Pressable onPress={toggle}>
      <Animated.View style={[styles.card, animatedStyle]}>
        <Text>Content</Text>
      </Animated.View>
    </Pressable>
  );
}

Why good: static styles stay in StyleSheet, only dynamic height in useAnimatedStyle, named constants for dimensions and durations, Animated.View receives the animated style

Key rules:

  • Only animate dynamic properties in useAnimatedStyle -- static styles belong in StyleSheet.create
  • Never mutate shared values inside useAnimatedStyle -- it is read-only
  • Always apply animated styles to Animated.* components, not regular View/Text

See examples/core.md for complete examples including React Compiler compatibility (get()/set()).


Pattern 2: withSpring and withTiming

withTiming is duration-based (predictable timing). withSpring is physics-based (natural feel). Choose based on UX intent.

// Physics-based spring (natural, bouncy)
sv.value = withSpring(TARGET, { damping: 100, stiffness: 800 });

// Duration-based spring (controlled timing with spring feel)
sv.value = withSpring(TARGET, { duration: 500, dampingRatio: 0.8 });

// Timing with easing
sv.value = withTiming(TARGET, {
  duration: ANIMATION_DURATION,
  easing: Easing.bezierFn(0.25, 0.1, 0.25, 1),
});

Reanimated 4 spring change: restDisplacementThreshold and restSpeedThreshold are removed. Replaced by energyThreshold (relative to animation, default 6e-9). In most cases, removing the old thresholds is sufficient -- no need to set energyThreshold manually.

Duration gotcha: In v4, actual spring completion time = perceptual duration x 1.5. Divide existing duration values by 1.5 for equivalent behavior when migrating from v3.

See examples/core.md for spring config comparison and withDecay.


Pattern 3: Layout Animations (Entering/Exiting)

Predefined animations for component mount/unmount. Apply to Animated.* components via entering and exiting props.

import Animated, { FadeIn, FadeOutLeft } from "react-native-reanimated";

const ANIMATION_DURATION = 400;
const ANIMATION_DELAY = 100;

function NotificationBanner({ visible }: { visible: boolean }) {
  if (!visible) return null;

  return (
    <Animated.View
      entering={FadeIn.duration(ANIMATION_DURATION).delay(ANIMATION_DELAY)}
      exiting={FadeOutLeft.duration(ANIMATION_DURATION)}
      style={styles.banner}
    >
      <Text>New notification</Text>
    </Animated.View>
  );
}

Available builders: FadeIn, SlideInRight, ZoomIn, BounceIn, FlipInEasyX, LightSpeedInRight, RotateIn, PinwheelIn, and all directional variants (Up/Down/Left/Right) plus corresponding Out variants.

Modifiers: .duration(ms), .delay(ms), .springify() (with .damping(), .stiffness(), .mass()), .withInitialValues(), .withCallback(), .reduceMotion().

Performance tip: Define animation builders outside components or in useMemo -- creating them inline in render causes unnecessary object allocation.

See examples/layout-animations.md for custom builders, staggered lists, and EntryExitTransition.


Pattern 4: Gesture Integration

Reanimated integrates with react-native-gesture-handler. Gesture callbacks are automatically workletized -- you can access shared values directly without the 'worklet' directive.

import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withDecay,
} from "react-native-reanimated";

function DraggableCard() {
  const offsetX = useSharedValue(0);

  const pan = Gesture.Pan()
    .onChange((e) => {
      offsetX.value += e.changeX;
    })
    .onFinalize((e) => {
      offsetX.value = withDecay({ velocity: e.velocityX, rubberBandEffect: true });
    });

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

  return (
    <GestureDetector gesture={pan}>
      <Animated.View style={[styles.card, animatedStyle]} />
    </GestureDetector>
  );
}

Why good: onChange gives delta values (not absolute), onFinalize adds momentum with withDecay, gesture callbacks access shared values directly on UI thread

Key points:

  • Use onChange for incremental updates (delta), onUpdate for absolute position
  • GestureHandlerRootView must wrap your app near the root
  • This skill covers the Reanimated side of gesture animations -- for gesture configuration details (tap, pinch, fling, simultaneous gestures), see the gesture handler skill

See examples/gestures.md for swipe-to-dismiss, bottom sheet, and combined gestures.


Pattern 5: Scroll-Driven Animations

Use useScrollOffset to track scroll position as a shared value. Combine with interpolate for parallax, collapsing headers, and fade effects.

import Animated, {
  useAnimatedRef,
  useScrollOffset,
  useAnimatedStyle,
  interpolate,
  Extrapolation,
} from "react-native-reanimated";

const HEADER_MAX = 200;
const HEADER_MIN = 60;

function CollapsibleHeader() {
  const scrollRef = useAnimatedRef<Animated.ScrollView>();
  const scrollOffset = useScrollOffset(scrollRef);

  const headerStyle = useAnimatedStyle(() => ({
    height: interpolate(
      scrollOffset.value,
      [0, HEADER_MAX - HEADER_MIN],
      [HEADER_MAX, HEADER_MIN],
      Extrapolation.CLAMP
    ),
  }));

  return (
    <>
      <Animated.View style={[styles.header, headerStyle]} />
      <Animated.ScrollView ref={scrollRef}>
        {/* content */}
      </Animated.ScrollView>
    </>
  );
}

Why good: useScrollOffset auto-detects horizontal/vertical, no manual scroll event handler needed, Extrapolation.CLAMP prevents values outside the range

Reanimated 4 rename: useScrollViewOffset -> useScrollOffset (deprecated alias remains temporarily).

See examples/scroll-animations.md for parallax, sticky elements, and scroll-to-hide tab bar.


Pattern 6: Interpolation

Map one value range to another. interpolate for numbers, interpolateColor for color transitions.

import {
  interpolate,
  interpolateColor,
  Extrapolation,
} from "react-native-reanimated";

// Number interpolation: scroll position -> opacity
const opacity = interpolate(
  scrollY.value,
  [0, 100], // input range
  [1, 0], // output range
  Extrapolation.CLAMP,
);

// Color interpolation: progress -> background
const backgroundColor = interpolateColor(
  progress.value,
  [0, 0.5, 1], // input range
  ["#FF0000", "#FFFF00", "#00FF00"], // output colors (red -> yellow -> green)
);

Extrapolation options: CLAMP (cap at edges), EXTEND (extrapolate linearly), IDENTITY (return input value). Can set left/right independently: { extrapolateLeft: Extrapolation.CLAMP, extrapolateRight: Extrapolation.EXTEND }.

interpolateColor modes: 'RGB' (default) or 'HSV'. HSV produces more perceptually uniform transitions for hue changes.

See examples/core.md for multi-step interpolation and color transition examples.


Pattern 7: Worklet Functions

Functions that run on the UI thread. Mark with 'worklet' directive. Reanimated auto-workletizes callbacks in useAnimatedStyle, gesture handlers, and animation callbacks -- you only need explicit 'worklet' for standalone helper functions.

import { scheduleOnRN } from "react-native-worklets";

function clampValue(value: number, min: number, max: number) {
  "worklet";
  return Math.min(Math.max(value, min), max);
}

// Use in useAnimatedStyle -- auto-workletized, no directive needed
const style = useAnimatedStyle(() => ({
  opacity: clampValue(progress.value, 0, 1),
}));

Reanimated 4 threading changes:

Reanimated 3Reanimated 4 (react-native-worklets)
runOnJS(fn)("arg")scheduleOnRN(fn, "arg")
runOnUI(fn)("arg")scheduleOnUI(fn, "arg")

When you need explicit 'worklet':

  • Standalone helper functions called from other worklets
  • Functions passed to scheduleOnUI

When you do NOT need it:

  • useAnimatedStyle callbacks (auto-workletized)
  • Gesture handler callbacks (auto-workletized)
  • Animation callbacks (auto-workletized)

Pattern 8: CSS Animations and Transitions (Reanimated 4)

Declarative animation API modeled after web CSS. Best for state-driven animations. Worklet API remains for gesture/scroll-driven scenarios.

import Animated from "react-native-reanimated";

const TRANSITION_DURATION = 300;

function ToggleBox({ expanded }: { expanded: boolean }) {
  return (
    <Animated.View
      style={{
        height: expanded ? 200 : 60,
        opacity: expanded ? 1 : 0.5,
        transitionProperty: "height, opacity",
        transitionDuration: `${TRANSITION_DURATION}ms`,
        transitionTimingFunction: "ease-in-out",
      }}
    />
  );
}

CSS animation keyframes:

const PULSE_DURATION = 1000;

<Animated.View
  style={{
    animationName: {
      from: { transform: [{ scale: 1 }] },
      to: { transform: [{ scale: 1.1 }] },
    },
    animationDuration: `${PULSE_DURATION}ms`,
    animationIterationCount: "infinite",
    animationDirection: "alternate",
    animationTimingFunction: "ease-in-out",
  }}
/>

When to use CSS vs worklets:

  • CSS -- state-driven toggles, hover effects, simple transitions (less code, better optimizable)
  • Worklets -- gesture-driven, scroll-driven, frame-by-frame control, complex orchestration
</patterns>

<red_flags>

RED FLAGS

High Priority Issues:

  • Passing animated styles to regular View/Text instead of Animated.View/Animated.Text -- causes silent failure or crash
  • Mutating shared values inside useAnimatedStyle -- causes infinite re-evaluation loops
  • Using react-native-reanimated/plugin in Babel config with Reanimated 4 -- must use react-native-worklets/plugin (and it must be last in the plugins array)
  • Using Reanimated 4.x with Legacy Architecture (old bridge) -- Reanimated 4 is New Architecture only
  • Animating static properties in useAnimatedStyle instead of keeping them in StyleSheet -- wastes UI thread resources
  • Using restDisplacementThreshold/restSpeedThreshold in withSpring -- removed in v4, replaced by energyThreshold

Medium Priority Issues:

  • Creating layout animation builders inline in render -- allocates objects every render; define outside component or in useMemo
  • Using runOnJS/runOnUI instead of scheduleOnRN/scheduleOnUI -- old API moved to react-native-worklets
  • Missing GestureHandlerRootView at app root -- gestures silently fail without it
  • Using useAnimatedGestureHandler -- removed in v4, migrate to Gesture Handler 2's Gesture API

Gotchas and Edge Cases:

  • withSpring duration: actual completion time = perceptual duration x 1.5 -- divide v3 duration values by 1.5 when migrating
  • useScrollOffset renamed from useScrollViewOffset -- deprecated alias still works temporarily
  • Shared value .value access is synchronous on UI thread but asynchronous on JS thread -- don't rely on immediate reads after writes on JS thread
  • useWorkletCallback removed -- replace with useCallback + 'worklet' directive
  • React Compiler compatibility: use sv.get() and sv.set() instead of direct .value access when using React Compiler
  • combineTransition removed -- use EntryExitTransition.entering(entering).exiting(exiting)
  • Object shared values: reassign the entire object, never mutate individual properties -- mutations break reactivity tracking
  • Removing an animated style from a view does not unset the animated values -- explicitly set properties to undefined to reset
  • On New Architecture, layout animations use nativeID internally -- don't overwrite it on animated components

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

(You MUST use Animated components (Animated.View, Animated.Text, etc.) for any animated styles -- passing animated styles to regular components causes errors)

(You MUST keep static styles in StyleSheet.create and only animate dynamic properties in useAnimatedStyle -- animating static values wastes UI thread resources)

(You MUST NOT mutate shared values inside useAnimatedStyle callbacks -- read only, or you cause infinite loops)

(You MUST use react-native-worklets as a separate dependency in Reanimated 4 -- the worklet Babel plugin moved from react-native-reanimated/plugin to react-native-worklets/plugin)

Failure to follow these rules will cause animation failures, infinite loops, and crashes on the UI thread.

</critical_reminders>

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

agents-inc의 스킬 모두 보기

이 스킬의 문제 신고