CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-shopify--react-native-skia

High-performance React Native Graphics using Skia

Pending
Overview
Eval results
Files

animation.mddocs/

Animation Integration

Animation utilities and React Native Reanimated integration for creating smooth, performant animations in React Native Skia.

Capabilities

Core Animation Functions

/**
 * 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;

Animation Prop System

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]>;
};

Reanimated Integration

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;

Animation Utilities

// 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
}

Usage Examples

Basic Property Animation

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>
  );
}

Color Animation

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>
  );
}

Transform Animation

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>
  );
}

Complex Animation with Multiple Properties

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>
  );
}

Gesture-Driven Animation

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>
  );
}

Animation Performance Tips

  1. Use SharedValues: Always use Reanimated's SharedValue for animated properties
  2. Prefer useDerivedValue: Use useDerivedValue for computed animated values
  3. Minimize Re-renders: Keep animated logic in the UI thread when possible
  4. Batch Updates: Group related property changes together
  5. Use runOnUI: For complex calculations, use runOnUI to run on the UI thread

Core Types

// 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

docs

advanced.md

animation.md

canvas-views.md

effects-filters.md

index.md

paint-styling.md

shapes.md

skia-api.md

text.md

tile.json