Claude Code Plugins

Community-maintained marketplace

Feedback

bellog-animations

@whddltjdwhd/bellog
2
0

Provides Framer Motion animation patterns and best practices specific to the Bellog blog project. Triggers when implementing animated components or interactions.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name bellog-animations
description Provides Framer Motion animation patterns and best practices specific to the Bellog blog project. Triggers when implementing animated components or interactions.

Bellog Animation Patterns

This skill provides the animation patterns and best practices used throughout the Bellog blog project.

Core Animation Principles

  1. Organic movement - Use easing curves, never linear
  2. Stagger for rhythm - Create visual flow with staggered animations
  3. Living elements - Ambient animations that breathe life
  4. Consistent timing - Follow project timing standards

Animation Timing Standards

// Interaction timings
const INTERACTION_FAST = 0.2;    // Button press, hover start
const INTERACTION_NORMAL = 0.3;  // Standard hover effects
const INTERACTION_SLOW = 0.5;    // Modal open, drawer slide

// Transition timings
const TRANSITION_FAST = 0.3;     // Quick state changes
const TRANSITION_NORMAL = 0.4;   // Page transitions (standard)
const TRANSITION_SLOW = 0.6;     // Heavy content transitions

// Ambient timings
const AMBIENT_SLOW = 3;          // Slow blob movement
const AMBIENT_NORMAL = 4;        // Standard blob rhythm
const AMBIENT_FAST = 5;          // Faster ambient motion

Pattern 1: Stagger Children

Use for lists, grids, and groups of elements.

When to use: Animating multiple items that should appear in sequence

Example from Intro.tsx:

const container = {
  hidden: { opacity: 0 },
  show: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1,  // 100ms delay between each child
      delayChildren: 0.2      // Start after 200ms
    }
  }
};

const item = {
  hidden: { y: 20, opacity: 0 },
  show: {
    y: 0,
    opacity: 1,
    transition: {
      duration: 0.5,
      ease: "easeInOut"
    }
  }
};

// Usage
<motion.div
  variants={container}
  initial="hidden"
  animate="show"
>
  {items.map(item => (
    <motion.div key={item.id} variants={item}>
      {item.content}
    </motion.div>
  ))}
</motion.div>

Pattern 2: Living Blob Animations

Use for decorative elements, background shapes, ambient animations.

When to use: Creating organic, perpetual movement

Example from Intro.tsx:

const blobVariants = {
  initial: {
    scale: 1,
    x: 0,
    y: 0
  },
  hover: {
    scale: [1, 1.2, 0.9, 1.1, 1],    // Keyframes
    x: [0, 20, -10, 5, 0],
    y: [0, -15, 10, -5, 0],
    transition: {
      duration: 4,
      repeat: Infinity,
      repeatType: "mirror",
      ease: "easeInOut"
    }
  }
};

// Multiple blobs with different rhythms
const blob1 = { duration: 3, ... };
const blob2 = { duration: 4.5, ... };
const blob3 = { duration: 5.2, ... };

Best practices:

  • Layer multiple blobs with different durations for organic feel
  • Use repeatType: "mirror" for smooth loops
  • Keep movements subtle (scale: 0.9-1.2 range)
  • Use blur and opacity to create depth

Pattern 3: Page Transitions

Use for route changes, content swapping.

When to use: Navigating between pages or major content changes

Example from template.tsx:

<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  exit={{ opacity: 0, y: 20 }}
  transition={{
    ease: "easeInOut",
    duration: 0.4
  }}
>
  {children}
</motion.div>

Variations:

// Fade only
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}

// Slide from right
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}

// Scale + fade
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}

Pattern 4: Hover Interactions

Use for buttons, cards, clickable elements.

When to use: Adding interactivity to user-actionable elements

const cardVariants = {
  initial: { scale: 1 },
  hover: {
    scale: 1.02,
    transition: {
      duration: 0.3,
      ease: "easeInOut"
    }
  },
  tap: {
    scale: 0.98
  }
};

<motion.div
  variants={cardVariants}
  initial="initial"
  whileHover="hover"
  whileTap="tap"
>

Common hover patterns:

  • Cards: scale(1.02) + shadow increase
  • Buttons: scale(1.05) + slight lift
  • Icons: rotate or scale
  • Links: underline expand

Pattern 5: Scroll-Based Animations

Use for parallax, fade-ins, progress indicators.

When to use: Animations triggered by scroll position

import { useScroll, useTransform } from "framer-motion";

const { scrollYProgress } = useScroll();
const opacity = useTransform(scrollYProgress, [0, 0.5], [0, 1]);
const y = useTransform(scrollYProgress, [0, 0.5], [50, 0]);

<motion.div style={{ opacity, y }}>
  {/* Content */}
</motion.div>

Example: Progress bar

const { scrollYProgress } = useScroll();

<motion.div
  style={{ scaleX: scrollYProgress }}
  className="fixed top-0 left-0 right-0 h-1 bg-primary origin-left"
/>

Pattern 6: Enter/Exit Animations

Use with AnimatePresence for conditional rendering.

When to use: Elements that appear and disappear

import { AnimatePresence } from "framer-motion";

const variants = {
  hidden: { opacity: 0, y: -10 },
  visible: { opacity: 1, y: 0 },
  exit: { opacity: 0, y: -10 }
};

<AnimatePresence>
  {isVisible && (
    <motion.div
      variants={variants}
      initial="hidden"
      animate="visible"
      exit="exit"
      transition={{ duration: 0.3 }}
    >
      {content}
    </motion.div>
  )}
</AnimatePresence>

Easing Functions

Use these, not "linear":

// Bellog standard
ease: "easeInOut"  // Default for most animations

// Other options
ease: "easeOut"    // For entrances
ease: "easeIn"     // For exits
ease: [0.43, 0.13, 0.23, 0.96]  // Custom cubic-bezier

Animation Checklist

Before finalizing animations:

  • Timing follows project standards (0.2-0.5s for interactions)
  • Uses variants pattern (not inline animation props)
  • Easing is easeInOut or appropriate alternative
  • No linear easing
  • Stagger delay appropriate for number of items
  • Exit animations defined if using AnimatePresence
  • Performance: No layout thrashing (avoid animating width/height)
  • Accessibility: Respects prefers-reduced-motion if critical

Performance Tips

  1. Transform over top/left:

    // ✅ Good (GPU accelerated)
    { x: 100 }
    { translateX: "100px" }
    { scale: 1.1 }
    
    // ❌ Bad (layout recalc)
    { left: 100 }
    { width: "100%" }
    
  2. Will-change hint:

    style={{ willChange: "transform" }}
    
  3. Layout animations (use sparingly):

    <motion.div layout>
    

Reduced Motion

Respect user preferences:

import { useReducedMotion } from "framer-motion";

const shouldReduceMotion = useReducedMotion();

const variants = {
  hidden: { opacity: 0, y: shouldReduceMotion ? 0 : 20 },
  visible: { opacity: 1, y: 0 }
};

Common Mistakes to Avoid

Don't: Inline animation props

<motion.div animate={{ opacity: 1 }} initial={{ opacity: 0 }}>

Do: Use variants

const variants = { hidden: { opacity: 0 }, visible: { opacity: 1 } };
<motion.div variants={variants} initial="hidden" animate="visible">

Don't: Linear easing

transition={{ duration: 0.3, ease: "linear" }}

Do: Use curves

transition={{ duration: 0.3, ease: "easeInOut" }}

Don't: Animate width/height directly

animate={{ width: "100%" }}

Do: Use scale or layout

animate={{ scaleX: 1 }}
// or
<motion.div layout>

Quick Reference

// Standard fade + slide in
{ initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 } }

// Standard hover
{ whileHover: { scale: 1.02 }, transition: { duration: 0.3 } }

// Standard stagger
{
  variants: {
    container: { transition: { staggerChildren: 0.1 } },
    item: { hidden: { y: 20, opacity: 0 }, show: { y: 0, opacity: 1 } }
  }
}

// Standard exit
{ exit: { opacity: 0, y: -10 }, transition: { duration: 0.2 } }

Remember: Animations should enhance the experience, not distract from it. When in doubt, keep it subtle and fast.