Utility library for React Native Reanimated and Gesture Handler providing mathematical functions, animations, transformations, and helper utilities for building complex gesture-driven animations.
—
2D vector mathematics with full support for React Native Reanimated SharedValues, providing a foundation for position-based animations and transformations.
Core vector interface supporting generic types, commonly used with numbers or SharedValues.
/**
* 2D vector with x and y components
* @template T - Type of vector components (number, SharedValue<number>, etc.)
*/
interface Vector<T = number> {
x: T;
y: T;
}/**
* Create a vector with optional x and y components
* @param x - X component (default: 0)
* @param y - Y component (default: x or 0)
* @returns Vector with specified components
*/
function vec2<T>(x?: T, y?: T): Vector<T>;
/**
* Vector creation utilities
*/
const vec: {
create: typeof vec2;
};Usage Examples:
import { vec2, vec } from "react-native-redash";
// Create vectors with numbers
const origin = vec2(0, 0);
const position = vec2(100, 200);
const symmetric = vec2(50); // Creates { x: 50, y: 50 }
// Alternative syntax
const center = vec.create(150, 150);React hooks for creating vectors with Reanimated SharedValues.
/**
* Create a vector of SharedValues for animated positions
* @param x1 - Initial x value (default: 0)
* @param y1 - Initial y value (default: x1 or 0)
* @returns Vector with SharedValue components
*/
function useVector(
x1?: number,
y1?: number
): Vector<Animated.SharedValue<number>>;Usage Examples:
import { useVector } from "react-native-redash";
import { useAnimatedStyle, useAnimatedGestureHandler } from "react-native-reanimated";
import { PanGestureHandler } from "react-native-gesture-handler";
const position = useVector(0, 0);
const velocity = useVector();
// Use in gesture handler
const gestureHandler = useAnimatedGestureHandler({
onStart: () => {
// Reset position
position.x.value = 0;
position.y.value = 0;
},
onActive: (event) => {
// Update position during gesture
position.x.value = event.translationX;
position.y.value = event.translationY;
},
onEnd: (event) => {
// Store final velocity
velocity.x.value = event.velocityX;
velocity.y.value = event.velocityY;
}
});
// Use in animated styles
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: position.x.value },
{ translateY: position.y.value }
]
}));Vectors are used throughout the library for coordinate transformations, path operations, and matrix calculations.
import {
useVector,
canvas2Cartesian,
cartesian2Polar,
transformOrigin
} from "react-native-redash";
import { useAnimatedStyle } from "react-native-reanimated";
const center = useVector(150, 150);
const position = useVector(100, 100);
const animatedStyle = useAnimatedStyle(() => {
// Convert coordinates
const cartesian = canvas2Cartesian(
{ x: position.x.value, y: position.y.value },
{ x: center.x.value, y: center.y.value }
);
// Convert to polar
const polar = cartesian2Polar(cartesian);
// Apply transformation with origin
const transform = transformOrigin(
{ x: center.x.value, y: center.y.value },
[{ rotate: `${polar.theta}rad` }]
);
return { transform };
});/**
* Hook for translation animations using vector of SharedValues
* @param vector - Vector with SharedValue components
* @returns Animated style with translation transform
*/
function useTranslation(vector: Vector<Animated.SharedValue<number>>): {
transform: { translateX: number; translateY: number }[];
};Complete Example:
import React from "react";
import { View } from "react-native";
import {
useVector,
useTranslation,
vec2
} from "react-native-redash";
import Animated, {
useSharedValue,
useAnimatedGestureHandler,
useAnimatedStyle,
withSpring
} from "react-native-reanimated";
import { PanGestureHandler } from "react-native-gesture-handler";
export const DraggableBox = () => {
const position = useVector(0, 0);
const offset = useVector(0, 0);
// Alternative: Use the translation hook
const translationStyle = useTranslation(position);
const gestureHandler = useAnimatedGestureHandler({
onStart: () => {
offset.x.value = position.x.value;
offset.y.value = position.y.value;
},
onActive: (event) => {
position.x.value = offset.x.value + event.translationX;
position.y.value = offset.y.value + event.translationY;
},
onEnd: () => {
// Spring back to center
const center = vec2(0, 0);
position.x.value = withSpring(center.x);
position.y.value = withSpring(center.y);
}
});
// Custom animated style (alternative to useTranslation)
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: position.x.value },
{ translateY: position.y.value }
]
}));
return (
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View
style={[
{ width: 100, height: 100, backgroundColor: 'blue' },
animatedStyle // or translationStyle
]}
/>
</PanGestureHandler>
);
};All vector operations maintain type safety when working with different component types:
// Vector with numbers
const numericVector: Vector<number> = { x: 10, y: 20 };
// Vector with SharedValues (animated)
const animatedVector: Vector<Animated.SharedValue<number>> = {
x: useSharedValue(10),
y: useSharedValue(20)
};
// Vector with mixed types (if needed)
const mixedVector: Vector<Animated.Adaptable<number>> = {
x: 10,
y: useSharedValue(20)
};Install with Tessl CLI
npx tessl i tessl/npm-react-native-redash