CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-native-reanimated

More powerful alternative to Animated library for React Native with UI thread animations and advanced gesture handling.

Pending
Overview
Eval results
Files

interpolation-easing.mddocs/

Interpolation and Easing

Mathematical functions for smooth value transitions, custom animation curves, and color interpolation that enable sophisticated animation effects.

Capabilities

Numeric Interpolation

Maps values from one range to another using linear interpolation.

/**
 * Maps a value from an input range to an output range using linear interpolation
 * @param value - The input value to interpolate
 * @param inputRange - Array of input values (must be monotonically increasing)
 * @param outputRange - Array of corresponding output values
 * @param extrapolate - How to handle values outside the input range
 * @returns Interpolated output value
 */
function interpolate(
  value: number,
  inputRange: readonly number[],
  outputRange: readonly number[],
  extrapolate?: ExtrapolationType
): number;

/**
 * Clamps a value between minimum and maximum bounds
 * @param value - Value to clamp
 * @param min - Minimum allowed value
 * @param max - Maximum allowed value
 * @returns Clamped value
 */
function clamp(value: number, min: number, max: number): number;

enum Extrapolation {
  /** Extend the interpolation beyond the ranges */
  EXTEND = "extend",
  /** Clamp to the edge values of the ranges */
  CLAMP = "clamp", 
  /** Return the input value as-is when outside ranges */
  IDENTITY = "identity"
}

type ExtrapolationType = Extrapolation;

/** @deprecated Use Extrapolation instead */
const Extrapolate = Extrapolation;

Usage Examples:

import React from "react";
import Animated, { 
  useSharedValue,
  useAnimatedStyle,
  interpolate,
  Extrapolation,
  clamp,
  withTiming,
  useDerivedValue 
} from "react-native-reanimated";
import { Button } from "react-native";

const InterpolationExample = () => {
  const progress = useSharedValue(0);

  // Basic interpolation
  const animatedStyle = useAnimatedStyle(() => ({
    opacity: interpolate(progress.value, [0, 1], [0.2, 1]),
    transform: [
      {
        scale: interpolate(progress.value, [0, 0.5, 1], [1, 1.5, 1]),
      },
      {
        rotate: `${interpolate(progress.value, [0, 1], [0, 360])}deg`,
      },
    ],
  }));

  // Interpolation with different extrapolation modes
  const extendedStyle = useAnimatedStyle(() => ({
    // Extends beyond range
    translateX: interpolate(
      progress.value,
      [0, 1],
      [0, 100],
      Extrapolation.EXTEND
    ),
    // Clamps to range bounds
    translateY: interpolate(
      progress.value,
      [0, 1], 
      [0, 100],
      Extrapolation.CLAMP
    ),
  }));

  // Complex multi-point interpolation
  const complexStyle = useAnimatedStyle(() => ({
    backgroundColor: progress.value < 0.33 ? "red" : 
                     progress.value < 0.66 ? "green" : "blue",
    borderRadius: interpolate(
      progress.value,
      [0, 0.25, 0.5, 0.75, 1],
      [0, 10, 25, 10, 0]
    ),
  }));

  // Using clamp utility
  const clampedValue = useDerivedValue(() => 
    clamp(progress.value * 150, 50, 100)
  );

  const clampedStyle = useAnimatedStyle(() => ({
    width: clampedValue.value,
    height: clampedValue.value,
  }));

  const animate = () => {
    progress.value = withTiming(progress.value === 0 ? 1 : 0, { 
      duration: 2000 
    });
  };

  return (
    <>
      <Button title="Animate" onPress={animate} />
      
      {/* Basic interpolation */}
      <Animated.View
        style={[
          { width: 100, height: 100, backgroundColor: "lightblue", margin: 10 },
          animatedStyle,
        ]}
      />

      {/* Extended interpolation */}
      <Animated.View
        style={[
          { width: 50, height: 50, backgroundColor: "lightgreen", margin: 10 },
          extendedStyle,
        ]}
      />

      {/* Complex interpolation */}
      <Animated.View
        style={[
          { width: 80, height: 80, margin: 10 },
          complexStyle,
        ]}
      />

      {/* Clamped size */}
      <Animated.View
        style={[
          { backgroundColor: "lightcoral", margin: 10 },
          clampedStyle,
        ]}
      />
    </>
  );
};

Color Interpolation

Interpolates between color values in different color spaces.

/**
 * Interpolates between color values
 * @param value - The input value to interpolate
 * @param inputRange - Array of input values (must be monotonically increasing)
 * @param outputRange - Array of color strings to interpolate between
 * @param colorSpace - Color space for interpolation (RGB or HSV)
 * @param options - Additional interpolation options
 * @returns Interpolated color string
 */
function interpolateColor(
  value: number,
  inputRange: readonly number[],
  outputRange: readonly string[],
  colorSpace?: ColorSpace,
  options?: InterpolationOptions
): string;

enum ColorSpace {
  RGB = "rgb",
  HSV = "hsv"
}

interface InterpolationOptions {
  /** Gamma correction for RGB interpolation */
  gamma?: number;
  /** Whether to use shorter or longer path in HSV */
  useCorrectedHSVInterpolation?: boolean;
}

/**
 * Hook for creating reusable color interpolation configurations
 * @param inputRange - Input range for interpolation
 * @param outputRange - Output color range
 * @param colorSpace - Color space to use
 * @returns Interpolation configuration function
 */
function useInterpolateConfig(
  inputRange: readonly number[],
  outputRange: readonly string[],
  colorSpace?: ColorSpace
): (value: number) => string;

Usage Examples:

import React from "react";
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  interpolateColor,
  ColorSpace,
  withTiming,
  useInterpolateConfig,
  useDerivedValue
} from "react-native-reanimated";
import { Button } from "react-native";

const ColorInterpolationExample = () => {
  const progress = useSharedValue(0);

  // RGB color interpolation
  const rgbStyle = useAnimatedStyle(() => ({
    backgroundColor: interpolateColor(
      progress.value,
      [0, 0.5, 1],
      ["#FF0000", "#00FF00", "#0000FF"], // Red -> Green -> Blue
      ColorSpace.RGB
    ),
  }));

  // HSV color interpolation (smoother transitions)
  const hsvStyle = useAnimatedStyle(() => ({
    backgroundColor: interpolateColor(
      progress.value,
      [0, 1],
      ["#FF0000", "#0000FF"], // Red -> Blue via HSV
      ColorSpace.HSV
    ),
  }));

  // Complex color progression
  const rainbowStyle = useAnimatedStyle(() => ({
    backgroundColor: interpolateColor(
      progress.value,
      [0, 0.16, 0.33, 0.5, 0.66, 0.83, 1],
      [
        "#FF0000", // Red
        "#FF8000", // Orange  
        "#FFFF00", // Yellow
        "#00FF00", // Green
        "#0000FF", // Blue
        "#8000FF", // Indigo
        "#FF00FF", // Violet
      ],
      ColorSpace.HSV
    ),
  }));

  // Using interpolation config hook
  const colorConfig = useInterpolateConfig(
    [0, 0.3, 0.7, 1],
    ["#1a1a1a", "#ff6b6b", "#4ecdc4", "#45b7d1"],
    ColorSpace.RGB
  );

  const configStyle = useAnimatedStyle(() => ({
    backgroundColor: colorConfig(progress.value),
  }));

  // Color with alpha interpolation
  const alphaStyle = useAnimatedStyle(() => ({
    backgroundColor: interpolateColor(
      progress.value,
      [0, 1],
      ["rgba(255, 0, 0, 0.2)", "rgba(255, 0, 0, 1.0)"]
    ),
  }));

  // Border color animation
  const borderStyle = useAnimatedStyle(() => ({
    borderColor: interpolateColor(
      progress.value,
      [0, 1],
      ["#cccccc", "#ff0000"],
      ColorSpace.RGB
    ),
    borderWidth: 3,
  }));

  const animate = () => {
    progress.value = withTiming(progress.value === 0 ? 1 : 0, { 
      duration: 3000 
    });
  };

  return (
    <>
      <Button title="Animate Colors" onPress={animate} />
      
      {/* RGB interpolation */}
      <Animated.View
        style={[
          { width: 100, height: 50, margin: 5, borderRadius: 5 },
          rgbStyle,
        ]}
      />
      
      {/* HSV interpolation */}
      <Animated.View
        style={[
          { width: 100, height: 50, margin: 5, borderRadius: 5 },
          hsvStyle,
        ]}
      />
      
      {/* Rainbow progression */}
      <Animated.View
        style={[
          { width: 100, height: 50, margin: 5, borderRadius: 5 },
          rainbowStyle,
        ]}
      />
      
      {/* Config-based interpolation */}
      <Animated.View
        style={[
          { width: 100, height: 50, margin: 5, borderRadius: 5 },
          configStyle,
        ]}
      />
      
      {/* Alpha interpolation */}
      <Animated.View
        style={[
          { width: 100, height: 50, margin: 5, borderRadius: 5 },
          alphaStyle,
        ]}
      />
      
      {/* Border color */}
      <Animated.View
        style={[
          { 
            width: 100, 
            height: 50, 
            margin: 5, 
            borderRadius: 5,
            backgroundColor: "white" 
          },
          borderStyle,
        ]}
      />
    </>
  );
};

Color Processing Functions

Utility functions for color validation, conversion, and processing for animations.

/**
 * Checks if a value is a valid color string or number
 * @param value - Value to test for color validity
 * @returns True if value is a valid color
 */
function isColor(value: unknown): boolean;

/**
 * Converts a color value to RGBA array format
 * @param color - Color value (string, number, or hex)
 * @returns RGBA array with values from 0-1
 */
function convertToRGBA(color: unknown): ParsedColorArray;

/**
 * Processes color values for platform-specific rendering
 * @param color - Raw color value to process
 * @returns Processed color number, null, or undefined
 */
function processColor(color: unknown): number | null | undefined;

type ParsedColorArray = [number, number, number, number]; // [r, g, b, a]

Usage Examples:

import { isColor, convertToRGBA, processColor } from "react-native-reanimated";

// Color validation
const validateColors = () => {
  console.log(isColor("red"));           // true
  console.log(isColor("#FF0000"));       // true
  console.log(isColor("rgb(255,0,0)"));  // true
  console.log(isColor("invalid"));       // false
  console.log(isColor(123));             // false
};

// Color conversion for animations
const useColorAnimation = () => {
  const colorValue = useSharedValue("red");
  
  const animatedStyle = useAnimatedStyle(() => {
    // Convert color to RGBA for processing
    const [r, g, b, a] = convertToRGBA(colorValue.value);
    
    return {
      backgroundColor: `rgba(${r * 255}, ${g * 255}, ${b * 255}, ${a})`,
    };
  });

  return animatedStyle;
};

// Color processing for platform compatibility
const processColors = () => {
  const colors = ["red", "#FF0000", "rgb(255,0,0)", null, undefined];
  
  colors.forEach(color => {
    const processed = processColor(color);
    console.log(`${color} -> ${processed}`);
  });
};

// Advanced color interpolation with conversion
const ColorTransition = () => {
  const progress = useSharedValue(0);
  
  const animatedStyle = useAnimatedStyle(() => {
    // Convert start and end colors to RGBA
    const startColor = convertToRGBA("red");     // [1, 0, 0, 1]
    const endColor = convertToRGBA("blue");      // [0, 0, 1, 1]
    
    // Manually interpolate each component
    const r = interpolate(progress.value, [0, 1], [startColor[0], endColor[0]]);
    const g = interpolate(progress.value, [0, 1], [startColor[1], endColor[1]]);
    const b = interpolate(progress.value, [0, 1], [startColor[2], endColor[2]]);
    const a = interpolate(progress.value, [0, 1], [startColor[3], endColor[3]]);
    
    return {
      backgroundColor: `rgba(${r * 255}, ${g * 255}, ${b * 255}, ${a})`,
    };
  });

  return <Animated.View style={animatedStyle} />;
};

Easing Functions

Predefined and custom easing functions for natural animation curves.

const Easing: {
  /** Linear easing function (f(t) = t) */
  linear: EasingFunction;
  /** Default ease function with gentle acceleration and deceleration */
  ease: EasingFunction;
  /** Quadratic easing (f(t) = t²) */
  quad: EasingFunction;
  /** Cubic easing (f(t) = t³) */
  cubic: EasingFunction;
  /** Polynomial easing with custom exponent */
  poly(n: number): EasingFunction;
  /** Sinusoidal easing */
  sin: EasingFunction;
  /** Circular easing */
  circle: EasingFunction;
  /** Exponential easing */
  exp: EasingFunction;
  /** Elastic spring easing with bounce effect */
  elastic(bounciness?: number): EasingFunction;
  /** Back easing with overshoot effect */
  back(s?: number): EasingFunction;
  /** Bouncing easing with multiple bounces */
  bounce: EasingFunction;
  /** Cubic bezier curve easing */
  bezier(x1: number, y1: number, x2: number, y2: number): EasingFunction;
  
  /** Apply easing in forward direction */
  in(easing: EasingFunction): EasingFunction;
  /** Apply easing in reverse direction */
  out(easing: EasingFunction): EasingFunction;
  /** Apply easing in both directions (symmetric) */
  inOut(easing: EasingFunction): EasingFunction;
};

type EasingFunction = (value: number) => number;

interface EasingFunctionFactory {
  factory(): EasingFunction;
}

Usage Examples:

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

const EasingExample = () => {
  const progress1 = useSharedValue(0);
  const progress2 = useSharedValue(0);
  const progress3 = useSharedValue(0);
  const progress4 = useSharedValue(0);

  // Linear easing
  const linearStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: progress1.value * 200 }],
  }));

  // Ease out quadratic
  const easeOutStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: progress2.value * 200 }],
  }));

  // Bounce easing
  const bounceStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: progress3.value * 200 }],
  }));

  // Custom bezier easing
  const bezierStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: progress4.value * 200 }],
  }));

  const animateLinear = () => {
    progress1.value = withTiming(progress1.value === 0 ? 1 : 0, {
      duration: 1000,
      easing: Easing.linear,
    });
  };

  const animateEaseOut = () => {
    progress2.value = withTiming(progress2.value === 0 ? 1 : 0, {
      duration: 1000,
      easing: Easing.out(Easing.quad),
    });
  };

  const animateBounce = () => {
    progress3.value = withTiming(progress3.value === 0 ? 1 : 0, {
      duration: 1500,
      easing: Easing.bounce,
    });
  };

  const animateBezier = () => {
    progress4.value = withTiming(progress4.value === 0 ? 1 : 0, {
      duration: 1000,
      easing: Easing.bezier(0.25, 0.1, 0.25, 1), // CSS ease
    });
  };

  return (
    <>
      <Button title="Linear" onPress={animateLinear} />
      <Animated.View
        style={[
          { width: 50, height: 50, backgroundColor: "red", margin: 5 },
          linearStyle,
        ]}
      />

      <Button title="Ease Out Quad" onPress={animateEaseOut} />
      <Animated.View
        style={[
          { width: 50, height: 50, backgroundColor: "green", margin: 5 },
          easeOutStyle,
        ]}
      />

      <Button title="Bounce" onPress={animateBounce} />
      <Animated.View
        style={[
          { width: 50, height: 50, backgroundColor: "blue", margin: 5 },
          bounceStyle,
        ]}
      />

      <Button title="Bezier" onPress={animateBezier} />
      <Animated.View
        style={[
          { width: 50, height: 50, backgroundColor: "purple", margin: 5 },
          bezierStyle,
        ]}
      />
    </>
  );
};

Advanced Easing Patterns

Complex easing combinations and custom curves.

Custom Easing Functions:

import { Easing } from "react-native-reanimated";

// Create custom easing functions
const customEasings = {
  // Elastic with custom bounciness
  elasticOut: Easing.out(Easing.elastic(2)),
  
  // Back with overshoot
  backInOut: Easing.inOut(Easing.back(1.7)),
  
  // Custom polynomial
  fastSlowFast: Easing.inOut(Easing.poly(3)),
  
  // Complex bezier curves
  cssEase: Easing.bezier(0.25, 0.1, 0.25, 1),
  cssEaseIn: Easing.bezier(0.42, 0, 1, 1),
  cssEaseOut: Easing.bezier(0, 0, 0.58, 1),
  cssEaseInOut: Easing.bezier(0.42, 0, 0.58, 1),
  
  // Material Design curves
  materialStandard: Easing.bezier(0.4, 0.0, 0.2, 1),
  materialDecelerate: Easing.bezier(0.0, 0.0, 0.2, 1),
  materialAccelerate: Easing.bezier(0.4, 0.0, 1, 1),
  
  // Custom stepped function
  stepped: (steps: number) => (t: number) => Math.floor(t * steps) / steps,
};

Interpolation Configuration

Advanced interpolation patterns and utilities.

interface InterpolateConfig {
  inputRange: readonly number[];
  outputRange: readonly (string | number)[];
  extrapolate?: ExtrapolationType;
  extrapolateLeft?: ExtrapolationType;
  extrapolateRight?: ExtrapolationType;
}

interface InterpolateHSV {
  h: number;
  s: number;
  v: number;
}

interface InterpolateRGB {
  r: number;
  g: number;
  b: number;
}

Advanced Interpolation Example:

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

const AdvancedInterpolationExample = () => {
  const scrollY = useSharedValue(0);

  // Complex header transformation
  const headerStyle = useAnimatedStyle(() => {
    const headerHeight = 200;
    const minHeight = 80;
    
    return {
      height: interpolate(
        scrollY.value,
        [0, headerHeight - minHeight],
        [headerHeight, minHeight],
        Extrapolation.CLAMP
      ),
      opacity: interpolate(
        scrollY.value,
        [0, headerHeight / 2, headerHeight],
        [1, 0.8, 0.3],
        Extrapolation.CLAMP
      ),
      transform: [
        {
          scale: interpolate(
            scrollY.value,
            [0, headerHeight],
            [1, 0.9],
            Extrapolation.CLAMP
          ),
        },
      ],
    };
  });

  // Parallax background
  const backgroundStyle = useAnimatedStyle(() => ({
    transform: [
      {
        translateY: interpolate(
          scrollY.value,
          [0, 300],
          [0, -100],
          Extrapolation.EXTEND // Allow over-scroll effect
        ),
      },
      {
        scale: interpolate(
          scrollY.value,
          [-100, 0, 300],
          [1.2, 1, 0.8],
          {
            extrapolateLeft: Extrapolation.CLAMP,
            extrapolateRight: Extrapolation.EXTEND,
          }
        ),
      },
    ],
  }));

  return (
    <>
      <Animated.View style={[{ position: "absolute", top: 0 }, backgroundStyle]}>
        {/* Background content */}
      </Animated.View>
      
      <Animated.View style={headerStyle}>
        {/* Header content */}
      </Animated.View>
      
      <Animated.ScrollView
        onScroll={(event) => {
          scrollY.value = event.nativeEvent.contentOffset.y;
        }}
        scrollEventThrottle={16}
      >
        {/* Scroll content */}
      </Animated.ScrollView>
    </>
  );
};

Type Definitions

type ExtrapolationType = Extrapolation | {
  extrapolateLeft?: Extrapolation;
  extrapolateRight?: Extrapolation;
};

interface ExtrapolationConfig {
  extrapolateLeft?: ExtrapolationType;
  extrapolateRight?: ExtrapolationType;
}

type ParsedColorArray = readonly [number, number, number, number]; // RGBA

interface InterpolationOptions {
  gamma?: number;
  useCorrectedHSVInterpolation?: boolean;
}

Install with Tessl CLI

npx tessl i tessl/npm-react-native-reanimated

docs

animated-components.md

animation-functions.md

configuration-utilities.md

core-reactive-system.md

css-integration.md

event-handling.md

index.md

interpolation-easing.md

layout-animations.md

platform-functions.md

screen-transitions.md

testing-utilities.md

worklet-functions.md

tile.json