Documentation Index
Fetch the complete documentation index at: https://mintlify.com/shopify/react-native-skia/llms.txt
Use this file to discover all available pages before exploring further.
React Native Skia provides powerful animation capabilities through seamless integration with Reanimated 3, enabling high-performance 60+ FPS animations with zero bridge overhead.
Why Reanimated?
React Native Skia integrates with Reanimated 3 for animations because:
- Zero bridge overhead - Animations run entirely on the UI thread
- 60+ FPS performance - Smooth animations without dropping frames
- Declarative API - Easy to use and understand
- Shared values - Reactive state that updates the canvas automatically
- Gesture integration - Works seamlessly with React Native Gesture Handler
Basic Animation Example
import { Canvas, Circle } from "@shopify/react-native-skia";
import { useSharedValue, withRepeat, withTiming } from "react-native-reanimated";
import { useEffect } from "react";
const AnimatedCircle = () => {
const cx = useSharedValue(50);
useEffect(() => {
cx.value = withRepeat(
withTiming(200, { duration: 1000 }),
-1, // infinite
true // reverse
);
}, [cx]);
return (
<Canvas style={{ width: 256, height: 256 }}>
<Circle cx={cx} cy={128} r={40} color="blue" />
</Canvas>
);
};
Shared Values
Shared values are the foundation of Reanimated animations. They can be used directly in Skia components:
import { useSharedValue } from "react-native-reanimated";
const rotation = useSharedValue(0);
const opacity = useSharedValue(1);
const color = useSharedValue("red");
// Use in components
<Group transform={[{ rotate: rotation }]}>
<Circle cx={128} cy={128} r={64} color={color} opacity={opacity} />
</Group>
Animation Types
Timing Animation
Animate to a target value over time:
import { withTiming, Easing } from "react-native-reanimated";
useEffect(() => {
opacity.value = withTiming(0, {
duration: 500,
easing: Easing.inOut(Easing.ease)
});
}, []);
Spring Animation
Physics-based spring animation:
import { withSpring } from "react-native-reanimated";
useEffect(() => {
scale.value = withSpring(1.5, {
damping: 10,
stiffness: 100
});
}, []);
Decay Animation
Gradually slow down (great for gestures):
import { withDecay } from "react-native-reanimated";
const onPanEnd = (velocityX: number) => {
translateX.value = withDecay({
velocity: velocityX,
clamp: [0, 300]
});
};
Repeat Animation
Repeat animations indefinitely or a set number of times:
import { withRepeat, withTiming } from "react-native-reanimated";
useEffect(() => {
// Infinite loop
rotation.value = withRepeat(
withTiming(360, { duration: 2000 }),
-1, // -1 for infinite
false // don't reverse
);
}, []);
Sequence Animation
Chain animations together:
import { withSequence, withTiming } from "react-native-reanimated";
useEffect(() => {
scale.value = withSequence(
withTiming(1.2, { duration: 200 }),
withTiming(1, { duration: 200 })
);
}, []);
Derived Values
Compute values based on other shared values:
import { useDerivedValue } from "react-native-reanimated";
const progress = useSharedValue(0);
const rotation = useDerivedValue(() => {
return progress.value * Math.PI * 2;
});
const opacity = useDerivedValue(() => {
return 1 - progress.value;
});
return (
<Group transform={[{ rotate: rotation }]} opacity={opacity}>
<Circle cx={128} cy={128} r={40} color="blue" />
</Group>
);
Interpolation
Map values from one range to another:
import { interpolate, Extrapolation } from "react-native-reanimated";
const scrollY = useSharedValue(0);
const opacity = useDerivedValue(() => {
return interpolate(
scrollY.value,
[0, 100], // input range
[1, 0], // output range
Extrapolation.CLAMP
);
});
Color Interpolation
import { interpolateColor } from "react-native-reanimated";
const progress = useSharedValue(0);
const color = useDerivedValue(() => {
return interpolateColor(
progress.value,
[0, 1],
["#FF0000", "#0000FF"]
);
});
<Circle cx={128} cy={128} r={64} color={color} />
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const rotation = useSharedValue(0);
const scale = useSharedValue(1);
<Group
transform={[
{ translateX },
{ translateY },
{ rotate: rotation },
{ scale }
]}
>
<Circle cx={128} cy={128} r={40} color="purple" />
</Group>
Path Interpolation
Interpolate between paths:
import { Skia } from "@shopify/react-native-skia";
import { useDerivedValue } from "react-native-reanimated";
const progress = useSharedValue(0);
const path1 = Skia.Path.Make();
path1.addCircle(128, 128, 64);
const path2 = Skia.Path.Make();
path2.addRect(Skia.XYWHRect(64, 64, 128, 128));
const animatedPath = useDerivedValue(() => {
return path1.interpolate(path2, progress.value);
});
<Path path={animatedPath} color="green" />
Use worklets
Mark functions that run on the UI thread with 'worklet':
const onFrame = (frameInfo: FrameInfo) => {
'worklet';
rotation.value = frameInfo.timestamp * 0.001;
};
Minimize re-renders
Shared values don’t trigger re-renders. Use them for high-frequency updates:
// Good - no re-renders
const rotation = useSharedValue(0);
// Bad - causes re-renders on every change
const [rotation, setRotation] = useState(0);
Batch updates
Update multiple values in a single animation:
const animate = () => {
'worklet';
x.value = withTiming(100);
y.value = withTiming(100);
rotation.value = withTiming(Math.PI);
};
requestAnimationFrame
For custom animation loops:
import { useFrameCallback } from "react-native-reanimated";
const rotation = useSharedValue(0);
useFrameCallback((frameInfo) => {
rotation.value = (frameInfo.timestamp / 1000) % (Math.PI * 2);
});
Common Animation Patterns
Fade In
const opacity = useSharedValue(0);
useEffect(() => {
opacity.value = withTiming(1, { duration: 300 });
}, []);
Pulse Effect
const scale = useSharedValue(1);
useEffect(() => {
scale.value = withRepeat(
withSequence(
withTiming(1.2, { duration: 500 }),
withTiming(1, { duration: 500 })
),
-1,
false
);
}, []);
Rotate Continuously
const rotation = useSharedValue(0);
useEffect(() => {
rotation.value = withRepeat(
withTiming(2 * Math.PI, { duration: 2000, easing: Easing.linear }),
-1,
false
);
}, []);
Bounce In
const scale = useSharedValue(0);
useEffect(() => {
scale.value = withSpring(1, {
damping: 5,
stiffness: 100
});
}, []);
Animation State
Cancel animations programmatically:
import { cancelAnimation } from "react-native-reanimated";
const stopAnimation = () => {
cancelAnimation(rotation);
};