Motion Design Principles¶
Our motion system creates a sophisticated, cohesive experience that enhances usability while delighting users. Every animation serves a purpose, guiding attention and providing feedback.
Animation Philosophy¶
Core Principles¶
1. Purposeful Motion¶
Every animation must serve a clear purpose: - Guide Attention: Direct focus to important elements - Provide Feedback: Confirm user actions - Reveal Relationships: Show how elements are connected - Enhance Personality: Express brand character
2. Natural Movement¶
Animations should feel organic and physics-based: - Use spring physics for playful interactions - Apply exponential easing for smooth transitions - Respect object weight and momentum - Create believable motion paths
3. Performance First¶
Smooth performance is non-negotiable: - Target 60fps for all animations - Use CSS transforms and opacity - Leverage GPU acceleration - Optimize for mobile devices
4. Accessible by Default¶
Respect user preferences and needs:
- Honor prefers-reduced-motion
- Provide motion alternatives
- Ensure functionality without animation
- Keep animations subtle and non-distracting
Timing Guidelines¶
Duration Scale¶
/* Our duration tokens */
--motion-duration-instant: 50ms; /* Immediate feedback */
--motion-duration-fast: 150ms; /* Micro-interactions */
--motion-duration-normal: 250ms; /* Standard transitions */
--motion-duration-slow: 350ms; /* Complex animations */
--motion-duration-slower: 500ms; /* Page transitions */
--motion-duration-slowest: 700ms; /* Elaborate sequences */
When to Use Each Duration¶
Instant (50ms)¶
- Active/pressed states
- Immediate visual feedback
- Tooltip appearances
Fast (150ms)¶
- Hover states
- Small UI element transitions
- Icon animations
Normal (250ms)¶
- Most UI transitions
- Fade in/out effects
- Standard reveals
Slow (350ms)¶
- Modal appearances
- Complex state changes
- Accordion expansions
Slower (500ms)¶
- Page transitions
- Large content reveals
- Stagger animation sequences
Slowest (700ms)¶
- Loading animations
- Complex choreographed sequences
- Initial page load animations
Easing Guidelines¶
Our Easing Curves¶
Ease Out Expo - Primary Easing¶
Use for most enter animations. Creates smooth deceleration.Ease In Expo - Exit Animations¶
Use for elements leaving the screen. Quick acceleration.Spring Physics - Playful Motion¶
Use for delightful micro-interactions. Slight overshoot.Ease In Out Quart - Smooth Transitions¶
Use for continuous motion like scrolling or dragging.Motion Choreography¶
Stagger Patterns¶
Sequential Reveal¶
Elements appear one after another:
.stagger-item:nth-child(1) { animation-delay: 0ms; }
.stagger-item:nth-child(2) { animation-delay: 50ms; }
.stagger-item:nth-child(3) { animation-delay: 100ms; }
Diagonal Grid¶
Create visual flow in grid layouts:
// Top-left to bottom-right
.grid-item:nth-child(1) { animation-delay: 0ms; }
.grid-item:nth-child(2) { animation-delay: 50ms; }
.grid-item:nth-child(4) { animation-delay: 50ms; }
.grid-item:nth-child(3) { animation-delay: 100ms; }
Center Outward¶
Radiate from a focal point:
Transition Patterns¶
Crossfade¶
Smooth content replacement:
.crossfade-exit {
animation: fadeOut 250ms ease-in;
}
.crossfade-enter {
animation: fadeIn 250ms ease-out;
}
Shared Element¶
Maintain visual continuity:
// Track element position
const startPos = element.getBoundingClientRect();
// Animate to new position
element.animate([
{ transform: `translate(${startX}px, ${startY}px)` },
{ transform: 'translate(0, 0)' }
], { duration: 300, easing: 'ease-out' });
Morphing¶
Transform between states:
.morph {
transition: all 350ms var(--motion-ease-out-expo);
transition-property: transform, border-radius, background;
}
Performance Considerations¶
Optimization Techniques¶
Use Transform & Opacity¶
These properties are GPU-accelerated:
/* Good - Hardware accelerated */
.animate {
transform: translateY(20px);
opacity: 0;
}
/* Avoid - Causes reflow */
.animate {
top: 20px;
display: none;
}
Will-Change Property¶
Hint browser optimizations:
.will-animate {
will-change: transform, opacity;
}
/* Remove after animation */
.animated {
will-change: auto;
}
Contain Layout¶
Isolate animation impact:
Mobile Optimization¶
Reduce Complexity¶
Simplify animations on mobile:
Touch Feedback¶
Immediate response to touch:
Implementation Examples¶
Hero Animation Sequence¶
// Choreographed hero entrance
class HeroAnimator {
animate() {
const timeline = [
{ element: '.hero-title', animation: 'fadeInDown', delay: 0 },
{ element: '.hero-subtitle', animation: 'fadeInUp', delay: 100 },
{ element: '.hero-cta', animation: 'scaleIn', delay: 200 },
{ element: '.hero-image', animation: 'fadeIn', delay: 300 }
];
timeline.forEach(({ element, animation, delay }) => {
setTimeout(() => {
document.querySelector(element)?.classList.add(animation);
}, delay);
});
}
}
Scroll-Triggered Animation¶
// Reveal elements on scroll
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -100px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('in-view');
}
});
}, observerOptions);
document.querySelectorAll('.scroll-animate').forEach(el => {
observer.observe(el);
});
Micro-Interaction Example¶
/* Button with spring physics */
.button {
transition: all 150ms var(--motion-spring-gentle);
}
.button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
.button:active {
transform: translateY(0);
transition-duration: 50ms;
}
Page Transition¶
// Smooth page transitions
class PageTransition {
async navigate(url) {
// Exit animation
document.body.classList.add('page-exit');
await this.wait(250);
// Load new content
const content = await this.fetchContent(url);
this.updateDOM(content);
// Enter animation
document.body.classList.remove('page-exit');
document.body.classList.add('page-enter');
}
}
Accessibility Guidelines¶
Reduced Motion Support¶
/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
/* Provide alternative feedback */
.animated-element {
opacity: 1;
transform: none;
}
}
Focus Indicators¶
/* Animated focus states */
.focus-visible:focus {
outline: none;
animation: focusRing 200ms ease-out;
}
@keyframes focusRing {
from {
box-shadow: 0 0 0 0 var(--color-primary);
}
to {
box-shadow: 0 0 0 4px var(--color-primary-alpha);
}
}
Testing & Debugging¶
Performance Monitoring¶
// Monitor animation performance
const perfObserver = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.duration > 16.67) { // Below 60fps
console.warn('Animation frame dropped:', entry);
}
});
});
perfObserver.observe({ entryTypes: ['measure'] });
Debug Mode¶
/* Slow down animations for debugging */
.debug-motion * {
animation-duration: 3s !important;
transition-duration: 3s !important;
}
Motion System Checklist¶
- Every animation has a clear purpose
- Timing feels natural and appropriate
- Performance is consistently 60fps
- Reduced motion preferences are respected
- Animations enhance rather than distract
- Touch interactions feel responsive
- Loading states are smooth and informative
- Page transitions maintain context
- Focus states are clearly visible
- Motion creates a cohesive experience
Remember: Great motion design is felt, not seen. When done right, users will feel your interface is fast, smooth, and delightful without consciously noticing the animations.