Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    canatufkansu

    framer-motion-animations

    canatufkansu/framer-motion-animations
    Design
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Subtle animation patterns for hero sections, card reveals, page transitions, and scroll-triggered effects using Framer Motion.

    SKILL.md

    Framer Motion Animations

    Installation

    npm install framer-motion
    

    Basic Fade In

    'use client';
    
    import { motion } from 'framer-motion';
    
    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>
      );
    }
    

    Staggered Children

    'use client';
    
    import { motion } from 'framer-motion';
    
    const container = {
      hidden: { opacity: 0 },
      show: {
        opacity: 1,
        transition: {
          staggerChildren: 0.1,
        },
      },
    };
    
    const item = {
      hidden: { opacity: 0, y: 20 },
      show: { opacity: 1, y: 0 },
    };
    
    export function StaggeredList({ items }: { items: React.ReactNode[] }) {
      return (
        <motion.ul
          variants={container}
          initial="hidden"
          animate="show"
          className="space-y-4"
        >
          {items.map((child, i) => (
            <motion.li key={i} variants={item}>
              {child}
            </motion.li>
          ))}
        </motion.ul>
      );
    }
    

    Scroll-Triggered Animation

    'use client';
    
    import { motion, useInView } from 'framer-motion';
    import { useRef } from 'react';
    
    export function ScrollReveal({ 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>
      );
    }
    

    Hero Animation

    'use client';
    
    import { motion } from 'framer-motion';
    
    export function HeroSection() {
      return (
        <section className="min-h-screen flex items-center">
          <div className="container mx-auto px-4">
            <motion.h1
              initial={{ opacity: 0, y: 30 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{ duration: 0.8, delay: 0.2 }}
              className="text-5xl md:text-7xl font-bold"
            >
              Pilates & Yoga
            </motion.h1>
            
            <motion.p
              initial={{ opacity: 0, y: 30 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{ duration: 0.8, delay: 0.4 }}
              className="text-xl mt-6 text-muted-foreground"
            >
              Transform your body and mind
            </motion.p>
            
            <motion.div
              initial={{ opacity: 0, y: 30 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{ duration: 0.8, delay: 0.6 }}
              className="mt-8 flex gap-4"
            >
              <Button>Book Now</Button>
              <Button variant="outline">Learn More</Button>
            </motion.div>
          </div>
        </section>
      );
    }
    

    Card Hover Effect

    'use client';
    
    import { motion } from 'framer-motion';
    
    export function AnimatedCard({ children }: { children: React.ReactNode }) {
      return (
        <motion.div
          whileHover={{ y: -5, boxShadow: '0 10px 30px rgba(0,0,0,0.1)' }}
          transition={{ duration: 0.2 }}
          className="bg-card rounded-lg p-6 border"
        >
          {children}
        </motion.div>
      );
    }
    

    Section Wrapper

    'use client';
    
    import { motion } from 'framer-motion';
    import { useInView } from 'framer-motion';
    import { useRef } from 'react';
    
    interface SectionProps {
      children: React.ReactNode;
      className?: string;
      delay?: number;
    }
    
    export function AnimatedSection({ children, className, delay = 0 }: SectionProps) {
      const ref = useRef(null);
      const isInView = useInView(ref, { once: true, margin: '-50px' });
    
      return (
        <motion.section
          ref={ref}
          initial={{ opacity: 0, y: 40 }}
          animate={isInView ? { opacity: 1, y: 0 } : {}}
          transition={{ duration: 0.6, delay, ease: 'easeOut' }}
          className={className}
        >
          {children}
        </motion.section>
      );
    }
    

    Counter Animation

    'use client';
    
    import { motion, useMotionValue, useTransform, animate } from 'framer-motion';
    import { useEffect } from 'react';
    
    interface CounterProps {
      from: number;
      to: number;
      duration?: number;
    }
    
    export function AnimatedCounter({ from, to, duration = 2 }: CounterProps) {
      const count = useMotionValue(from);
      const rounded = useTransform(count, (latest) => Math.round(latest));
    
      useEffect(() => {
        const controls = animate(count, to, { duration });
        return controls.stop;
      }, [count, to, duration]);
    
      return <motion.span>{rounded}</motion.span>;
    }
    
    // Usage
    <div className="text-4xl font-bold">
      <AnimatedCounter from={0} to={500} />+
      <span className="text-sm">Happy Clients</span>
    </div>
    

    Page Transition Wrapper

    'use client';
    
    import { motion, AnimatePresence } from 'framer-motion';
    import { usePathname } from 'next/navigation';
    
    export function PageTransition({ children }: { children: React.ReactNode }) {
      const pathname = usePathname();
    
      return (
        <AnimatePresence mode="wait">
          <motion.div
            key={pathname}
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.3 }}
          >
            {children}
          </motion.div>
        </AnimatePresence>
      );
    }
    

    Accordion Animation

    'use client';
    
    import { motion, AnimatePresence } from 'framer-motion';
    import { useState } from 'react';
    
    interface AccordionItemProps {
      title: string;
      children: React.ReactNode;
    }
    
    export function AccordionItem({ title, children }: AccordionItemProps) {
      const [isOpen, setIsOpen] = useState(false);
    
      return (
        <div className="border-b">
          <button
            onClick={() => setIsOpen(!isOpen)}
            className="w-full py-4 flex justify-between items-center"
          >
            <span className="font-medium">{title}</span>
            <motion.span
              animate={{ rotate: isOpen ? 180 : 0 }}
              transition={{ duration: 0.2 }}
            >
              ▼
            </motion.span>
          </button>
          
          <AnimatePresence>
            {isOpen && (
              <motion.div
                initial={{ height: 0, opacity: 0 }}
                animate={{ height: 'auto', opacity: 1 }}
                exit={{ height: 0, opacity: 0 }}
                transition={{ duration: 0.3 }}
                className="overflow-hidden"
              >
                <div className="pb-4">{children}</div>
              </motion.div>
            )}
          </AnimatePresence>
        </div>
      );
    }
    

    Performance Tips

    1. Use layoutId for shared element transitions
    2. Use useReducedMotion() to respect user preferences
    3. Avoid animating layout properties (width, height) - use transforms
    4. Use will-change sparingly via Tailwind's will-change-transform
    5. Prefer opacity and transform animations (GPU accelerated)
    Repository
    canatufkansu/claude-skills
    Files