Synthèse automatique
Cette skill guide l'implémentation d'animations React avec Framer Motion : révélations au scroll, entrées/sorties, listes décalées (stagger) et respect de prefers-reduced-motion via useReducedMotion.
Points forts
- Fournit des variantes prêtes à l'emploi (fadeInUp, staggerContainer, staggerItem, heroEntrance) avec courbes d'accélération cohérentes
- Intègre systématiquement useReducedMotion pour l'accessibilité dans chaque exemple
- Couvre trois cas d'usage concrets : scroll (whileInView + viewport once), listes décalées et animations d'entrée sans déclencheur de scroll
- Donne des chemins de fichiers explicites pour centraliser les variantes partagées
Limites
- Le document est tronqué : la section « 4. Index-Based » est incomplète et les animations de sortie annoncées ne sont pas illustrées
- Les chemins cités (apps/web/src/app/about/_components/variants.ts) sont spécifiques à un projet et devront être adaptés
- Le titre mentionne le paquet motion v12+ alors que tous les imports utilisent framer-motion, ce qui peut prêter à confusion
À utiliser lorsqu'il faut ajouter ou harmoniser des animations d'entrée et de révélation au scroll dans une application React/Next.js existante.
À éviter pour des animations purement CSS légères, des transitions de route complexes ou des projets hors React qui ne peuvent pas utiliser Framer Motion.
Analyse de sécurité
SûrThe skill only provides Framer Motion animation guidance and code examples. It does not instruct destructive actions, network access, credential handling, obfuscation, or safety bypasses. The declared tools are file-editing/search tools used for legitimate code changes.
Aucun point d'attention détecté
Comment cette analyse est faiteExemples
Add a scroll-triggered fade-in-up animation to the testimonials section using our shared fadeInUpVariants, with viewport once and reduced-motion support.Animate this feature grid so the cards stagger in on scroll, reusing staggerContainerVariants and staggerItemVariants.Replace the Intersection Observer reveal logic in this component with Framer Motion whileInView, keeping the same timing and respecting prefers-reduced-motion.name: framer-motion-animations description: Create scroll-triggered and entrance animations using Framer Motion (motion package). Use when adding animations, implementing scroll reveals, or migrating from CSS/Intersection Observer. allowed-tools: Read, Edit, Write, Grep, Glob
Framer Motion Animations Skill
This skill helps you implement consistent, accessible animations across the codebase using Framer Motion (motion package v12+).
When to Use This Skill
- Adding scroll-triggered reveal animations
- Implementing entrance/exit animations
- Creating staggered list animations
- Migrating from CSS/Intersection Observer to Motion
- Ensuring accessibility with reduced motion support
Key Files
| File | Purpose |
|------|---------|
| apps/web/src/app/about/_components/variants.ts | Shared animation variants |
| apps/web/src/components/animated-number.tsx | Number animation component |
Animation Variants
Standard Variants (in variants.ts)
import type { Variants } from "framer-motion";
// Base fade-in-up animation for section content
export const fadeInUpVariants: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] },
},
};
// Container variant for staggered children
export const staggerContainerVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.1, delayChildren: 0.1 },
},
};
// Individual stagger item
export const staggerItemVariants: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.5, ease: [0.4, 0, 0.2, 1] },
},
};
// Hero entrance animation (faster, more dramatic)
export const heroEntranceVariants: Variants = {
hidden: { opacity: 0, y: 24, scale: 0.98 },
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: { duration: 0.8, ease: [0.16, 1, 0.3, 1] },
},
};
Usage Patterns
1. Scroll-Triggered Animation (Single Element)
import { motion, useReducedMotion } from "framer-motion";
import { fadeInUpVariants } from "./variants";
export const Section = () => {
const shouldReduceMotion = useReducedMotion();
return (
<motion.div
variants={shouldReduceMotion ? undefined : fadeInUpVariants}
initial={shouldReduceMotion ? undefined : "hidden"}
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
>
{/* Content */}
</motion.div>
);
};
2. Staggered List Animation
import { motion, useReducedMotion } from "framer-motion";
import { staggerContainerVariants, staggerItemVariants } from "./variants";
export const FeatureGrid = () => {
const shouldReduceMotion = useReducedMotion();
return (
<motion.div
className="grid grid-cols-2 gap-6"
variants={shouldReduceMotion ? undefined : staggerContainerVariants}
initial={shouldReduceMotion ? undefined : "hidden"}
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
>
{features.map((feature) => (
<motion.div
key={feature.id}
variants={shouldReduceMotion ? undefined : staggerItemVariants}
>
{/* Feature card */}
</motion.div>
))}
</motion.div>
);
};
3. Entrance Animation (No Scroll Trigger)
import { motion, useReducedMotion } from "framer-motion";
export const HeroSection = () => {
const shouldReduceMotion = useReducedMotion();
// Custom entrance transition with delay
const entranceTransition = (delay: number) =>
shouldReduceMotion
? undefined
: { duration: 1, delay, ease: [0.16, 1, 0.3, 1] as const };
return (
<motion.h1
initial={shouldReduceMotion ? undefined : { opacity: 0, y: 32 }}
animate={{ opacity: 1, y: 0 }}
transition={entranceTransition(0.15)}
>
Headline
</motion.h1>
);
};
4. Index-Based Stagger (Manual Delays)
import { motion, useReducedMotion } from "framer-motion";
interface TimelineItemProps {
index: number;
}
const TimelineItem = ({ index }: TimelineItemProps) => {
const shouldReduceMotion = useReducedMotion();
return (
<motion.div
initial={shouldReduceMotion ? undefined : { opacity: 0, y: 32 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={
shouldReduceMotion
? undefined
: { duration: 0.5, delay: index * 0.15, ease: [0.4, 0, 0.2, 1] }
}
>
{/* Content */}
</motion.div>
);
};
5. Number Animation with Viewport Trigger
import { motion, useReducedMotion } from "framer-motion";
import { AnimatedNumber } from "@web/components/animated-number";
import { useState } from "react";
import { staggerItemVariants } from "./variants";
const StatItem = ({ value }: { value: number }) => {
const shouldReduceMotion = useReducedMotion();
const [isInView, setIsInView] = useState(false);
return (
<motion.div
variants={shouldReduceMotion ? undefined : staggerItemVariants}
onViewportEnter={() => setIsInView(true)}
viewport={{ once: true }}
>
{isInView ? <AnimatedNumber value={value} /> : <span>0</span>}
</motion.div>
);
};
Accessibility
Always use useReducedMotion() to respect user preferences:
import { useReducedMotion } from "framer-motion";
const Component = () => {
const shouldReduceMotion = useReducedMotion();
// When reduced motion is preferred:
// - Pass undefined to variants prop
// - Pass undefined to initial prop
// - Pass undefined to transition prop
// - Skip CSS keyframe animations
};
When to Use CSS vs Motion
| Use Case | Recommendation |
|----------|----------------|
| Scroll-triggered reveals | Motion (whileInView) |
| Entrance animations | Motion (initial/animate) |
| Staggered lists | Motion (staggerChildren) |
| Hover states | CSS (Tailwind transition-*) |
| Infinite loops (background effects) | CSS keyframes |
| Simple state transitions | CSS (transition-all) |
Easing Functions
Standard easing curves used in the codebase:
| Name | Value | Use Case |
|------|-------|----------|
| Smooth decelerate | [0.16, 1, 0.3, 1] | Hero entrances, dramatic reveals |
| Standard ease | [0.4, 0, 0.2, 1] | General purpose animations |
Viewport Options
viewport={{
once: true, // Only animate once (recommended)
amount: 0.2, // Trigger when 20% visible
// amount: 0.3, // Trigger when 30% visible (for smaller items)
}}
File Organization
Variants file naming: Use variants.ts (industry standard)
src/app/about/
├── _components/
│ ├── variants.ts # Shared animation variants
│ ├── hero-section.tsx # Uses variants
│ ├── stats-section.tsx # Uses variants + AnimatedNumber
│ └── timeline-section.tsx # Uses variants
Migration from CSS/Intersection Observer
When migrating existing animations:
- Remove
useState(isVisible)+useEffectwithIntersectionObserver - Remove
refpassed to section element - Add
motion.divwithwhileInView - Add
useReducedMotion()check - Import variants from shared file
Before (Intersection Observer):
const [isVisible, setIsVisible] = useState(false);
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => { if (entry.isIntersecting) setIsVisible(true); },
{ threshold: 0.2 }
);
if (sectionRef.current) observer.observe(sectionRef.current);
return () => observer.disconnect();
}, []);
return (
<div ref={sectionRef} className={isVisible ? "animate-fade-in" : "opacity-0"}>
After (Motion):
const shouldReduceMotion = useReducedMotion();
return (
<motion.div
variants={shouldReduceMotion ? undefined : fadeInUpVariants}
initial={shouldReduceMotion ? undefined : "hidden"}
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
>
Validation Checklist
When implementing animations:
- [ ] Uses
useReducedMotion()for accessibility - [ ] Passes
undefinedto variants/initial/transition when reduced motion preferred - [ ] Uses shared variants from
variants.tswhere applicable - [ ] Uses
viewport={{ once: true }}for scroll-triggered animations - [ ] Keeps hover states as CSS transitions (not Motion)
- [ ] Uses CSS keyframes for infinite/background animations
Related Files
apps/web/CLAUDE.md- Web app conventionsapps/web/src/app/about/_components/variants.ts- Animation variantsapps/web/src/components/animated-number.tsx- Number animation component
Du fichier au premier essai
Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.
Consulter la source et ses fichiers annexesCe téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.
1. Télécharger le fichier
Télécharger SKILL.mdDepuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.
Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.
mkdir -p '.skill-downloads/framer-motion-animations-mrx3xxnw' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/framer-motion-animations-mrx3xxnw/download' --output '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md.part' && mv '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md.part' '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md'2. Vérifier les prérequis
Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.
Outils déclarés par l’auteur (à vérifier dans votre agent) : Read, Edit, Write, Grep, Glob
Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.
Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.
3. Charger la skill
Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.
Claude Code
test -f '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md' && test -s '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/framer-motion-animations' && cp -R '.skill-downloads/framer-motion-animations-mrx3xxnw' '.claude/skills/framer-motion-animations'Cursor
test -f '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md' && test -s '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/framer-motion-animations' && cp -R '.skill-downloads/framer-motion-animations-mrx3xxnw' '.cursor/skills/framer-motion-animations'Codex
test -f '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md' && test -s '.skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/framer-motion-animations' && cp -R '.skill-downloads/framer-motion-animations-mrx3xxnw' '.agents/skills/framer-motion-animations'OpenSkills
OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.
Installation officielle d’OpenSkillsopenskills install './.skill-downloads/framer-motion-animations-mrx3xxnw'openskills read 'framer-motion-animations-mrx3xxnw'La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.
Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.
openskills syncMode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.
4. Faire un premier essai
Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :
Lis .skill-downloads/framer-motion-animations-mrx3xxnw/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.
Bonnes pratiques React Hook Form
Developpement
Maîtrisez React Hook Form : évitez les anti-patterns, gérez les abonnements, et traitez correctement reset, dirty state et entrées contrôlées.
Migration Emotion vers Mantine
Developpement
Migrer les styled-components Emotion vers des composants Mantine avec style props et modules CSS. Pour convertir .styled.tsx ou supprimer les imports @emotion.
Détecteur de dérive de périmètre
Developpement
Analyse les diffs git par rapport à une intention pour détecter la dérive de périmètre, fichiers non liés et PR trop larges, puis suggère de garder, diviser ou justifier.