К основному содержанию
скилл CX Codex

framer-motion-animator — скилл для Claude Code: обзор и установка

Скилл помогает создавать анимации и микроинтерфейсы на Framer Motion: от переходов между страницами до жестов свайпа и скролла. Пригодится при вёрстке интерактивных React-компонентов.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add patricio0312rev/skills --skill framer-motion-animator -a claude-code
Открыть на GitHub

Что делает framer-motion-animator

Скилл даёт готовые паттерны декларативных анимаций для React. Он раскладывает задачу на шесть шагов: выбор типа анимации, расчёт параметров движения, настройка физики пружин, каскадная задержка дочерних элементов и перенос нагрузки на GPU.

Внутри собраны типовые примеры кода: появление через FadeIn, скрытие модальных окон с помощью AnimatePresence, списки с эффектом staggerChildren и переключение вкладок через LayoutGroup с общим layoutId. Также описаны жесты перетаскивания и свайпа для удаления карточек, плюс анимации появления по скроллу через хук useInView.

Для работы в проекте обязательно нужен установленный пакет framer-motion. В Next.js App Router переходы между страницами предлагается настраивать через файл template.tsx.

Какие задачи решает

  • анимировать появление модального окна и оверлея через AnimatePresence
  • настроить каскадное появление списка с задержкой элементов
  • связать индикатор активной вкладки через layoutId в LayoutGroup
  • добавить жест смахивания для удаления карточки

Примеры запросов агенту

  • Добавь анимацию появления для модального окна через framer motion
  • Настрой переход между страницами в Next.js через template.tsx с framer-motion
  • Сделай перетаскивание карточки с ограничением по координатам

Как установить framer-motion-animator

1Через Skills CLI (Vercel)

npx skills add patricio0312rev/skills --skill framer-motion-animator -a claude-code

2Вручную: положить файлы

~/.claude/skills/framer-motion-animator/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/framer-motion-animator/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора26

eslint-prettier-config Скилл разворачивает ESLint и Prettier в проекте на TypeScript и React: конфиги, правила, скрипты и хук на коммит. CX Codex +1 1 100установок changelog-writer Собирает CHANGELOG и release notes из git-коммитов, заголовков PR и ссылок на issues. Пригодится перед релизом, когда нужно разложить изменения по типам и подобрать версию. CX Codex +1 615установок bruno-collection-generator Скилл сканирует роуты Express, Next.js или Fastify и раскладывает их в коллекцию Bruno: по файлу .bru на запрос, с окружениями и авторизацией. CX Codex +1 603установок jsdoc-typescript-docs Скилл расставляет JSDoc-комментарии в TypeScript-коде и собирает из них документацию через TypeDoc. Пригодится, когда проект оброс функциями без описаний. CX Codex +1 547установок dockerfile-optimizer Скилл переписывает Dockerfile под многоэтапную сборку: меньше образ, быстрее сборка, кэш слоёв работает как надо. Пригодится, когда образ раздулся или сборка идёт по десять минут. CX Codex +1 530установок animation-micro-interaction-pack Набор готовых паттернов движения для интерфейса: ховеры, входы и выходы элементов, отклик на жесты. Пригодится, когда UI выглядит статично и хочется оживить его без ручного подбора таймингов. CX Codex +1 499установок explaining-code Разбирает незнакомый код по шагам: аналогия из быта, ASCII-схема потока, потом построчный разбор. Пригодится, когда чужой проект надо понять быстро. CX Codex +1 473установок conventional-commits Скилл пишет коммиты по спецификации Conventional Commits: тип, область, тело и футеры. Пригодится, когда нужен автоматический версионинг и changelog. CX Codex +1 469установок

Похожие

framer-motion AThevon Подсказывает агенту правила работы с Framer Motion и Motion в React: анимации раскладки, жесты и хуки без лишних ререндеров. CX Codex +1 990установок framer-motion-react C-Jeril Скилл по Framer Motion для React и Next.js: AnimatePresence, layout-анимации, useAnimation и обход проблем с SSR. CX Codex +1 822установок motion-framer freshtechbro Помогает агенту добавлять анимации Motion и Framer Motion в React-интерфейсы: от эффектов наведения до переходов между состояниями. CX Codex +1 5 900установок framer-motion-scroll C-Jeril Скилл для Framer Motion: подсказывает агенту, как делать анимации, привязанные к прокрутке, параллакс и индикаторы прогресса. CX Codex +1 803установок motion-dev-animations Motion Dev Standards Генерирует GPU-анимации на Motion.dev для React, Next.js, Svelte и Astro. Помогает настроить физику пружин, скролл-эффекты и жесты с учётом prefers-reduced-motion. CX Codex +1 594установок motion secondsky Скилл по библиотеке Motion для React: подсказывает, как собрать drag-and-drop, scroll-анимации и переходы макета. Пригодится, когда агент путает пропсы или ломает exit-анимации. CX Codex +1 1 100установок

Рядом в теме «Фронтенд и UI»

Всё по теме «Фронтенд и UI» →

Вопросы о framer-motion-animator

Как установить framer-motion-animator в Claude Code?

Выполните команду npx skills add patricio0312rev/skills --skill framer-motion-animator -a claude-code в терминале. Также можно сохранить файл скилла по пути ~/.claude/skills/framer-motion-animator/SKILL.md.

Что делает скилл framer-motion-animator?

Он направляет агента при генерации анимаций на Framer Motion, включая жесты перетаскивания, переходы страниц, списки со staggerChildren и скролл-триггеры.

Что нужно установить в проекте для работы сгенерированного кода?

В зависимостях проекта должен быть установлен пакет Framer Motion с помощью команды npm install framer-motion.

Исходный текст

SKILL.md · MIT
---
name: framer-motion-animator
description: Creates smooth animations and micro-interactions using Framer Motion including page transitions, gestures, scroll-based animations, and orchestrated sequences. Use when users request "add animation", "framer motion", "page transition", "animate component", or "micro-interactions".
---

# Framer Motion Animator

Build delightful animations and interactions with Framer Motion's declarative API.

## Core Workflow

1. **Identify animation needs**: Entrance, exit, hover, gestures
2. **Choose animation type**: Simple, variants, gestures, layout
3. **Define motion values**: Opacity, scale, position, rotation
4. **Add transitions**: Duration, easing, spring physics
5. **Orchestrate sequences**: Stagger, delay, parent-child
6. **Optimize performance**: GPU-accelerated properties

## Installation

```bash
npm install framer-motion
```

## Basic Animations

### Simple Animation

```tsx
import { motion } from 'framer-motion';

// Animate on mount
export function FadeIn({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.5 }}
    >
      {children}
    </motion.div>
  );
}

// Animate on hover
export function ScaleOnHover({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      whileHover={{ scale: 1.05 }}
      whileTap={{ scale: 0.95 }}
      transition={{ type: 'spring', stiffness: 400, damping: 17 }}
    >
      {children}
    </motion.div>
  );
}
```

### Exit Animations with AnimatePresence

```tsx
import { motion, AnimatePresence } from 'framer-motion';

export function Modal({ isOpen, onClose, children }: ModalProps) {
  return (
    <AnimatePresence>
      {isOpen && (
        <>
          {/* Backdrop */}
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            onClick={onClose}
            className="fixed inset-0 bg-black/50 z-40"
          />

          {/* Modal */}
          <motion.div
            initial={{ opacity: 0, scale: 0.95, y: 20 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.95, y: 20 }}
            transition={{ type: 'spring', damping: 25, stiffness: 300 }}
            className="fixed inset-0 z-50 flex items-center justify-center"
          >
            <div className="bg-white rounded-xl p-6 max-w-md w-full">
              {children}
            </div>
          </motion.div>
        </>
      )}
    </AnimatePresence>
  );
}
```

## Variants Pattern

### Staggered Children

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

const itemVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { type: 'spring', stiffness: 300, damping: 24 },
  },
};

export function StaggeredList({ items }: { items: string[] }) {
  return (
    <motion.ul
      variants={containerVariants}
      initial="hidden"
      animate="visible"
    >
      {items.map((item, index) => (
        <motion.li key={index} variants={itemVariants}>
          {item}
        </motion.li>
      ))}
    </motion.ul>
  );
}
```

### Interactive Variants

```tsx
const buttonVariants = {
  initial: { scale: 1 },
  hover: { scale: 1.05 },
  tap: { scale: 0.95 },
  disabled: { opacity: 0.5, scale: 1 },
};

export function AnimatedButton({
  children,
  disabled,
  onClick,
}: ButtonProps) {
  return (
    <motion.button
      variants={buttonVariants}
      initial="initial"
      whileHover={disabled ? 'disabled' : 'hover'}
      whileTap={disabled ? 'disabled' : 'tap'}
      animate={disabled ? 'disabled' : 'initial'}
      onClick={onClick}
      disabled={disabled}
      className="px-4 py-2 bg-blue-500 text-white rounded-lg"
    >
      {children}
    </motion.button>
  );
}
```

## Page Transitions

### Next.js App Router

```tsx
// app/template.tsx
'use client';

import { motion } from 'framer-motion';

export default function Template({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: 20 }}
      transition={{ duration: 0.3 }}
    >
      {children}
    </motion.div>
  );
}
```

### Shared Layout Animations

```tsx
import { motion, LayoutGroup } from 'framer-motion';

export function Tabs({ tabs, activeTab, onTabChange }: TabsProps) {
  return (
    <LayoutGroup>
      <div className="flex gap-2">
        {tabs.map((tab) => (
          <button
            key={tab.id}
            onClick={() => onTabChange(tab.id)}
            className="relative px-4 py-2"
          >
            {activeTab === tab.id && (
              <motion.div
                layoutId="activeTab"
                className="absolute inset-0 bg-blue-500 rounded-lg"
                transition={{ type: 'spring', stiffness: 500, damping: 30 }}
              />
            )}
            <span className="relative z-10">{tab.label}</span>
          </button>
        ))}
      </div>
    </LayoutGroup>
  );
}
```

## Gesture Animations

### Drag

```tsx
export function DraggableCard() {
  return (
    <motion.div
      drag
      dragConstraints={{ left: -100, right: 100, top: -100, bottom: 100 }}
      dragElastic={0.2}
      dragTransition={{ bounceStiffness: 600, bounceDamping: 20 }}
      whileDrag={{ scale: 1.1, cursor: 'grabbing' }}
      className="w-32 h-32 bg-blue-500 rounded-lg cursor-grab"
    />
  );
}
```

### Swipe to Dismiss

```tsx
export function SwipeToDelete({ onDelete, children }: SwipeProps) {
  return (
    <motion.div
      drag="x"
      dragConstraints={{ left: 0, right: 0 }}
      onDragEnd={(_, info) => {
        if (info.offset.x < -100) {
          onDelete();
        }
      }}
      className="relative"
    >
      {children}
      <motion.div
        className="absolute right-0 inset-y-0 bg-red-500 flex items-center px-4"
        style={{ opacity: 0 }}
        animate={{ opacity: 1 }}
      >
        Delete
      </motion.div>
    </motion.div>
  );
}
```

## Scroll Animations

### Scroll-Triggered

```tsx
import { motion, useInView } from 'framer-motion';
import { useRef } from 'react';

export function FadeInWhenVisible({ children }: { children: React.ReactNode }) {
  const ref = useRef(null);
  const isInView = useInView(ref, { once: true, margin: '-100px' });

  return (
    <motion.div
      ref={ref}
      initial={{ opacity: 0, y: 50 }}
      animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 50 }}
      transition={{ duration: 0.6, ease: 'easeOut' }}
    >
      {children}
    </motion.div>
  );
}
```

### Scroll Progress

```tsx
import { motion, useScroll, useTransform } from 'framer-motion';

export function ParallaxHero() {
  const { scrollY } = useScroll();
  const y = useTransform(scrollY, [0, 500], [0, 150]);
  const opacity = useTransform(scrollY, [0, 300], [1, 0]);

  return (
    <motion.div
      style={{ y, opacity }}
      className="h-screen flex items-center justify-center"
    >
      <h1 className="text-6xl font-bold">Parallax Hero</h1>
    </motion.div>
  );
}

export function ScrollProgress() {
  const { scrollYProgress } = useScroll();

  return (
    <motion.div
      style={{ scaleX: scrollYProgress }}
      className="fixed top-0 left-0 right-0 h-1 bg-blue-500 origin-left z-50"
    />
  );
}
```

## Animation Hooks

### useAnimate (Imperative)

```tsx
import { useAnimate } from 'framer-motion';

export function SubmitButton() {
  const [scope, animate] = useAnimate();

  const handleClick = async () => {
    // Sequence of animations
    await animate(scope.current, { scale: 0.95 }, { duration: 0.1 });
    await animate(scope.current, { scale: 1 }, { type: 'spring' });

    // Success animation
    await animate(
      scope.current,
      { backgroundColor: '#22c55e' },
      { duration: 0.2 }
    );
  };

  return (
    <motion.button ref={scope} onClick={handleClick} className="px-4 py-2">
      Submit
    </motion.button>
  );
}
```

### useMotionValue & useTransform

```tsx
import { motion, useMotionValue, useTransform } from 'framer-motion';

export function RotatingCard() {
  const x = useMotionValue(0);
  const rotateY = useTransform(x, [-200, 200], [-45, 45]);
  const opacity = useTransform(x, [-200, 0, 200], [0.5, 1, 0.5]);

  return (
    <motion.div
      drag="x"
      dragConstraints={{ left: -200, right: 200 }}
      style={{ x, rotateY, opacity }}
      className="w-64 h-96 bg-gradient-to-br from-purple-500 to-pink-500 rounded-xl"
    />
  );
}
```

## Reusable Animation Components

### AnimatedContainer

```tsx
// components/AnimatedContainer.tsx
import { motion, Variants } from 'framer-motion';

const animations: Record<string, Variants> = {
  fadeIn: {
    hidden: { opacity: 0 },
    visible: { opacity: 1 },
  },
  fadeInUp: {
    hidden: { opacity: 0, y: 20 },
    visible: { opacity: 1, y: 0 },
  },
  fadeInDown: {
    hidden: { opacity: 0, y: -20 },
    visible: { opacity: 1, y: 0 },
  },
  scaleIn: {
    hidden: { opacity: 0, scale: 0.8 },
    visible: { opacity: 1, scale: 1 },
  },
  slideInLeft: {
    hidden: { opacity: 0, x: -50 },
    visible: { opacity: 1, x: 0 },
  },
  slideInRight: {
    hidden: { opacity: 0, x: 50 },
    visible: { opacity: 1, x: 0 },
  },
};

interface AnimatedContainerProps {
  children: React.ReactNode;
  animation?: keyof typeof animations;
  delay?: number;
  duration?: number;
  className?: string;
}

export function AnimatedContainer({
  children,
  animation = 'fadeInUp',
  delay = 0,
  duration = 0.5,
  className,
}: AnimatedContainerProps) {
  return (
    <motion.div
      variants={animations[animation]}
      initial="hidden"
      animate="visible"
      transition={{ duration, delay, ease: 'easeOut' }}
      className={className}
    >
      {children}
    </motion.div>
  );
}
```

### AnimatedList

```tsx
// components/AnimatedList.tsx
import { motion } from 'framer-motion';

const containerVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.05,
    },
  },
};

const itemVariants = {
  hidden: { opacity: 0, x: -20 },
  visible: { opacity: 1, x: 0 },
};

interface AnimatedListProps<T> {
  items: T[];
  renderItem: (item: T, index: number) => React.ReactNode;
  keyExtractor: (item: T, index: number) => string;
  className?: string;
}

export function AnimatedList<T>({
  items,
  renderItem,
  keyExtractor,
  className,
}: AnimatedListProps<T>) {
  return (
    <motion.ul
      variants={containerVariants}
      initial="hidden"
      animate="visible"
      className={className}
    >
      {items.map((item, index) => (
        <motion.li key={keyExtractor(item, index)} variants={itemVariants}>
          {renderItem(item, index)}
        </motion.li>
      ))}
    </motion.ul>
  );
}
```

## Transition Presets

```tsx
// lib/transitions.ts
export const transitions = {
  spring: {
    type: 'spring',
    stiffness: 300,
    damping: 24,
  },
  springBouncy: {
    type: 'spring',
    stiffness: 500,
    damping: 15,
  },
  springStiff: {
    type: 'spring',
    stiffness: 700,
    damping: 30,
  },
  smooth: {
    type: 'tween',
    duration: 0.3,
    ease: 'easeInOut',
  },
  snappy: {
    type: 'tween',
    duration: 0.15,
    ease: [0.25, 0.1, 0.25, 1],
  },
} as const;

// Usage
<motion.div transition={transitions.spring} />
```

## Reduced Motion Support

```tsx
import { useReducedMotion } from 'framer-motion';

export function AccessibleAnimation({ children }: { children: React.ReactNode }) {
  const shouldReduceMotion = useReducedMotion();

  return (
    <motion.div
      initial={{ opacity: 0, y: shouldReduceMotion ? 0 : 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: shouldReduceMotion ? 0 : 0.5 }}
    >
      {children}
    </motion.div>
  );
}
```

## Best Practices

1. **Use GPU-accelerated properties**: `opacity`, `transform` (not `width`, `height`)
2. **Add `layout` for smooth resizing**: Automatic layout animations
3. **Use `AnimatePresence`**: For exit animations
4. **Prefer springs**: More natural than tween for UI
5. **Respect reduced motion**: Use `useReducedMotion` hook
6. **Avoid animating layout thrashing**: Don't animate `top`, `left`, `width`
7. **Use `layoutId`**: For shared element transitions
8. **Stagger children**: For list animations

## Output Checklist

Every animation implementation should include:

- [ ] Appropriate animation type (simple, variants, gestures)
- [ ] Smooth transitions with proper easing
- [ ] Exit animations with AnimatePresence
- [ ] Reduced motion support
- [ ] GPU-accelerated properties only
- [ ] Spring physics for natural feel
- [ ] Staggered children for lists
- [ ] Performance tested on low-end devices

© patricio0312rev · MIT · patricio0312rev/skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой