Claude
Skills
Sign in
Back

svg-animations

Included with Lifetime
$97 forever

Expert knowledge for SVG path animations, morphing shapes, and vector graphics effects that create stunning visual experiences with resolution-independent graphics.

AI Agents

What this skill does


# SVG Animations Skill

Expert knowledge for SVG path animations, morphing shapes, and vector graphics effects that create stunning visual experiences with resolution-independent graphics.

## When to Use

Activate this skill when:
- User wants to animate SVG icons or illustrations
- Need path drawing/tracing animations
- Building morphing shape transitions
- Creating animated logos or icons
- Working with SVG line art animations
- Building data visualization animations

## File Patterns

- `**/*.svg` files
- `**/*.tsx` containing SVG elements
- `**/icons/*.tsx` with animated icons
- `**/components/**/Animated*.tsx` with SVG
- Files with `pathLength`, `stroke-dasharray`

## Core Techniques

### Path Drawing Animation (Framer Motion)
```typescript
import { motion } from 'framer-motion';

function DrawPath() {
  return (
    <svg viewBox="0 0 100 100" className="w-24 h-24">
      <motion.path
        d="M10 50 Q 50 10, 90 50 T 90 90"
        fill="transparent"
        stroke="#3B82F6"
        strokeWidth="4"
        initial={{ pathLength: 0 }}
        animate={{ pathLength: 1 }}
        transition={{ duration: 2, ease: 'easeInOut' }}
      />
    </svg>
  );
}
```

### Path Drawing with CSS
```css
.svg-path {
  stroke-dasharray: 1000; /* Total path length */
  stroke-dashoffset: 1000; /* Start hidden */
  animation: draw 2s ease-in-out forwards;
}

@keyframes draw {
  to {
    stroke-dashoffset: 0;
  }
}
```

### Calculate Path Length
```typescript
// Get actual path length for accurate animation
useEffect(() => {
  const path = document.querySelector('.animated-path') as SVGPathElement;
  if (path) {
    const length = path.getTotalLength();
    console.log('Path length:', length);
  }
}, []);
```

## Animated Icon Components

### Checkmark Animation
```typescript
import { motion } from 'framer-motion';

function AnimatedCheck({ isVisible }: { isVisible: boolean }) {
  return (
    <svg viewBox="0 0 24 24" className="w-6 h-6">
      {/* Circle background */}
      <motion.circle
        cx="12"
        cy="12"
        r="10"
        fill="#22C55E"
        initial={{ scale: 0 }}
        animate={{ scale: isVisible ? 1 : 0 }}
        transition={{ type: 'spring', stiffness: 300, damping: 20 }}
      />

      {/* Checkmark path */}
      <motion.path
        d="M6 12l4 4 8-8"
        fill="transparent"
        stroke="white"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
        initial={{ pathLength: 0 }}
        animate={{ pathLength: isVisible ? 1 : 0 }}
        transition={{ delay: 0.2, duration: 0.3, ease: 'easeOut' }}
      />
    </svg>
  );
}
```

### Hamburger to X Animation
```typescript
import { motion } from 'framer-motion';

function MenuIcon({ isOpen }: { isOpen: boolean }) {
  const variant = isOpen ? 'open' : 'closed';

  const topLineVariants = {
    closed: { rotate: 0, y: 0 },
    open: { rotate: 45, y: 8 },
  };

  const middleLineVariants = {
    closed: { opacity: 1 },
    open: { opacity: 0 },
  };

  const bottomLineVariants = {
    closed: { rotate: 0, y: 0 },
    open: { rotate: -45, y: -8 },
  };

  return (
    <svg viewBox="0 0 24 24" className="w-6 h-6">
      <motion.line
        x1="4" y1="6" x2="20" y2="6"
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        variants={topLineVariants}
        animate={variant}
        transition={{ duration: 0.3 }}
        style={{ transformOrigin: 'center' }}
      />
      <motion.line
        x1="4" y1="12" x2="20" y2="12"
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        variants={middleLineVariants}
        animate={variant}
        transition={{ duration: 0.2 }}
      />
      <motion.line
        x1="4" y1="18" x2="20" y2="18"
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        variants={bottomLineVariants}
        animate={variant}
        transition={{ duration: 0.3 }}
        style={{ transformOrigin: 'center' }}
      />
    </svg>
  );
}
```

### Loading Spinner
```typescript
import { motion } from 'framer-motion';

function Spinner() {
  return (
    <svg viewBox="0 0 50 50" className="w-12 h-12">
      {/* Background circle */}
      <circle
        cx="25"
        cy="25"
        r="20"
        fill="none"
        stroke="#E5E7EB"
        strokeWidth="4"
      />

      {/* Animated arc */}
      <motion.circle
        cx="25"
        cy="25"
        r="20"
        fill="none"
        stroke="#3B82F6"
        strokeWidth="4"
        strokeLinecap="round"
        initial={{ pathLength: 0, rotate: 0 }}
        animate={{
          pathLength: [0, 0.5, 0],
          rotate: 360,
        }}
        transition={{
          pathLength: {
            duration: 1.5,
            repeat: Infinity,
            ease: 'easeInOut',
          },
          rotate: {
            duration: 1.5,
            repeat: Infinity,
            ease: 'linear',
          },
        }}
        style={{ transformOrigin: 'center' }}
      />
    </svg>
  );
}
```

## Shape Morphing

### Framer Motion Morphing
```typescript
import { motion, useAnimation } from 'framer-motion';

const shapes = {
  circle: 'M50,10 A40,40 0 1,1 50,90 A40,40 0 1,1 50,10',
  square: 'M10,10 L90,10 L90,90 L10,90 Z',
  triangle: 'M50,10 L90,90 L10,90 Z',
};

function MorphingShape() {
  const [currentShape, setCurrentShape] = useState<keyof typeof shapes>('circle');

  return (
    <svg viewBox="0 0 100 100" className="w-32 h-32">
      <motion.path
        fill="#3B82F6"
        animate={{ d: shapes[currentShape] }}
        transition={{ duration: 0.5, ease: 'easeInOut' }}
      />
    </svg>
  );
}
```

### GSAP MorphSVG
```typescript
import gsap from 'gsap';
import { MorphSVGPlugin } from 'gsap/MorphSVGPlugin';

gsap.registerPlugin(MorphSVGPlugin);

function GSAPMorph() {
  useEffect(() => {
    gsap.to('#shape', {
      duration: 1,
      morphSVG: '#targetShape',
      ease: 'power2.inOut',
    });
  }, []);

  return (
    <svg>
      <path id="shape" d="M10,10 L90,10 L90,90 L10,90 Z" />
      <path id="targetShape" d="M50,10 A40,40 0 1,1 50,90 A40,40 0 1,1 50,10" style={{ visibility: 'hidden' }} />
    </svg>
  );
}
```

## Complex SVG Animations

### Animated Logo
```typescript
function AnimatedLogo() {
  const controls = useAnimation();

  const logoVariants = {
    hidden: { opacity: 0 },
    visible: {
      opacity: 1,
      transition: {
        staggerChildren: 0.1,
        delayChildren: 0.2,
      },
    },
  };

  const pathVariants = {
    hidden: { pathLength: 0, opacity: 0 },
    visible: {
      pathLength: 1,
      opacity: 1,
      transition: { duration: 1, ease: 'easeInOut' },
    },
  };

  const fillVariants = {
    hidden: { fillOpacity: 0 },
    visible: {
      fillOpacity: 1,
      transition: { delay: 0.5, duration: 0.5 },
    },
  };

  return (
    <motion.svg
      viewBox="0 0 200 60"
      className="w-48"
      variants={logoVariants}
      initial="hidden"
      animate="visible"
    >
      {/* Letter outlines */}
      <motion.path
        d="M10,50 L10,10 L40,10 L40,30 L20,30 L20,50"
        fill="none"
        stroke="#3B82F6"
        strokeWidth="2"
        variants={pathVariants}
      />
      {/* Fill after stroke */}
      <motion.path
        d="M10,50 L10,10 L40,10 L40,30 L20,30 L20,50"
        fill="#3B82F6"
        variants={fillVariants}
      />
    </motion.svg>
  );
}
```

### Data Visualization Animation
```typescript
function AnimatedBarChart({ data }: { data: number[] }) {
  const maxValue = Math.max(...data);

  return (
    <svg viewBox="0 0 300 200" className="w-full h-48">
      {data.map((value, index) => {
        const barHeight = (value / maxValue) * 160;
        const barWidth = 40;
        const gap = 20;
        const x = index * (barWidth + gap) + 20;
        const y = 180 - barHeight;

        return (
          <motion.rect
            key={index}
            x={x}
            y={180}
            

Related in AI Agents