or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

animation-controls.mdconfiguration.mddom-utilities.mdgestures.mdindex.mdlayout-presence.mdmotion-components.mdmotion-values.mdscroll-view.md
tile.json

animation-controls.mddocs/

Animation Controls

Imperative animation hooks and utilities for programmatic control over animations, including scoped animations and animation controls.

Capabilities

useAnimate Hook

Creates a scoped animation function that can target elements within a specific scope.

/**
 * Creates a scoped animation function for imperative animations
 * @returns Tuple of [scope ref, animate function]
 */
function useAnimate<T extends Element = any>(): [
  scope: AnimationScope<T>,
  animate: (
    target: string | Element,
    keyframes: Record<string, any> | Record<string, any>[],
    options?: AnimationOptions
  ) => AnimationPlaybackControls
];

interface AnimationScope<T extends Element = any> extends React.RefObject<T> {
  /**
   * Animation scope reference for targeting elements
   */
}

interface AnimationOptions {
  /**
   * Animation duration in seconds
   */
  duration?: number;
  
  /**
   * Delay before animation starts in seconds
   */
  delay?: number;
  
  /**
   * Easing function or array of easing functions
   */
  ease?: Easing | Easing[];
  
  /**
   * Number of times to repeat animation
   */
  repeat?: number;
  
  /**
   * Type of repeat: "loop" or "reverse"
   */
  repeatType?: "loop" | "reverse" | "mirror";
  
  /**
   * Delay between repeats in seconds
   */
  repeatDelay?: number;
  
  /**
   * Animation type
   */
  type?: "tween" | "spring" | "keyframes" | "inertia";
  
  /**
   * Spring configuration (when type is "spring")
   */
  bounce?: number;
  damping?: number;
  mass?: number;
  stiffness?: number;
  velocity?: number;
  restSpeed?: number;
  restDelta?: number;
}

interface AnimationPlaybackControls {
  /**
   * Stop the animation
   */
  stop: () => void;
  
  /**
   * Pause the animation
   */
  pause: () => void;
  
  /**
   * Resume the animation
   */
  play: () => void;
  
  /**
   * Reverse the animation direction
   */
  reverse: () => void;
  
  /**
   * Cancel the animation and reset to initial state
   */
  cancel: () => void;
  
  /**
   * Complete the animation immediately
   */
  complete: () => void;
  
  /**
   * Promise that resolves when animation completes
   */
  then: (
    onResolve?: () => void,
    onReject?: (error: any) => void
  ) => Promise<void>;
}

Usage Examples:

import { useAnimate } from "framer-motion";

function AnimatedComponent() {
  const [scope, animate] = useAnimate();
  
  const handleClick = async () => {
    // Animate multiple elements in sequence
    await animate(".card", { x: 100 }, { duration: 0.5 });
    await animate(".title", { opacity: 0.5 }, { duration: 0.3 });
    
    // Animate multiple properties
    await animate(
      ".button",
      {
        scale: [1, 1.2, 1],
        rotate: [0, 180, 360],
        backgroundColor: ["#ff0000", "#00ff00", "#0000ff"]
      },
      { duration: 1, ease: "easeInOut" }
    );
  };
  
  return (
    <div ref={scope}>
      <div className="card">Card content</div>
      <h1 className="title">Title</h1>
      <button className="button" onClick={handleClick}>
        Animate
      </button>
    </div>
  );
}

useAnimationControls Hook

Creates animation controls that can be passed to motion components for imperative control.

/**
 * Creates animation controls for imperative animation control
 * @returns Animation controls instance
 */
function useAnimationControls(): LegacyAnimationControls;

/**
 * Alias for useAnimationControls
 */
function useAnimation(): LegacyAnimationControls;

interface LegacyAnimationControls {
  /**
   * Start an animation
   * @param definition - Animation definition or variant name
   * @returns Promise that resolves when animation completes
   */
  start(definition?: AnimationDefinition): Promise<any>;
  
  /**
   * Stop all running animations
   */
  stop(): void;
  
  /**
   * Mount the controls (called automatically by motion components)
   * @returns Cleanup function
   */
  mount(): () => void;
}

type AnimationDefinition = string | {
  [key: string]: any;
} | ((custom?: any) => {
  [key: string]: any;
});

Usage Examples:

import { motion, useAnimationControls } from "framer-motion";

function ControlledAnimation() {
  const controls = useAnimationControls();
  
  const variants = {
    hidden: { opacity: 0, scale: 0.8 },
    visible: { opacity: 1, scale: 1 },
    pulse: { 
      scale: [1, 1.1, 1],
      transition: { duration: 0.5, repeat: Infinity }
    }
  };
  
  return (
    <div>
      <motion.div
        animate={controls}
        variants={variants}
        initial="hidden"
      >
        Controlled animation
      </motion.div>
      
      <button onClick={() => controls.start("visible")}>
        Show
      </button>
      <button onClick={() => controls.start("pulse")}>
        Pulse
      </button>
      <button onClick={() => controls.stop()}>
        Stop
      </button>
    </div>
  );
}

Animation Controls Factory

Utility for creating animation controls outside of React components.

/**
 * Creates animation controls instance
 * @returns New animation controls
 */
function animationControls(): LegacyAnimationControls;

useAnimateMini Hook

Minimal animation hook for WAAPI-based animations with smaller bundle size.

/**
 * Minimal animation hook using Web Animations API
 * @returns Animation function for WAAPI animations
 */
function useAnimateMini(): (
  target: string | Element,
  keyframes: Record<string, any> | Record<string, any>[],
  options?: AnimationOptions
) => Animation;

Usage Example:

import { useAnimateMini } from "framer-motion/mini";

function MiniAnimation() {
  const animate = useAnimateMini();
  
  const handleClick = () => {
    animate(
      ".element",
      { transform: ["translateX(0px)", "translateX(100px)"] },
      { duration: 500, easing: "ease-out" }
    );
  };
  
  return (
    <div>
      <div className="element">Element to animate</div>
      <button onClick={handleClick}>Animate</button>
    </div>
  );
}

Animation Sequencing

Creating complex animation sequences with timing control:

// Sequential animations
async function sequence() {
  await animate(".first", { x: 100 }, { duration: 0.5 });
  await animate(".second", { y: 100 }, { duration: 0.5 });
  await animate(".third", { rotate: 180 }, { duration: 0.5 });
}

// Parallel animations
function parallel() {
  animate(".first", { x: 100 }, { duration: 0.5 });
  animate(".second", { y: 100 }, { duration: 0.5, delay: 0.1 });
  animate(".third", { rotate: 180 }, { duration: 0.5, delay: 0.2 });
}

// Staggered animations
function stagger() {
  const elements = document.querySelectorAll(".item");
  elements.forEach((element, index) => {
    animate(
      element,
      { opacity: 1, y: 0 },
      { 
        duration: 0.5,
        delay: index * 0.1,
        ease: "easeOut"
      }
    );
  });
}

Advanced Control Patterns

Dynamic Animation Definitions:

const controls = useAnimationControls();

// Function-based animation definition
controls.start((custom) => ({
  x: custom.targetX,
  y: custom.targetY,
  transition: { duration: custom.duration }
}));

// Conditional animations
controls.start(isVisible ? "visible" : "hidden");

// Chained animations
controls.start("slideIn")
  .then(() => controls.start("fadeIn"))
  .then(() => controls.start("bounce"));

Coordinated Multi-Element Animation:

function CoordinatedAnimation() {
  const [scope, animate] = useAnimate();
  
  const animateSequence = async () => {
    // Animate multiple elements with precise timing
    const timeline = [
      [".header", { opacity: 1, y: 0 }, { duration: 0.5 }],
      [".content", { opacity: 1, x: 0 }, { duration: 0.6, delay: 0.2 }],
      [".footer", { opacity: 1, scale: 1 }, { duration: 0.4, delay: 0.4 }]
    ];
    
    // Run animations in parallel with different delays
    timeline.forEach(([target, keyframes, options]) => {
      animate(target, keyframes, options);
    });
  };
  
  return (
    <div ref={scope}>
      <div className="header" style={{ opacity: 0, y: -20 }}>Header</div>
      <div className="content" style={{ opacity: 0, x: -20 }}>Content</div>
      <div className="footer" style={{ opacity: 0, scale: 0.8 }}>Footer</div>
      <button onClick={animateSequence}>Animate All</button>
    </div>
  );
}