Claude Code for Anime.js: Lightweight JavaScript Animation Engine — Claude Skills 360 Blog
Blog / Frontend / Claude Code for Anime.js: Lightweight JavaScript Animation Engine
Frontend

Claude Code for Anime.js: Lightweight JavaScript Animation Engine

Published: May 6, 2027
Read time: 6 min read
By: Claude Skills 360

Anime.js is a lightweight JavaScript animation engine — anime({ targets: ".box", translateX: 250, duration: 1000, easing: "easeInOutQuad" }) animates CSS transforms on DOM elements. anime.timeline({ easing: "easeOutExpo" }) sequences animations with .add({ targets, ... }, offset). delay: anime.stagger(100) staggers animations across multiple targets. loop: true and direction: "alternate" create ping-pong loops. SVG path drawing uses strokeDashoffset with the element’s path length. anime.set(targets, { scale: 0 }) applies instant transforms. animation.seek(timeMs) scrubs to a point. onUpdate: (anim) => console.log(anim.progress) tracks percentage. anime.get(el, "translateX") reads current animated values. Anime.js targets CSS classes, id strings, DOM nodes, and JavaScript objects for number interpolation. Claude Code generates Anime.js scroll-triggered counters, SVG logo reveals, page transition sequences, staggered card entrances, and data value animations.

CLAUDE.md for Anime.js

## Anime.js Stack
- Version: animejs >= 3.2 (@types/animejs for TS)
- Basic: anime({ targets: ref.current, translateY: [-20, 0], opacity: [0, 1], duration: 600, easing: "easeOutQuart" })
- Timeline: const tl = anime.timeline({ easing: "easeOutExpo", duration: 500 }); tl.add({ targets, properties }).add({ targets }, "+=100")
- Stagger: delay: anime.stagger(80, { start: 200, from: "center" })
- Cleanup: const anim = anime(...); return () => anim.pause()
- SVG path: const path = el.getTotalLength(); anime({ targets: el, strokeDashoffset: [path, 0] })
- Object: anime({ targets: counter, count: [0, value], round: 1, update: () => setDisplay(Math.round(counter.count)) })

React Hooks

// hooks/useAnime.ts — Anime.js with React refs and cleanup
import { useEffect, useRef, useCallback } from "react"
import anime, { type AnimeParams, type AnimeInstance } from "animejs"

// One-shot animation on mount
export function useAnimeOnMount(params: Omit<AnimeParams, "targets">) {
  const ref = useRef<HTMLElement>(null)
  const instanceRef = useRef<AnimeInstance | null>(null)

  useEffect(() => {
    if (!ref.current) return

    instanceRef.current = anime({
      targets: ref.current,
      ...params,
    })

    return () => {
      instanceRef.current?.pause()
      instanceRef.current = null
    }
  }, [])  // eslint-disable-line react-hooks/exhaustive-deps

  return ref
}

// Imperative animation trigger
export function useAnime<T extends HTMLElement = HTMLElement>(
  params: Omit<AnimeParams, "targets">,
) {
  const ref = useRef<T>(null)
  const instanceRef = useRef<AnimeInstance | null>(null)

  const play = useCallback(() => {
    instanceRef.current?.pause()
    if (!ref.current) return
    instanceRef.current = anime({
      targets: ref.current,
      ...params,
    })
  }, [params])

  const pause = useCallback(() => instanceRef.current?.pause(), [])
  const reverse = useCallback(() => instanceRef.current?.reverse(), [])
  const seek = useCallback((ms: number) => instanceRef.current?.seek(ms), [])

  useEffect(() => () => { instanceRef.current?.pause() }, [])

  return { ref, play, pause, reverse, seek }
}

// Staggered list animation
export function useAnimeStagger(
  containerRef: React.RefObject<HTMLElement>,
  selector: string,
  params: Omit<AnimeParams, "targets">,
) {
  const instanceRef = useRef<AnimeInstance | null>(null)

  const animate = useCallback((from: typeof params["from"]) => {
    if (!containerRef.current) return
    const els = containerRef.current.querySelectorAll(selector)
    if (!els.length) return

    instanceRef.current?.pause()
    instanceRef.current = anime({
      targets: els,
      ...params,
      delay: anime.stagger(60, { from }),
    })
  }, [containerRef, selector, params])

  useEffect(() => () => { instanceRef.current?.pause() }, [])

  return animate
}

Timeline Page Transition

// components/animation/PageReveal.tsx — coordinated page entrance
"use client"
import { useEffect, useRef } from "react"
import anime from "animejs"

interface PageRevealProps {
  children: React.ReactNode
  className?: string
}

export function PageReveal({ children, className }: PageRevealProps) {
  const containerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const container = containerRef.current
    if (!container) return

    // Reset initial states
    anime.set(container.querySelectorAll("[data-reveal='heading']"), {
      opacity: 0, translateY: 40,
    })
    anime.set(container.querySelectorAll("[data-reveal='subheading']"), {
      opacity: 0, translateY: 30,
    })
    anime.set(container.querySelectorAll("[data-reveal='item']"), {
      opacity: 0, translateY: 20, scale: 0.97,
    })
    anime.set(container.querySelectorAll("[data-reveal='fade']"), {
      opacity: 0,
    })

    const tl = anime.timeline({
      easing: "easeOutQuart",
    })

    tl.add({
      targets: container.querySelectorAll("[data-reveal='heading']"),
      opacity: [0, 1],
      translateY: [40, 0],
      duration: 700,
    })
    .add({
      targets: container.querySelectorAll("[data-reveal='subheading']"),
      opacity: [0, 1],
      translateY: [30, 0],
      duration: 600,
    }, "-=400")
    .add({
      targets: container.querySelectorAll("[data-reveal='item']"),
      opacity: [0, 1],
      translateY: [20, 0],
      scale: [0.97, 1],
      duration: 500,
      delay: anime.stagger(80),
    }, "-=300")
    .add({
      targets: container.querySelectorAll("[data-reveal='fade']"),
      opacity: [0, 1],
      duration: 400,
    }, "-=200")

    return () => tl.pause()
  }, [])

  return (
    <div ref={containerRef} className={className}>
      {children}
    </div>
  )
}

// Usage:
// <PageReveal>
//   <h1 data-reveal="heading">Welcome</h1>
//   <p data-reveal="subheading">Subtitle</p>
//   <Card data-reveal="item" />
//   <Card data-reveal="item" />
//   <Footer data-reveal="fade" />
// </PageReveal>

SVG Path Drawing

// components/animation/SvgReveal.tsx — SVG stroke drawing animation
"use client"
import { useEffect, useRef } from "react"
import anime from "animejs"

interface SvgRevealProps {
  paths: string[]    // SVG d attributes
  viewBox?: string
  strokeColor?: string
  strokeWidth?: number
  duration?: number
  className?: string
}

export function SvgReveal({
  paths,
  viewBox = "0 0 100 100",
  strokeColor = "#3B82F6",
  strokeWidth = 2,
  duration = 1500,
  className,
}: SvgRevealProps) {
  const svgRef = useRef<SVGSVGElement>(null)

  useEffect(() => {
    const svg = svgRef.current
    if (!svg) return

    const pathEls = svg.querySelectorAll("path")
    const anims: ReturnType<typeof anime>[] = []

    pathEls.forEach((path, i) => {
      const length = path.getTotalLength()
      anime.set(path, {
        strokeDasharray: length,
        strokeDashoffset: length,
        opacity: 1,
      })

      anims.push(
        anime({
          targets: path,
          strokeDashoffset: [length, 0],
          easing: "easeInOutSine",
          duration,
          delay: i * 200,
        }),
      )
    })

    return () => anims.forEach(a => a.pause())
  }, [duration])

  return (
    <svg ref={svgRef} viewBox={viewBox} className={className} fill="none">
      {paths.map((d, i) => (
        <path
          key={i}
          d={d}
          stroke={strokeColor}
          strokeWidth={strokeWidth}
          strokeLinecap="round"
          strokeLinejoin="round"
          opacity={0}
        />
      ))}
    </svg>
  )
}

Animated Counter

// components/animation/AnimatedCounter.tsx — number count-up
"use client"
import { useEffect, useRef } from "react"
import anime from "animejs"

interface AnimatedCounterProps {
  value: number
  prefix?: string
  suffix?: string
  duration?: number
  easing?: string
  className?: string
}

export function AnimatedCounter({
  value,
  prefix = "",
  suffix = "",
  duration = 1500,
  easing = "easeOutExpo",
  className,
}: AnimatedCounterProps) {
  const displayRef = useRef<HTMLSpanElement>(null)
  const counterRef = useRef({ count: 0 })

  useEffect(() => {
    const el = displayRef.current
    if (!el) return

    const anim = anime({
      targets: counterRef.current,
      count: [0, value],
      duration,
      easing,
      round: 1,
      update: () => {
        el.textContent = prefix + Math.round(counterRef.current.count).toLocaleString() + suffix
      },
    })

    return () => anim.pause()
  }, [value, duration, easing, prefix, suffix])

  return (
    <span ref={displayRef} className={className}>
      {prefix}0{suffix}
    </span>
  )
}

For the GSAP alternative when professional-grade animation with ScrollTrigger, timeline scrubbing, morphing, DrawSVG plugin, and production reliability for complex marketing sites is needed — GSAP has better browser compatibility, more plugins, and smoother performance than Anime.js for advanced use cases, although it requires a commercial license for some plugins, see the GSAP guide. For the react-spring alternative when physics-based spring animations that respond to user gestures and feel natural without specifying explicit duration are preferred — react-spring’s spring physics produces different motion character than Anime.js’s easing curves, see the react-spring guide. The Claude Skills 360 bundle includes Anime.js skill sets covering timelines, stagger, and SVG animations. Start with the free tier to try JavaScript animation generation.

Keep Reading

Frontend

Claude Code for Chart.js Advanced: Custom Plugins and Mixed Charts

Advanced Chart.js patterns with Claude Code — chart.register() for tree-shaking, mixed chart types combining bar and line, custom plugin API with beforeDraw and afterDatasetsDraw hooks, ScriptableContext for computed colors, ChartDataLabels plugin for value labels, chartjs-plugin-zoom for pan and zoom, custom gradient fills via ctx.createLinearGradient, ChartJS annotation plugin for threshold lines, streaming data with chartjs-plugin-streaming, and react-chartjs-2 with useRef and chart instance.

6 min read Jun 27, 2027
Frontend

Claude Code for Nivo: Rich SVG and Canvas Charts

Build rich data visualizations with Nivo and Claude Code — ResponsiveLine and ResponsiveBar for adaptive charts, ResponsiveHeatMap for matrix data, ResponsiveTreeMap for hierarchal data, ResponsiveSunburst for nested proportions, ResponsiveChord for relationship diagrams, ResponsiveCalendar for activity heat maps, ResponsiveNetwork for force graphs, NivoTheme for consistent styling, tooltip customization with sliceTooltip, and motion config for spring animations.

6 min read Jun 26, 2027
Frontend

Claude Code for Victory Charts: React Native and Web Charts

Build cross-platform charts with Victory and Claude Code — VictoryChart, VictoryLine, VictoryBar, and VictoryScatter for web and React Native, VictoryPie for donut charts, VictoryArea for stacked areas, VictoryAxis for custom axes, VictoryTooltip and VictoryVoronoiContainer for hover tooltips, VictoryBrushContainer for range selection, VictoryZoomContainer for pan and zoom, VictoryLegend for series labels, custom theme with VictoryTheme, and VictoryStack for grouped bars.

6 min read Jun 25, 2027

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free