High-performance React Native Graphics using Skia
—
Animation utilities and React Native Reanimated integration for creating smooth, performant animations in React Native Skia.
/**
* Maps input value to output range with extrapolation control
* @param x - Input value to interpolate
* @param input - Input range array (must be monotonically increasing)
* @param output - Output range array (same length as input)
* @param type - Extrapolation behavior outside input range
* @returns Interpolated output value
*/
function interpolate(
x: number,
input: readonly number[],
output: readonly number[],
type?: ExtrapolationType
): number;
type ExtrapolationType = "extend" | "clamp" | "identity";
/**
* Interpolates between multiple colors
* @param value - Input value (typically 0.0 to 1.0)
* @param inputRange - Input range for color interpolation
* @param outputRange - Array of colors to interpolate between
* @returns Color as number array [r, g, b, a]
*/
function interpolateColors(
value: number,
inputRange: number[],
outputRange: Color[]
): number[];
/**
* Mixes two colors with a blend factor
* @param value - Blend factor (0.0 = first color, 1.0 = second color)
* @param x - First color
* @param y - Second color
* @returns Mixed color as Float32Array
*/
function mixColors(value: number, x: Color, y: Color): Float32Array;
/**
* Mixes two vectors with a blend factor
* @param value - Blend factor (0.0 = first vector, 1.0 = second vector)
* @param from - First vector
* @param to - Second vector
* @returns Mixed vector
*/
function mixVector(value: number, from: Vector, to: Vector): Vector;React Native Skia supports animated properties through the SkiaProps type system.
/**
* Wrapper type that makes all properties of T potentially animated
*/
type SkiaProps<T> = {
[K in keyof T]: T[K] | SharedValue<T[K]> | DerivedValue<T[K]>;
};
/**
* Single animated property type
*/
type AnimatedProp<T> = T | SharedValue<T> | DerivedValue<T>;
/**
* Props with optional default values that can be animated
*/
type SkiaDefaultProps<T, N> = SkiaProps<T> & {
[K in keyof N]: AnimatedProp<N[K]>;
};React Native Skia integrates seamlessly with React Native Reanimated for smooth animations.
// Animation hooks from external/reanimated module
/**
* Hook for animated image loading and updates
* @param imageUri - Image URI that can be animated
* @returns Animated image value
*/
function useAnimatedImageValue(imageUri: SharedValue<string>): SharedValue<SkImage | null>;
/**
* Hook for video playback integration with animations
* @param url - Video URL
* @returns Video object with frame access
*/
function useVideo(url: string): Video | null;// Render helpers for animated content
interface RenderHelpers {
/** Helper functions for rendering animated content */
// Implementation details depend on internal architecture
}
// Interpolation utilities
interface Interpolators {
/** Vector interpolation utilities */
interpolateVector: (
value: number,
inputRange: number[],
outputRange: Vector[]
) => Vector;
/** Path interpolation for morphing shapes */
interpolatePaths: (
value: number,
inputRange: number[],
outputRange: PathDef[]
) => PathDef;
}
// Texture and buffer management for animations
interface TextureUtils {
/** Texture sharing utilities with Reanimated */
// Used internally for performance optimization
}
interface BufferUtils {
/** Buffer management utilities */
// Used internally for memory management
}import React, { useEffect } from "react";
import { Canvas, Circle, Paint } from "@shopify/react-native-skia";
import { useSharedValue, withRepeat, withTiming } from "react-native-reanimated";
function AnimatedCircle() {
const radius = useSharedValue(20);
useEffect(() => {
radius.value = withRepeat(
withTiming(50, { duration: 1000 }),
-1, // infinite
true // reverse
);
}, []);
return (
<Canvas style={{ width: 200, height: 200 }}>
<Circle cx={100} cy={100} r={radius}>
<Paint color="blue" />
</Circle>
</Canvas>
);
}import React, { useEffect } from "react";
import { Canvas, Circle, Paint } from "@shopify/react-native-skia";
import { useSharedValue, withRepeat, withTiming, useDerivedValue } from "react-native-reanimated";
import { interpolateColors } from "@shopify/react-native-skia";
function ColorAnimatedCircle() {
const progress = useSharedValue(0);
const animatedColor = useDerivedValue(() => {
return interpolateColors(
progress.value,
[0, 1],
["red", "blue"]
);
});
useEffect(() => {
progress.value = withRepeat(
withTiming(1, { duration: 2000 }),
-1,
true
);
}, []);
return (
<Canvas style={{ width: 200, height: 200 }}>
<Circle cx={100} cy={100} r={40}>
<Paint color={animatedColor} />
</Circle>
</Canvas>
);
}import React, { useEffect } from "react";
import { Canvas, Rect, Paint } from "@shopify/react-native-skia";
import { useSharedValue, withRepeat, withTiming } from "react-native-reanimated";
function RotatingRect() {
const rotation = useSharedValue(0);
useEffect(() => {
rotation.value = withRepeat(
withTiming(360, { duration: 2000 }),
-1,
false
);
}, []);
return (
<Canvas style={{ width: 200, height: 200 }}>
<Rect
x={75}
y={75}
width={50}
height={50}
origin={{ x: 100, y: 100 }}
transform={[{ rotate: rotation }]}
>
<Paint color="green" />
</Rect>
</Canvas>
);
}import React, { useEffect } from "react";
import { Canvas, Circle, Paint, LinearGradient } from "@shopify/react-native-skia";
import {
useSharedValue,
withRepeat,
withTiming,
useDerivedValue,
withSequence
} from "react-native-reanimated";
import { interpolate } from "@shopify/react-native-skia";
function ComplexAnimation() {
const progress = useSharedValue(0);
const radius = useDerivedValue(() => {
return interpolate(progress.value, [0, 1], [20, 60]);
});
const opacity = useDerivedValue(() => {
return interpolate(progress.value, [0, 0.5, 1], [1, 0.3, 1]);
});
const translateX = useDerivedValue(() => {
return interpolate(progress.value, [0, 1], [50, 150], "clamp");
});
useEffect(() => {
progress.value = withRepeat(
withSequence(
withTiming(1, { duration: 1500 }),
withTiming(0, { duration: 1500 })
),
-1,
false
);
}, []);
return (
<Canvas style={{ width: 200, height: 200 }}>
<Circle
cx={translateX}
cy={100}
r={radius}
opacity={opacity}
>
<LinearGradient
start={{ x: 0, y: 0 }}
end={{ x: 100, y: 0 }}
colors={["purple", "pink"]}
/>
</Circle>
</Canvas>
);
}import React from "react";
import { Canvas, Circle, Paint } from "@shopify/react-native-skia";
import { useSharedValue } from "react-native-reanimated";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
function GestureAnimatedCircle() {
const translateX = useSharedValue(100);
const translateY = useSharedValue(100);
const panGesture = Gesture.Pan()
.onUpdate((event) => {
translateX.value = event.translationX + 100;
translateY.value = event.translationY + 100;
});
return (
<GestureDetector gesture={panGesture}>
<Canvas style={{ width: 200, height: 200 }}>
<Circle cx={translateX} cy={translateY} r={25}>
<Paint color="orange" />
</Circle>
</Canvas>
</GestureDetector>
);
}// Reanimated types (from react-native-reanimated)
type SharedValue<T> = {
value: T;
};
type DerivedValue<T> = {
readonly value: T;
};
// Animation prop types
type AnimatedProp<T> = T | SharedValue<T> | DerivedValue<T>;
type SkiaProps<T> = {
[K in keyof T]: AnimatedProp<T[K]>;
};
// Interpolation types
type ExtrapolationType = "extend" | "clamp" | "identity";
// Common animated types
type Color = string | number | Float32Array;
type Vector = SkPoint | { x: number; y: number };
type PathDef = string | SkPath;
// Transform types for animation
type Transform3d =
| { translateX: number }
| { translateY: number }
| { scale: number }
| { scaleX: number }
| { scaleY: number }
| { rotate: number }
| { rotateX: number }
| { rotateY: number }
| { rotateZ: number }
| { skewX: number }
| { skewY: number };Install with Tessl CLI
npx tessl i tessl/npm-shopify--react-native-skia