CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-framer-motion

A production-ready motion library for React that provides comprehensive animation and gesture APIs for creating fluid, performant interactions.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

dom-utilities.mddocs/

DOM Utilities

Direct DOM animation functions that work without React, for imperative animations and scroll tracking.

Capabilities

Animate Function

Direct DOM animation function using Web Animations API or fallback engine.

/**
 * Animate DOM elements directly without React
 * @param element - Element to animate (selector string or Element)
 * @param keyframes - Animation keyframes or single keyframe object
 * @param options - Animation options
 * @returns Animation playback controls
 */
function animate(
  element: string | Element,
  keyframes: Record<string, any> | Record<string, any>[],
  options?: AnimationOptions
): AnimationPlaybackControls;

/**
 * Create scoped animate function bound to a container
 * @param scope - Container element for scoped queries
 * @returns Scoped animate function
 */
function createScopedAnimate(scope: Element): typeof animate;

interface AnimationOptions {
  /**
   * Animation duration in seconds
   */
  duration?: number;
  
  /**
   * Delay before animation starts in seconds
   */
  delay?: number;
  
  /**
   * Easing function or WAAPI easing string
   */
  ease?: string | number[] | ((t: number) => number);
  
  /**
   * Number of times to repeat animation
   */
  repeat?: number;
  
  /**
   * Type of repeat behavior
   */
  repeatType?: "loop" | "reverse" | "mirror";
  
  /**
   * Delay between repeats in seconds
   */
  repeatDelay?: number;
  
  /**
   * Direction of animation
   */
  direction?: "normal" | "reverse" | "alternate" | "alternate-reverse";
  
  /**
   * Fill mode for animation
   */
  fill?: "none" | "forwards" | "backwards" | "both";
  
  /**
   * Animation end behavior
   */
  endDelay?: number;
  
  /**
   * Start time offset
   */
  startTime?: number;
  
  /**
   * Animation timing function
   */
  composite?: "replace" | "add" | "accumulate";
}

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
   */
  finish(): void;
  
  /**
   * Get current animation time
   */
  currentTime: number;
  
  /**
   * Get animation duration
   */
  duration: number;
  
  /**
   * Get animation playback rate
   */
  playbackRate: number;
  
  /**
   * Set animation playback rate
   */
  updatePlaybackRate(rate: number): void;
  
  /**
   * Promise that resolves when animation completes
   */
  then(onResolve?: () => void, onReject?: (error: any) => void): Promise<void>;
  
  /**
   * Attach event listeners
   */
  addEventListener(event: string, handler: EventListener): void;
  
  /**
   * Remove event listeners
   */
  removeEventListener(event: string, handler: EventListener): void;
}

Usage Examples:

import { animate, createScopedAnimate } from "framer-motion/dom";

// Basic DOM animation
function basicDOMAnimation() {
  // Animate single element
  animate(".box", { x: 100, rotate: 45 }, { duration: 1 });
  
  // Animate with keyframes
  animate(".circle", [
    { scale: 1, backgroundColor: "#ff0000" },
    { scale: 1.5, backgroundColor: "#00ff00" },
    { scale: 1, backgroundColor: "#0000ff" }
  ], { 
    duration: 2, 
    repeat: Infinity, 
    repeatType: "reverse" 
  });
  
  // Animate multiple elements
  document.querySelectorAll(".item").forEach((element, index) => {
    animate(element, 
      { y: -50, opacity: [0, 1] }, 
      { duration: 0.5, delay: index * 0.1 }
    );
  });
}

// Animation with controls
function controlledDOMAnimation() {
  const controls = animate(".animated-element", 
    { rotate: 360 }, 
    { duration: 2, repeat: Infinity }
  );
  
  // Control playback
  document.getElementById("pause")?.addEventListener("click", () => {
    controls.pause();
  });
  
  document.getElementById("play")?.addEventListener("click", () => {
    controls.play();
  });
  
  document.getElementById("reverse")?.addEventListener("click", () => {
    controls.reverse();
  });
  
  document.getElementById("stop")?.addEventListener("click", () => {
    controls.stop();
  });
  
  // Promise-based completion
  controls.then(() => {
    console.log("Animation completed");
  });
}

// Scoped animations
function scopedDOMAnimation() {
  const container = document.getElementById("animation-container");
  if (container) {
    const scopedAnimate = createScopedAnimate(container);
    
    // Animate elements within container only
    scopedAnimate(".box", { x: 200 }, { duration: 1 });
    scopedAnimate(".circle", { scale: 1.5 }, { duration: 0.8 });
  }
}

Minimal Animation Function

Ultra-lightweight animation function for simple WAAPI animations.

/**
 * Minimal WAAPI-based animation function
 * @param element - Element to animate
 * @param keyframes - Animation keyframes
 * @param options - WAAPI options
 * @returns Native Web Animation object
 */
function animateMini(
  element: string | Element,
  keyframes: Keyframe[] | PropertyIndexedKeyframes,
  options?: KeyframeAnimationOptions
): Animation;

/**
 * Sequence multiple animations with precise timing
 * @param animations - Array of animation definitions
 * @param options - Sequence options
 * @returns Promise resolving when sequence completes
 */
function animateSequence(
  animations: Array<[string | Element, Keyframe[] | PropertyIndexedKeyframes, KeyframeAnimationOptions?]>,
  options?: SequenceOptions
): Promise<void>;

interface SequenceOptions {
  /**
   * Default duration for animations without explicit duration
   */
  defaultDuration?: number;
  
  /**
   * Default easing for animations
   */
  defaultEasing?: string;
  
  /**
   * Delay between animations
   */
  stagger?: number;
}

Usage Examples:

import { animateMini, animateSequence } from "framer-motion/dom-mini";

// Minimal WAAPI animation
function minimalAnimation() {
  const element = document.querySelector(".element");
  if (element) {
    const animation = animateMini(element, [
      { transform: "translateX(0px) scale(1)" },
      { transform: "translateX(100px) scale(1.2)" },
      { transform: "translateX(0px) scale(1)" }
    ], {
      duration: 1000,
      easing: "ease-in-out",
      iterations: Infinity
    });
    
    // Native Web Animation methods
    animation.pause();
    animation.play();
    animation.addEventListener("finish", () => {
      console.log("Animation finished");
    });
  }
}

// Animation sequences
async function sequencedAnimations() {
  await animateSequence([
    [".header", [{ opacity: 0 }, { opacity: 1 }], { duration: 500 }],
    [".content", [{ y: 50 }, { y: 0 }], { duration: 600 }],
    [".footer", [{ scale: 0.8 }, { scale: 1 }], { duration: 400 }]
  ], {
    stagger: 100 // 100ms delay between each animation
  });
  
  console.log("Sequence completed");
}

Scroll Utilities

Direct DOM scroll tracking utilities that work without React.

/**
 * Track scroll with callback (already documented in scroll-view.md)
 */
function scroll(
  onScroll: (info: ScrollInfo) => void,
  options?: ScrollOptions
): () => void;

/**
 * Advanced scroll tracking with detailed information
 */
function scrollInfo(
  onScroll: (info: DetailedScrollInfo) => void,
  options?: ScrollOptions
): () => void;

interface ScrollInfo {
  x: number;
  y: number;
  xProgress: number;
  yProgress: number;
  velocity: number;
}

interface DetailedScrollInfo extends ScrollInfo {
  targetBounds: DOMRect;
  containerBounds: DOMRect;
  intersectionRatio: number;
}

Viewport Utilities

Direct DOM intersection observer utilities.

/**
 * Observe element intersection with viewport (already documented in scroll-view.md)
 */
function inView(
  element: string | Element,
  onStart: (entry: IntersectionObserverEntry) => void | (() => void),
  options?: InViewOptions
): () => void;

interface InViewOptions {
  root?: Element;
  margin?: string;
  amount?: number | number[] | "some" | "all";
}

Transform Utilities

Utilities for working with CSS transforms.

/**
 * Build CSS transform string from transform object
 * @param transform - Transform properties object
 * @param transformOrigin - Transform origin values
 * @returns CSS transform string
 */
function buildTransform(
  transform: Record<string, string | number>,
  transformOrigin?: string
): string;

/**
 * Parse transform string into object
 * @param transformString - CSS transform string
 * @returns Object with transform properties
 */
function parseTransform(transformString: string): Record<string, number>;

/**
 * Interpolate between transform states
 * @param from - Starting transform object
 * @param to - Ending transform object
 * @param progress - Interpolation progress (0-1)
 * @returns Interpolated transform object
 */
function interpolateTransforms(
  from: Record<string, number>,
  to: Record<string, number>,
  progress: number
): Record<string, number>;

Usage Examples:

import { buildTransform, parseTransform } from "framer-motion/dom";

// Build transform strings
function transformUtilities() {
  // Build transform from object
  const transformString = buildTransform({
    x: 100,
    y: 50,
    rotate: 45,
    scale: 1.2,
    skewX: 10
  }, "center center");
  
  console.log(transformString); 
  // "translateX(100px) translateY(50px) rotate(45deg) scale(1.2) skewX(10deg)"
  
  // Apply to element
  const element = document.querySelector(".element");
  if (element) {
    (element as HTMLElement).style.transform = transformString;
    (element as HTMLElement).style.transformOrigin = "center center";
  }
  
  // Parse existing transform
  const existing = (element as HTMLElement)?.style.transform || "";
  const parsed = parseTransform(existing);
  console.log(parsed); // { translateX: 100, translateY: 50, rotate: 45, ... }
}

Animation Utilities

Additional utilities for animation management.

/**
 * Delay execution by specified time
 * @param duration - Delay duration in seconds
 * @returns Promise that resolves after delay
 */
function delay(duration: number): Promise<void>;

/**
 * Create delayed function
 * @param fn - Function to delay
 * @param duration - Delay duration in seconds
 * @returns Delayed function
 */
function delay<T extends (...args: any[]) => any>(
  fn: T, 
  duration: number
): DelayedFunction<T>;

interface DelayedFunction<T extends (...args: any[]) => any> {
  (...args: Parameters<T>): Promise<ReturnType<T>>;
  cancel(): void;
}

/**
 * RAF-based animation loop
 * @param callback - Function to call each frame
 * @returns Cleanup function to stop the loop
 */
function animationLoop(callback: (time: number, delta: number) => void): () => void;

/**
 * Throttle function calls to animation frames
 * @param fn - Function to throttle
 * @returns Throttled function
 */
function throttleToAnimationFrame<T extends (...args: any[]) => any>(fn: T): T;

Usage Examples:

import { delay, animationLoop, throttleToAnimationFrame } from "framer-motion/dom";

// Delay utilities
async function delayExample() {
  console.log("Starting...");
  await delay(1); // Wait 1 second
  console.log("After 1 second");
  
  // Delayed function execution
  const delayedLog = delay(console.log, 0.5);
  delayedLog("This appears after 500ms");
  
  // Cancel delayed execution
  const cancelable = delay(() => console.log("This won't run"), 2);
  cancelable.cancel();
}

// Animation loop
function customAnimationLoop() {
  let rotation = 0;
  const element = document.querySelector(".rotating-element") as HTMLElement;
  
  const stopLoop = animationLoop((time, delta) => {
    rotation += delta * 0.1; // Rotate based on time delta
    if (element) {
      element.style.transform = `rotate(${rotation}deg)`;
    }
  });
  
  // Stop after 5 seconds
  setTimeout(stopLoop, 5000);
}

// Throttled event handling
function throttledScrollExample() {
  const handleScroll = throttleToAnimationFrame((event: Event) => {
    const scrollY = window.scrollY;
    const header = document.querySelector(".header") as HTMLElement;
    if (header) {
      header.style.transform = `translateY(${Math.min(0, -scrollY * 0.5)}px)`;
    }
  });
  
  window.addEventListener("scroll", handleScroll);
  
  // Cleanup
  return () => window.removeEventListener("scroll", handleScroll);
}

Integration Patterns

Combining with React:

import { animate } from "framer-motion/dom";
import { useEffect, useRef } from "react";

function HybridAnimation() {
  const ref = useRef<HTMLDivElement>(null);
  
  useEffect(() => {
    if (ref.current) {
      // Use DOM animate for complex sequences
      const controls = animate(ref.current, [
        { x: 0, y: 0 },
        { x: 100, y: 0 },
        { x: 100, y: 100 },
        { x: 0, y: 100 },
        { x: 0, y: 0 }
      ], {
        duration: 4,
        repeat: Infinity,
        ease: "linear"
      });
      
      return () => controls.stop();
    }
  }, []);
  
  return <div ref={ref} className="w-16 h-16 bg-blue-500" />;
}

Performance Optimization:

// Batch DOM animations
function batchAnimations() {
  const elements = document.querySelectorAll(".animate-me");
  
  // Start all animations simultaneously for better performance
  elements.forEach((element, index) => {
    animate(element, 
      { y: -100, opacity: [0, 1] },
      { 
        duration: 0.6,
        delay: index * 0.05, // Small stagger
        ease: "easeOut"
      }
    );
  });
}

// Memory-efficient cleanup
function animationWithCleanup() {
  const cleanupFunctions: (() => void)[] = [];
  
  // Store cleanup functions
  cleanupFunctions.push(
    scroll((info) => {
      // Handle scroll
    })
  );
  
  cleanupFunctions.push(
    inView(".target", (entry) => {
      // Handle intersection
    })
  );
  
  // Clean up all listeners
  return () => {
    cleanupFunctions.forEach(cleanup => cleanup());
  };
}

Progressive Enhancement:

// Feature detection and fallbacks
function progressiveAnimation() {
  const element = document.querySelector(".element") as HTMLElement;
  
  if ("animate" in document.createElement("div")) {
    // Use Web Animations API
    animate(element, { x: 100 }, { duration: 1 });
  } else {
    // Fallback to CSS transitions
    element.style.transition = "transform 1s ease";
    element.style.transform = "translateX(100px)";
  }
}

docs

animation-controls.md

configuration.md

dom-utilities.md

gestures.md

index.md

layout-presence.md

motion-components.md

motion-values.md

scroll-view.md

tile.json