Skip to main content Home Creators amo-tech-ai rocket-path-ai motion-interaction-designer
motion-interaction-designer Design smooth UI animations and interactions using Framer Motion for React/Next.js. Use when users request animations, transitions, hover effects, scroll animations, gesture interactions, or need help implementing Framer Motion. Follow modern motion UX principles with purposeful, performant animations that enhance usability.
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/amo-tech-ai/rocket-path-ai --skill motion-interaction-designerThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository
OpenClaw Gateway setup, configuration, and best practices. Use when installing OpenClaw, configuring channels (WhatsApp/Telegram/Discord), setting up providers (OpenAI/Google/Anthropic), creating skills, managing the gateway daemon, or troubleshooting OpenClaw issues. Triggers on: openclaw, gateway, whatsapp channel, telegram bot, openclaw skill, openclaw config, openclaw install, openclaw cron, openclaw security.
Use this skill for setting up vector similarity search with pgvector for AI/ML embeddings, RAG applications, or semantic search.
**Trigger when user asks to:**
- Store or search vector embeddings in PostgreSQL
- Set up semantic search, similarity search, or nearest neighbor search
- Create HNSW or IVFFlat indexes for vectors
- Implement RAG (Retrieval Augmented Generation) with PostgreSQL
- Optimize pgvector performance, recall, or memory usage
- Use binary quantization for large vector datasets
**Keywords:** pgvector, embeddings, semantic search, vector similarity, HNSW, IVFFlat, halfvec, cosine distance, nearest neighbor, RAG, LLM, AI search
Covers: halfvec storage, HNSW index configuration (m, ef_construction, ef_search), quantization strategies, filtered search, bulk loading, and performance tuning.
**This project:** We use OpenAI text-embedding-3-small (1536) and store as vector(1536) in knowledge_chunks. halfvec is an optional future optimization; apply this skill's tuning (ef_search, iterative_scan
Related occupations SOC
Based on SOC occupation classification
name motion-interaction-designer description Design smooth UI animations and interactions using Framer Motion for React/Next.js. Use when users request animations, transitions, hover effects, scroll animations, gesture interactions, or need help implementing Framer Motion. Follow modern motion UX principles with purposeful, performant animations that enhance usability.
Motion & Interaction Designer
Design purposeful, smooth UI animations using Framer Motion following modern motion UX principles.
Core Philosophy
Motion UX Principles :
Purposeful : Every animation serves a function (feedback, guidance, delight)
Subtle : Motion enhances, never distracts (200-500ms sweet spot)
Responsive : Respect user preferences (reduced motion)
Performant : 60fps on all devices, GPU-accelerated properties
Consistent : Unified timing and easing across the app
When to Animate :
✅ State changes (hover, active, disabled)
✅ Page/component transitions (route changes, modals)
✅ User feedback (button clicks, form submissions)
✅ Content reveals (scroll, load, stagger)
✅ Contextual hints (first-time user guidance)
When NOT to Animate :
❌ Critical actions (payment buttons - instant only)
❌ Reading content (body text, paragraphs)
❌ Rapid repetition (typing, scrolling lists)
❌ User requested reduced motion
Technology Stack
Required Dependency :
{
"framer-motion" : "^11.0.0"
}
Optional (Scroll Animations) :
{
"react-intersection-observer" : "^9.5.0"
}
Motion Workflow When a user requests animation design, follow this approach:
Step 1: Identify Animation Type Categorize the interaction into one of these patterns:
1. State Transitions (hover, focus, active, disabled)
Buttons, links, cards
Duration: 150-300ms
Easing: ease-out
2. Enter/Exit Animations (mount, unmount, visibility)
Modals, dropdowns, tooltips
Duration: 200-400ms
Easing: ease-in-out
3. Layout Animations (position, size changes)
Expanding cards, reordering lists
Duration: 300-500ms
Easing: spring or ease-out
4. Scroll Animations (scroll-triggered reveals)
Parallax, fade-ins, stagger effects
Duration: 400-600ms
Easing: ease-out
5. Gesture Interactions (drag, tap, swipe)
Custom controls, sliders, carousels
Duration: Immediate feedback + 200-400ms settle
Easing: spring (feels natural)
Step 2: Define Motion Properties For each animation, specify:
Properties to Animate :
GPU-accelerated (best performance): transform, opacity
Avoid : width, height, top, left, margin
Duration : Target time in milliseconds
Easing : Curve type (see timing guide below)
Delay : Stagger or sequence timing
Spring vs Tween : Natural feel vs precise control
Step 3: Provide Implementation Code
Import statements
Component structure
Motion variants (reusable animation configs)
Responsive behavior
Accessibility (reduced motion)
Implementation Patterns
Pattern 1: Basic Hover Animation (Button) Use Case : Call-to-action buttons, interactive elements
import { motion } from 'framer-motion'
export function AnimatedButton ({ children, onClick } ) {
return (
<motion.button
onClick ={onClick}
whileHover ={{
scale: 1.05 ,
boxShadow: '0 10px 20px rgba (0 , 0 , 0 , 0.15 )'
}}
whileTap ={{ scale: 0.95 }}
transition ={{
type: 'spring ',
stiffness: 400 ,
damping: 17
}}
style ={{
padding: '12px 24px ',
backgroundColor: '#6366F1 ',
color: 'white ',
border: 'none ',
borderRadius: '8px ',
cursor: 'pointer '
}}
>
{children}
</motion.button >
)
}
Hover : Scale 1.05 (5% larger), shadow grows
Tap : Scale 0.95 (5% smaller) - tactile feedback
Transition : Spring (natural bounce)
Performance : GPU-accelerated (scale, boxShadow)
Pattern 2: Fade In on Mount (Modal, Dropdown) Use Case : Overlays, popups, tooltips
import { motion, AnimatePresence } from 'framer-motion'
export function Modal ({ isOpen, onClose, children } ) {
return (
<AnimatePresence >
{isOpen && (
<>
{/* Backdrop */}
<motion.div
initial ={{ opacity: 0 }}
animate ={{ opacity: 1 }}
exit ={{ opacity: 0 }}
transition ={{ duration: 0.2 }}
onClick ={onClose}
style ={{
position: 'fixed ',
inset: 0 ,
backgroundColor: 'rgba (0 , 0 , 0 , 0.5 )',
zIndex: 40
}}
/>
{/* Modal Content */}
<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 ={{
duration: 0.3 ,
ease: [0.4 , 0 , 0.2 , 1 ] // Custom ease-out
}}
style ={{
position: 'fixed ',
top: '50 %',
left: '50 %',
transform: 'translate (-50 %, -50 %)',
backgroundColor: 'white ',
padding: '32px ',
borderRadius: '12px ',
zIndex: 50
}}
>
{children}
</motion.div >
</>
)}
</AnimatePresence >
)
}
Enter : Fade + scale up + slide down
Exit : Fade + scale down + slide down
Duration : 300ms (perceivable but not slow)
Easing : Custom ease-out (smooth deceleration)
AnimatePresence : Handles unmount animations
Pattern 3: Stagger Children (List Items) Use Case : Todo lists, navigation items, feature grids
import { motion } from 'framer-motion'
const containerVariants = {
hidden : { opacity : 0 },
visible : {
opacity : 1 ,
transition : {
staggerChildren : 0.1 ,
delayChildren : 0.2
}
}
}
const itemVariants = {
hidden : { opacity : 0 , x : -20 },
visible : {
opacity : 1 ,
x : 0 ,
transition : {
duration : 0.4 ,
ease : 'easeOut'
}
}
}
export function TodoList ({ todos } ) {
return (
<motion.ul
variants ={containerVariants}
initial ="hidden"
animate ="visible"
style ={{ listStyle: 'none ', padding: 0 }}
>
{todos.map((todo) => (
<motion.li
key ={todo.id}
variants ={itemVariants}
style ={{ padding: '12px ', marginBottom: '8px ' }}
>
{todo.title}
</motion.li >
))}
</motion.ul >
)
}
Stagger : 100ms between each child
Delay : 200ms before first child
Item animation : Fade + slide from left
Variants : Reusable animation configs
Pattern 4: Scroll-Triggered Animation Use Case : Section reveals, parallax effects
import { motion, useScroll, useTransform } from 'framer-motion'
import { useRef } from 'react'
export function ScrollReveal ({ children } ) {
const ref = useRef (null )
return (
<motion.div
ref ={ref}
initial ={{ opacity: 0 , y: 50 }}
whileInView ={{ opacity: 1 , y: 0 }}
viewport ={{ once: true , amount: 0.3 }} // Trigger at 30 % visible
transition ={{ duration: 0.6 , ease: 'easeOut ' }}
>
{children}
</motion.div >
)
}
export function ParallaxSection ( ) {
const { scrollYProgress } = useScroll ()
const y = useTransform (scrollYProgress, [0 , 1 ], ['0%' , '50%' ])
return (
<motion.div
style ={{ y }}
className ="background-layer"
>
{/* Background content */}
</motion.div >
)
}
whileInView : Animates when 30% visible
viewport.once : Only animate first time (performance)
Parallax : Transform Y based on scroll progress
Use case : Hero sections, feature reveals
Pattern 5: Layout Animation (Reordering, Expanding) Use Case : Animated lists, accordions, grid layouts
import { motion, LayoutGroup } from 'framer-motion'
import { useState } from 'react'
export function AnimatedList ({ items } ) {
const [sortedItems, setSortedItems] = useState (items)
return (
<LayoutGroup >
<motion.ul layout >
{sortedItems.map((item) => (
<motion.li
key ={item.id}
layout
transition ={{
type: 'spring ',
stiffness: 500 ,
damping: 30
}}
>
{item.title}
</motion.li >
))}
</motion.ul >
</LayoutGroup >
)
}
export function Accordion ({ title, children } ) {
const [isOpen, setIsOpen] = useState (false )
return (
<motion.div layout >
<motion.button
layout
onClick ={() => setIsOpen(!isOpen)}
>
{title}
</motion.button >
<AnimatePresence >
{isOpen && (
<motion.div
initial ={{ height: 0 , opacity: 0 }}
animate ={{ height: 'auto ', opacity: 1 }}
exit ={{ height: 0 , opacity: 0 }}
transition ={{ duration: 0.3 }}
>
{children}
</motion.div >
)}
</AnimatePresence >
</motion.div >
)
}
layout prop : Auto-animates position/size changes
LayoutGroup : Shared layout context for smooth transitions
Spring : Natural feel for reordering
Auto height : Smooth accordion expand/collapse
Pattern 6: Drag Interaction Use Case : Sliders, reorderable lists, custom controls
import { motion } from 'framer-motion'
export function DraggableCard ( ) {
return (
<motion.div
drag
dragConstraints ={{
top: -100 ,
left: -100 ,
right: 100 ,
bottom: 100
}}
dragElastic ={0.1}
dragTransition ={{
bounceStiffness: 600 ,
bounceDamping: 20
}}
whileDrag ={{ scale: 1.05 , cursor: 'grabbing ' }}
style ={{
width: 200 ,
height: 200 ,
backgroundColor: '#6366F1 ',
borderRadius: 12 ,
cursor: 'grab '
}}
>
Drag me!
</motion.div >
)
}
export function SwipeCard ({ onDismiss } ) {
return (
<motion.div
drag ="x"
dragConstraints ={{ left: 0 , right: 0 }}
onDragEnd ={(e, { offset , velocity }) => {
const swipe = Math.abs(offset.x) * velocity.x
if (swipe < -10000 || swipe > 10000) {
onDismiss()
}
}}
>
Swipe to dismiss
</motion.div >
)
}
drag : Enable dragging (x, y, or both)
dragConstraints : Limit drag area
dragElastic : Bounce at boundaries
whileDrag : Scale up while dragging
Swipe detection : velocity × offset
Timing & Easing Guide
Duration Guidelines
Immediate feedback (button clicks, checkbox toggles)
No animation needed
State changes (hover, focus)
Small movements (icon rotations)
Use: transition={{ duration: 0.15 }}
Modals, dropdowns, tooltips
Card reveals, fades
Use: transition={{ duration: 0.3 }}
Page transitions
Large layout shifts
Scroll-triggered reveals
Use: transition={{ duration: 0.5 }}
Only for intentional dramatic effect
Onboarding tours, hero animations
Use sparingly: transition={{ duration: 0.8 }}
Easing Functions transition={{ ease : 'easeOut' }}
Use : Enter animations, reveals, fades
Feel : Starts fast, slows down (natural deceleration)
transition={{ ease : 'easeIn' }}
Use : Exit animations, dismissals
Feel : Starts slow, speeds up (falling away)
transition={{ ease : 'easeInOut' }}
Use : Mid-journey animations (A → B → A)
Feel : Smooth start and end
transition={{
type : 'spring' ,
stiffness : 500 ,
damping : 30
}}
Use : Interactive elements (buttons, drag)
Feel : Physical, bouncy, responsive
Stiffness : 300-700 range (500 is good default)
Damping : 20-40 range (30 is good default)
transition={{ ease : 'linear' }}
Use : Looping animations, loading spinners
Feel : Mechanical, constant speed
Accessibility & Reduced Motion
Respect User Preferences Always include reduced motion support :
import { useReducedMotion } from 'framer-motion'
export function AccessibleAnimation ({ children } ) {
const shouldReduceMotion = useReducedMotion ()
const variants = {
hidden : { opacity : 0 , y : shouldReduceMotion ? 0 : 20 },
visible : {
opacity : 1 ,
y : 0 ,
transition : {
duration : shouldReduceMotion ? 0.01 : 0.4
}
}
}
return (
<motion.div
variants ={variants}
initial ="hidden"
animate ="visible"
>
{children}
</motion.div >
)
}
Disable decorative animations
Reduce duration to 0.01s (instant but still works)
Keep essential feedback (button press, loading states)
Maintain layout shifts (don't disable layout prop)
Performance Optimization
GPU-Accelerated Properties Animate These (60fps guaranteed):
<motion.div
animate={{
x : 100 ,
y : 100 ,
scale : 1.5 ,
rotate : 45 ,
opacity : 0.5
}}
/>
Avoid Animating (causes reflow/repaint):
<motion.div
animate={{
width : 300 ,
height : 200 ,
top : 100 ,
left : 100 ,
margin : 20
}}
/>
Will-Change Optimization <motion.div
style={{ willChange : 'transform' }}
animate={{ x : 100 , rotate : 45 }}
/>
Warning : Only use for actively animating elements. Remove after animation completes.
Lazy Loading Animations import { motion, LazyMotion , domAnimation } from 'framer-motion'
export function OptimizedApp ( ) {
return (
<LazyMotion features ={domAnimation} >
<motion.div > Optimized animations</motion.div >
</LazyMotion >
)
}
Common Animation Patterns
Page Transitions (Next.js)
import { motion, AnimatePresence } from 'framer-motion'
import { usePathname } from 'next/navigation'
export default function Layout ({ children } ) {
const pathname = usePathname ()
return (
<AnimatePresence mode ="wait" >
<motion.div
key ={pathname}
initial ={{ opacity: 0 , x: 20 }}
animate ={{ opacity: 1 , x: 0 }}
exit ={{ opacity: 0 , x: -20 }}
transition ={{ duration: 0.3 }}
>
{children}
</motion.div >
</AnimatePresence >
)
}
Loading States export function LoadingSpinner ( ) {
return (
<motion.div
animate ={{ rotate: 360 }}
transition ={{
duration: 1 ,
repeat: Infinity ,
ease: 'linear '
}}
style ={{
width: 40 ,
height: 40 ,
border: '3px solid #E5E7EB ',
borderTopColor: '#6366F1 ',
borderRadius: '50 %'
}}
/>
)
}
Success Checkmark import { motion } from 'framer-motion'
const checkmarkVariants = {
hidden : { pathLength : 0 , opacity : 0 },
visible : {
pathLength : 1 ,
opacity : 1 ,
transition : {
pathLength : { duration : 0.5 , ease : 'easeOut' },
opacity : { duration : 0.01 }
}
}
}
export function SuccessCheckmark ( ) {
return (
<svg width ="60" height ="60" viewBox ="0 0 60 60" >
<motion.path
d ="M15,30 L25,40 L45,20"
fill ="none"
stroke ="#10B981"
strokeWidth ="4"
strokeLinecap ="round"
variants ={checkmarkVariants}
initial ="hidden"
animate ="visible"
/>
</svg >
)
}
Motion Design Checklist When designing animations, verify:
Advanced Patterns For complex scenarios, see:
references/motion-patterns.md - Advanced animation patterns (shared transitions, orchestration)
references/gesture-interactions.md - Drag, swipe, pan, pinch gestures
references/scroll-effects.md - Parallax, scroll-linked animations, viewport triggers
Output Format When providing motion design guidance, structure as:
## Animation: [Component Name]
### Purpose
[Why this animation exists - user benefit]
### Motion Specs
- **Trigger**: [Hover, click, scroll, mount]
- **Properties**: [x, y, scale, opacity, etc.]
- **Duration**: [200ms, 400ms, etc.]
- **Easing**: [ease-out, spring, etc.]
- **Delay**: [If staggered or sequenced]
### Implementation
[Framer Motion code]
### Reduced Motion Fallback
[Simplified version for accessibility]
### Performance Notes
[GPU acceleration, potential issues]
Remember : Less is more. Purposeful motion enhances usability. Excessive animation annoys users.