SuperAPI AI Directory

lottiefiles-motion-design-skill

Design & creation

View repository

Updated 10-16 03:08

About this skill

LottieFiles Motion Design Skill

Skill by ara.so — Design Skills collection.

This skill teaches AI agents to think like motion directors — choosing the right timing, easing, choreography, and emotional intent before writing animation code. Philosophy-first, implementation-agnostic approach that works with any animation system (CSS, Framer Motion, GSAP, Lottie, React Spring, etc.).

Installation

npx skills add LottieFiles/motion-design-skill

The skill integrates with 40+ AI coding agents including Claude Code, Cursor, Codex, and GitHub Copilot.

Core Philosophy

The Three Pillars

Every animation decision flows from three questions:

  1. WHY — What's the purpose? (feedback, guidance, delight, hierarchy)
  2. WHAT — Which properties communicate that? (position, scale, opacity, color)
  3. HOW — What personality matches the brand? (snappy, smooth, bouncy, minimal)

The 8-Step Motion Checklist

Before writing any animation code:

  1. Purpose — Why does this need to animate?
  2. Emotion — What should the user feel?
  3. Personality — Which motion archetype fits the brand?
  4. Properties — Which CSS/transform properties to animate?
  5. Duration — How long should it take?
  6. Easing — What curve shape matches the intent?
  7. Choreography — If multiple elements, what's the sequence?
  8. Quality — Does it pass the motion design checklist?

Motion Personality Archetypes

Choose one archetype per brand/project:

1. Snappy (Productivity, Tools)

// Framer Motion example
const snappy = {
  duration: 0.2,
  ease: [0.4, 0, 0.2, 1] // easeInOutCubic
};

// CSS example
.snappy-button {
  transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
}

2. Smooth (Finance, Professional)

// Framer Motion
const smooth = {
  duration: 0.4,
  ease: [0.25, 0.1, 0.25, 1] // easeInOutQuart
};

// CSS
.smooth-card {
  transition: all 400ms cubic-bezier(0.25, 0.1, 0.25, 1);
}

3. Bouncy (Social, Playful)

// Framer Motion
const bouncy = {
  type: "spring",
  damping: 15,
  stiffness: 300
};

// CSS (approximated)
.bouncy-modal {
  transition: all 500ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

4. Minimal (Editorial, Luxury)

// Framer Motion
const minimal = {
  duration: 0.6,
  ease: [0.25, 0, 0.1, 1] // easeOutQuart
};

// CSS
.minimal-fade {
  transition: opacity 600ms cubic-bezier(0.25, 0, 0.1, 1);
}

Duration & Easing Reference

Duration by Element Size

Element Type Duration Use Case
Icon/Badge 150-200ms Small UI feedback
Button/Input 200-300ms Interactive elements
Card/Panel 300-400ms Medium containers
Modal/Drawer 400-500ms Large overlays
Page Transition 500-700ms Full screen changes

Easing by Intent

Intent Easing Function Cubic Bezier Use Case
Enter easeOut (0, 0, 0.2, 1) Elements appearing
Exit easeIn (0.4, 0, 1, 1) Elements disappearing
Move easeInOut (0.4, 0, 0.2, 1) Position/size changes
Attention easeOutBack (0.34, 1.56, 0.64, 1) Success feedback
Smooth easeInOutQuart (0.25, 0.1, 0.25, 1) Professional feel

Property Selection Guide

What each property communicates:

  • Opacity — Existence (appearing/disappearing)
  • Scale — Importance (growing/shrinking attention)
  • Position (x/y) — Origin/direction (where it came from)
  • Rotation — Playfulness/dynamism
  • Color — State change (success/error/focus)

Recommended combinations:

// Entrance (appearing)
opacity: 0 → 1 + translateY(20px → 0)

// Exit (disappearing)
opacity: 1 → 0 + scale(1 → 0.95)

// Success feedback
scale(1 → 1.1 → 1) + color(blue → green)

// Error shake
translateX(0 → -10 → 10 → 0) with easeOutBounce

Common Patterns

Pattern 1: Button Hover/Press

// Framer Motion
const buttonVariants = {
  idle: { scale: 1 },
  hover: { scale: 1.05, transition: { duration: 0.2 } },
  press: { scale: 0.95, transition: { duration: 0.1 } }
};

<motion.button
  variants={buttonVariants}
  initial="idle"
  whileHover="hover"
  whileTap="press"
>
  Click me
</motion.button>
/* CSS version */
.button {
  transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
.button:hover {
  transform: scale(1.05);
}
.button:active {
  transform: scale(0.95);
  transition-duration: 100ms;
}

Pattern 2: Card Entrance

// Framer Motion
const cardVariants = {
  hidden: { 
    opacity: 0, 
    y: 20 
  },
  visible: { 
    opacity: 1, 
    y: 0,
    transition: {
      duration: 0.4,
      ease: [0, 0, 0.2, 1] // easeOut
    }
  }
};

<motion.div
  variants={cardVariants}
  initial="hidden"
  animate="visible"
>
  Card content
</motion.div>
/* CSS version with Intersection Observer */
.card {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 400ms ease-out, 
              transform 400ms ease-out;
}
.card.visible {
  opacity: 1;
  transform: translateY(0);
}

Pattern 3: Loading → Success → Error States

// Framer Motion
const buttonStates = {
  idle: {
    scale: 1,
    backgroundColor: "#3b82f6"
  },
  loading: {
    scale: 0.95,
    backgroundColor: "#6366f1",
    transition: { duration: 0.2 }
  },
  success: {
    scale: [1, 1.1, 1],
    backgroundColor: "#10b981",
    transition: { 
      scale: { duration: 0.4, times: [0, 0.5, 1] },
      backgroundColor: { duration: 0.3 }
    }
  },
  error: {
    x: [0, -10, 10, -10, 10, 0],
    backgroundColor: "#ef4444",
    transition: {
      x: { duration: 0.5 },
      backgroundColor: { duration: 0.3 }
    }
  }
};

function SubmitButton() {
  const [state, setState] = useState('idle');
  
  return (
    <motion.button
      variants={buttonStates}
      animate={state}
    >
      {state === 'loading' && 'Submitting...'}
      {state === 'success' && '✓ Success'}
      {state === 'error' && '✗ Error'}
      {state === 'idle' && 'Submit'}
    </motion.button>
  );
}

Pattern 4: Staggered List Entrance

// Framer Motion
const containerVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1 // 100ms delay between children
    }
  }
};

const itemVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: { 
    opacity: 1, 
    y: 0,
    transition: { duration: 0.3 }
  }
};

<motion.ul
  variants={containerVariants}
  initial="hidden"
  animate="visible"
>
  {items.map(item => (
    <motion.li key={item.id} variants={itemVariants}>
      {item.content}
    </motion.li>
  ))}
</motion.ul>

Pattern 5: Modal Enter/Exit

// Framer Motion with AnimatePresence
const backdropVariants = {
  hidden: { opacity: 0 },
  visible: { opacity: 1 }
};

const modalVariants = {
  hidden: { 
    opacity: 0, 
    scale: 0.95,
    y: 20 
  },
  visible: { 
    opacity: 1, 
    scale: 1,
    y: 0,
    transition: {
      duration: 0.3,
      ease: [0, 0, 0.2, 1]
    }
  },
  exit: {
    opacity: 0,
    scale: 0.95,
    transition: {
      duration: 0.2,
      ease: [0.4, 0, 1, 1]
    }
  }
};

<AnimatePresence>
  {isOpen && (
    <>
      <motion.div 
        className="backdrop"
        variants={backdropVariants}
        initial="hidden"
        animate="visible"
        exit="hidden"
      />
      <motion.div
        className="modal"
        variants={modalVariants}
        initial="hidden"
        animate="visible"
        exit="exit"
      >
        Modal content
      </motion.div>
    </>
  )}
</AnimatePresence>

Multi-Element Choreography

When animating multiple elements, follow the hierarchy → stagger → overlap principle:

Hierarchy Rules

  1. Most important first — Hero content enters before supporting elements
  2. Follow reading order — Respect natural eye flow (top→bottom, left→right)
  3. Group by relationship — Related elements move together

Stagger Timing

// Small gaps (snappy)
staggerChildren: 0.05 // 50ms

// Medium gaps (balanced)
staggerChildren: 0.1 // 100ms

// Large gaps (dramatic)
staggerChildren: 0.15 // 150ms

Choreography Example: Dashboard Entry

// 1. Hero chart enters first
// 2. Stats cards stagger in
// 3. Sidebar fades in last

const dashboardVariants = {
  hidden: {},
  visible: {
    transition: {
      staggerChildren: 0.1,
      delayChildren: 0.2 // Wait for hero
    }
  }
};

<motion.div variants={dashboardVariants} initial="hidden" animate="visible">
  {/* Hero enters immediately */}
  <motion.div variants={heroVariants}>
    <Chart />
  </motion.div>
  
  {/* Cards stagger after hero */}
  <motion.div variants={containerVariants}>
    {cards.map(card => (
      <motion.div key={card.id} variants={cardVariants}>
        {card.content}
      </motion.div>
    ))}
  </motion.div>
  
  {/* Sidebar fades in last */}
  <motion.aside variants={sidebarVariants}>
    <Sidebar />
  </motion.aside>
</motion.div>

Disney's 12 Principles (UI-Adapted)

1. Squash & Stretch

UI Application: Scale feedback on interactive elements

// Button press
whileTap={{ scale: 0.95 }}

2. Anticipation

UI Application: Subtle motion before main action

// Button hover primes for click
hover: { scale: 1.05, y: -2 }

3. Staging

UI Application: Focus attention through contrast

// Dim background, highlight modal
backdrop: { opacity: 0.8 }

4. Straight Ahead vs. Pose-to-Pose

UI Application: Keyframe complex sequences

scale: [1, 1.2, 1.1, 1] // Bounce through keyframes

5. Follow Through & Overlapping Action

UI Application: Stagger related elements

staggerChildren: 0.1

6. Slow In/Slow Out

UI Application: Use easing curves (not linear)

ease: [0.4, 0, 0.2, 1] // Always ease, never linear

7. Arcs

UI Application: Natural curved motion paths

// Dropdown arcs down and slightly inward
x: [0, -10, 0], y: [0, 0, 20]

8. Secondary Action

UI Application: Subtle supporting animations

// Icon rotates while button scales
rotate: 360, scale: 1.1

9. Timing

UI Application: Duration conveys weight/importance

// Small: 200ms, Large: 400ms

10. Exaggeration

UI Application: Emphasize success/error states

success: { scale: [1, 1.2, 1] } // Bounce bigger

11. Solid Drawing

UI Application: Maintain visual hierarchy during motion

// Keep z-index/stacking order clear

12. Appeal

UI Application: Polish until it feels right

// Iterate on easing/timing until satisfying

Accessibility & Performance

Respect User Preferences

// Framer Motion
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');

<motion.div
  animate={reducedMotion.matches ? { opacity: 1 } : { opacity: 1, y: 0 }}
  initial={reducedMotion.matches ? { opacity: 0 } : { opacity: 0, y: 20 }}
/>
/* CSS */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

Performance Guidelines

  1. Animate transform/opacity only — GPU-accelerated
  2. Avoid animating: width, height, top, left (causes layout thrashing)
  3. Use will-change sparingly — Only during animation
  4. Debounce scroll listeners — Use Intersection Observer instead
// ✅ Good (GPU-accelerated)
transform: translateY(20px)
opacity: 0

// ❌ Avoid (forces reflow)
top: 20px
height: auto

Quality Checklist

Before shipping any animation, verify:

  • Purpose is clear — Why does this animate?
  • Timing feels natural — Not too fast/slow
  • Easing matches intent — Curves feel appropriate
  • No janky performance — 60fps on target devices
  • Respects reduced motion — Fallback for a11y
  • Enhances, doesn't distract — User can still focus on task
  • Consistent with brand — Matches motion personality
  • Tested on real devices — Not just desktop/simulator

Troubleshooting

Animation feels too fast

Fix: Increase duration by 50-100ms, use gentler easing curve

Animation feels too slow

Fix: Decrease duration, use sharper easing (higher acceleration)

Animation feels robotic

Fix: Never use linear easing — always use curves with acceleration

Animation causes jank/stuttering

Fix:

  • Animate only transform and opacity
  • Check for forced reflows (width/height/top/left)
  • Use will-change: transform during animation
  • Reduce complexity (fewer elements, simpler paths)

Animation feels disconnected from brand

Fix: Re-check motion personality archetype — adjust duration/easing to match

Multiple animations feel chaotic

Fix: Apply choreography rules — stagger timing, establish hierarchy, group related elements

Animation works on desktop but not mobile

Fix:

  • Reduce duration by 20-30% for mobile
  • Simplify motion paths
  • Test on real devices, not simulators
  • Consider disabling parallax/complex effects on low-end devices

Implementation Examples (Multiple Frameworks)

CSS Animations

/* Entrance animation */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.card-enter {
  animation: fadeInUp 400ms cubic-bezier(0, 0, 0.2, 1);
}

/* Loading pulse */
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.loading {
  animation: pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

React + Framer Motion

import { motion } from 'framer-motion';

function AnimatedCard({ children }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ 
        duration: 0.4,
        ease: [0, 0, 0.2, 1]
      }}
    >
      {children}
    </motion.div>
  );
}

Vue + GSAP

<template>
  <div ref="card" class="card">
    {{ content }}
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { gsap } from 'gsap';

const card = ref(null);

onMounted(() => {
  gsap.from(card.value, {
    opacity: 0,
    y: 20,
    duration: 0.4,
    ease: 'power2.out'
  });
});
</script>

Svelte

<script>
  import { fade, fly } from 'svelte/transition';
  import { cubicOut } from 'svelte/easing';
</script>

<div 
  in:fly={{ y: 20, duration: 400, easing: cubicOut }}
  out:fade={{ duration: 200 }}
>
  Card content
</div>

Angular

import { trigger, state, style, transition, animate } from '@angular/animations';

export const cardAnimation = trigger('cardEnter', [
  transition(':enter', [
    style({ opacity: 0, transform: 'translateY(20px)' }),
    animate('400ms cubic-bezier(0, 0, 0.2, 1)', 
      style({ opacity: 1, transform: 'translateY(0)' })
    )
  ])
]);

// In component
@Component({
  animations: [cardAnimation]
})

Additional Resources

The full skill includes deep-dive documentation in these directories:

  • director/ — Philosophy, decision frameworks, emotion mapping, choreography
  • patterns/ — Ready-to-use recipes for common UI animations
  • reference/ — Timing tables, property guides, troubleshooting

These files provide extended context but the principles above cover 90% of practical motion design decisions.

When to Use This Skill

Activate motion design thinking when:

  • Building interactive UI components (buttons, cards, forms)
  • Implementing state transitions (loading, success, error)
  • Orchestrating multi-element sequences (lists, dashboards)
  • Establishing brand motion identity
  • Reviewing animation code for improvements
  • Debugging janky or unnatural-feeling animations
  • Adapting motion for accessibility or performance

Remember: Always think WHY → WHAT → HOW before writing animation code.