
bellog-animations
by whddltjdwhd
Castle Bell's custom blog
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
- Organic movement - Use easing curves, never linear
- Stagger for rhythm - Create visual flow with staggered animations
- Living elements - Ambient animations that breathe life
- 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
variantspattern (not inline animation props) - Easing is
easeInOutor 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-motionif critical
Performance Tips
-
Transform over top/left:
// ✅ Good (GPU accelerated) { x: 100 } { translateX: "100px" } { scale: 1.1 } // ❌ Bad (layout recalc) { left: 100 } { width: "100%" } -
Will-change hint:
style={{ willChange: "transform" }} -
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.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon


