React Three Fiber support for react-spring animations
—
Advanced animation capabilities including chaining, imperative control, utility hooks, and performance optimizations for complex Three.js scenes.
Sequences multiple spring animations to create complex, choreographed motion.
/**
* Chains multiple spring animations in sequence
* @param refs - Array of SpringRef instances to chain
* @param timeSteps - Optional array of timing offsets (0-1) for each ref
* @param timeFrame - Total duration for the chain in milliseconds
*/
function useChain(
refs: SpringRef[],
timeSteps?: number[],
timeFrame?: number
): void;Usage Examples:
import { animated, useSpring, useSpringRef, useChain } from "@react-spring/three";
function ChainedAnimation() {
const scaleRef = useSpringRef();
const rotationRef = useSpringRef();
const positionRef = useSpringRef();
const scaleSpring = useSpring({
ref: scaleRef,
from: { scale: [0, 0, 0] },
to: { scale: [1, 1, 1] },
});
const rotationSpring = useSpring({
ref: rotationRef,
from: { rotation: [0, 0, 0] },
to: { rotation: [0, Math.PI * 2, 0] },
});
const positionSpring = useSpring({
ref: positionRef,
from: { position: [0, 0, 0] },
to: { position: [2, 0, 0] },
});
// Chain animations: scale → rotation → position
useChain([scaleRef, rotationRef, positionRef], [0, 0.3, 0.8], 2000);
return (
<animated.mesh
{...scaleSpring}
{...rotationSpring}
{...positionSpring}
>
<boxGeometry />
<meshStandardMaterial color="purple" />
</animated.mesh>
);
}Creates animations based on scroll position, useful for scroll-driven 3D animations.
/**
* Creates scroll-driven animations
* @param config - Scroll animation configuration
* @returns Spring values based on scroll position
*/
function useScroll(config: ScrollConfig): SpringValues;
interface ScrollConfig {
from?: any;
to?: any;
config?: SpringConfig["config"];
container?: RefObject<HTMLElement>;
offset?: [number, number];
immediate?: boolean;
}Usage Examples:
import { animated, useScroll } from "@react-spring/three";
function ScrollDrivenAnimation() {
const { rotation, scale } = useScroll({
from: { rotation: [0, 0, 0], scale: [1, 1, 1] },
to: { rotation: [0, Math.PI * 2, 0], scale: [2, 2, 2] },
config: { tension: 200, friction: 50 },
});
return (
<animated.mesh rotation={rotation} scale={scale}>
<torusGeometry args={[1, 0.3, 16, 100]} />
<meshStandardMaterial color="gold" />
</animated.mesh>
);
}
// With custom scroll container
function ContainerScrollAnimation() {
const containerRef = useRef();
const { position } = useScroll({
container: containerRef,
from: { position: [0, -10, 0] },
to: { position: [0, 10, 0] },
offset: [0, 1], // Start and end of scroll range
});
return (
<div ref={containerRef} style={{ height: "200vh", overflow: "auto" }}>
<Canvas>
<animated.mesh position={position}>
<sphereGeometry />
<meshStandardMaterial />
</animated.mesh>
</Canvas>
</div>
);
}Creates animations based on window or element resize events.
/**
* Creates resize-driven animations
* @param config - Resize animation configuration
* @returns Spring values based on resize events
*/
function useResize(config: ResizeConfig): SpringValues;
interface ResizeConfig {
from?: any;
to?: any;
config?: SpringConfig["config"];
container?: RefObject<HTMLElement>;
immediate?: boolean;
}Usage Examples:
import { animated, useResize } from "@react-spring/three";
function ResizeResponsiveAnimation() {
const { scale, position } = useResize({
from: { scale: [0.5, 0.5, 0.5], position: [0, 0, 0] },
to: ({ width, height }) => ({
scale: [width / 800, height / 600, 1],
position: [(width - 800) / 400, (height - 600) / 300, 0],
}),
config: { tension: 300, friction: 30 },
});
return (
<animated.mesh scale={scale} position={position}>
<boxGeometry />
<meshStandardMaterial color="orange" />
</animated.mesh>
);
}Creates animations triggered by intersection observer events.
/**
* Creates intersection-driven animations
* @param config - InView animation configuration
* @returns Tuple of [spring values, ref callback]
*/
function useInView(config: InViewConfig): [SpringValues, RefCallback];
interface InViewConfig {
from?: any;
to?: any;
config?: SpringConfig["config"];
rootMargin?: string;
threshold?: number | number[];
triggerOnce?: boolean;
immediate?: boolean;
}
type RefCallback = (element: HTMLElement | null) => void;Usage Examples:
import { animated, useInView } from "@react-spring/three";
function InViewAnimation() {
const [springs, ref] = useInView({
from: { opacity: 0, scale: [0, 0, 0] },
to: { opacity: 1, scale: [1, 1, 1] },
config: { tension: 300, friction: 25 },
threshold: 0.5,
triggerOnce: true,
});
return (
<div ref={ref}>
<Canvas>
<animated.mesh {...springs}>
<icosahedronGeometry />
<meshStandardMaterial color="cyan" />
</animated.mesh>
</Canvas>
</div>
);
}Advanced easing functions and custom interpolations for precise animation control.
/**
* Built-in easing functions
*/
const easings: {
linear: (t: number) => number;
easeInQuad: (t: number) => number;
easeOutQuad: (t: number) => number;
easeInOutQuad: (t: number) => number;
easeInCubic: (t: number) => number;
easeOutCubic: (t: number) => number;
easeInOutCubic: (t: number) => number;
easeInQuart: (t: number) => number;
easeOutQuart: (t: number) => number;
easeInOutQuart: (t: number) => number;
easeInQuint: (t: number) => number;
easeOutQuint: (t: number) => number;
easeInOutQuint: (t: number) => number;
easeInSine: (t: number) => number;
easeOutSine: (t: number) => number;
easeInOutSine: (t: number) => number;
easeInExpo: (t: number) => number;
easeOutExpo: (t: number) => number;
easeInOutExpo: (t: number) => number;
easeInCirc: (t: number) => number;
easeOutCirc: (t: number) => number;
easeInOutCirc: (t: number) => number;
easeInBack: (t: number) => number;
easeOutBack: (t: number) => number;
easeInOutBack: (t: number) => number;
easeInElastic: (t: number) => number;
easeOutElastic: (t: number) => number;
easeInOutElastic: (t: number) => number;
easeInBounce: (t: number) => number;
easeOutBounce: (t: number) => number;
easeInOutBounce: (t: number) => number;
};
/**
* Creates custom interpolators
* @param config - Interpolation configuration
* @returns Interpolator function
*/
function createInterpolator(config: InterpolatorConfig): (input: number) => any;Usage Examples:
import { animated, useSpring, easings, createInterpolator } from "@react-spring/three";
// Using built-in easings
function EasedAnimation() {
const springs = useSpring({
position: [0, 2, 0],
from: { position: [0, 0, 0] },
config: {
duration: 2000,
easing: easings.easeOutBounce,
},
});
return (
<animated.mesh {...springs}>
<sphereGeometry />
<meshStandardMaterial color="red" />
</animated.mesh>
);
}
// Custom interpolation
function CustomInterpolation() {
const colorInterpolator = createInterpolator({
range: [0, 0.5, 1],
output: ["#ff0000", "#00ff00", "#0000ff"],
});
const springs = useSpring({
progress: 1,
from: { progress: 0 },
config: { duration: 3000 },
});
const color = springs.progress.to(colorInterpolator);
return (
<animated.mesh>
<boxGeometry />
<animated.meshStandardMaterial color={color} />
</animated.mesh>
);
}Utilities for optimizing animation performance in complex scenes.
/**
* Reduced motion preference hook
* @returns Boolean indicating user's motion preference
*/
function useReducedMotion(): boolean;
/**
* Cross-platform layout effect hook
*/
function useIsomorphicLayoutEffect(
effect: EffectCallback,
deps?: DependencyList
): void;Usage Examples:
import { animated, useSpring, useReducedMotion } from "@react-spring/three";
function AccessibleAnimation() {
const prefersReducedMotion = useReducedMotion();
const springs = useSpring({
rotation: [0, Math.PI * 2, 0],
from: { rotation: [0, 0, 0] },
config: prefersReducedMotion
? { duration: 0 } // Instant animation
: { tension: 200, friction: 25 }, // Normal spring
loop: !prefersReducedMotion,
});
return (
<animated.mesh {...springs}>
<octahedronGeometry />
<meshStandardMaterial color="violet" />
</animated.mesh>
);
}interface ScrollConfig {
from?: any;
to?: any;
config?: SpringConfig["config"];
container?: RefObject<HTMLElement>;
offset?: [number, number];
immediate?: boolean;
}
interface ResizeConfig {
from?: any;
to?: any | ((size: { width: number; height: number }) => any);
config?: SpringConfig["config"];
container?: RefObject<HTMLElement>;
immediate?: boolean;
}
interface InViewConfig {
from?: any;
to?: any;
config?: SpringConfig["config"];
rootMargin?: string;
threshold?: number | number[];
triggerOnce?: boolean;
immediate?: boolean;
}
interface InterpolatorConfig {
range: number[];
output: any[];
extrapolate?: "identity" | "clamp" | "extend";
}
type RefCallback = (element: HTMLElement | null) => void;
type EffectCallback = () => void | (() => void);
type DependencyList = ReadonlyArray<any>;
// Core animation classes
class Controller<State = any> {
start(props?: any): Promise<any>;
stop(keys?: string[]): void;
update(props: any): void;
set(values: any): void;
}
class SpringValue<T = any> {
constructor(initial: T, props?: any);
get(): T;
set(value: T): void;
start(config?: any): Promise<void>;
stop(): void;
to(value: T): SpringValue<T>;
}
class SpringRef<State = any> {
current: Controller<State>[];
start(): Promise<any>[];
stop(): void;
update(props: any): void;
set(values: any): void;
}
class SpringContext {
static Provider: React.ComponentType<{ value: any; children: React.ReactNode }>;
}
class FrameValue {
priority: number;
get(): any;
set(value: any): void;
}
class Interpolation {
constructor(source: any, args: any);
get(): any;
}
class BailSignal extends Error {
constructor(message?: string);
}
// Utility function
function inferTo(props: any): any;Install with Tessl CLI
npx tessl i tessl/npm-react-spring--three