CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-spring--three

React Three Fiber support for react-spring animations

Pending
Overview
Eval results
Files

advanced-features.mddocs/

Advanced Animation Features

Advanced animation capabilities including chaining, imperative control, utility hooks, and performance optimizations for complex Three.js scenes.

Capabilities

useChain Hook

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

useScroll Hook

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

useResize Hook

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

useInView Hook

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

Custom Easings and Interpolations

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

Performance Optimization Utilities

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

Types

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

docs

advanced-features.md

animated-components.md

animation-components.md

index.md

spring-hooks.md

tile.json