Motion Design Guidelines
Status: Complete Animation System
Version: 1.0.0
Verified: Performance optimized
Executive Summary
Motion brings interfaces to lifeβthoughtful animation guides attention, provides feedback, and creates delightful experiences. Our motion system balances personality with performance, ensuring every animation has purpose while maintaining 60fps smoothness.
Motion Philosophy
| Principle | Implementation | User Impact |
|---|---|---|
| Purposeful | Every animation has a job | Clearer understanding |
| Performant | 60fps on all devices | Smooth experience |
| Natural | Physics-based easing | Feels intuitive |
| Accessible | Respects preferences | Inclusive for all |
| Subtle | Enhance, don't distract | Focus on content |
Motion Architecture
Section 1: Timing & Easing (800 words)
Duration Scale
Our timing system creates consistent, predictable animations that feel natural and responsive.
Systematic timing scale for consistent animation feel
Duration Tokens
:root {
/* Duration scale */
--duration-instant: 50ms; /* Immediate feedback */
--duration-micro: 100ms; /* Tiny interactions */
--duration-fast: 150ms; /* Quick responses */
--duration-normal: 250ms; /* Standard transitions */
--duration-moderate: 350ms; /* Complex animations */
--duration-slow: 500ms; /* Page transitions */
--duration-slower: 700ms; /* Elaborate effects */
--duration-slowest: 1000ms; /* Special occasions */
}
Duration Guidelines:
| Animation Type | Duration | Use Cases |
|---|---|---|
| Hover states | 100-150ms | Buttons, links, cards |
| Focus states | 150ms | Form inputs, buttons |
| Toggles | 200ms | Switches, checkboxes |
| Dropdowns | 250ms | Menus, selects |
| Modals | 300ms | Dialogs, overlays |
| Page transitions | 350-500ms | Route changes |
| Loading | Continuous | Progress indicators |
Easing Functions
:root {
/* Natural easing curves */
--ease-linear: linear;
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
/* Expressive curves */
--ease-spring: cubic-bezier(0.5, 1.5, 0.5, 1);
--ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
--ease-elastic: cubic-bezier(0.68, -0.6, 0.32, 1.6);
/* Entrance/exit curves */
--ease-enter: var(--ease-out);
--ease-exit: var(--ease-in);
}
Easing Selection Guide:
// Choose easing based on animation purpose
const easingGuide = {
// Objects entering view
enter: 'ease-out', // Decelerate into place
// Objects leaving view
exit: 'ease-in', // Accelerate away
// State changes
transition: 'ease-in-out', // Smooth both ways
// Playful feedback
bounce: 'ease-bounce', // Overshoot effect
// Continuous motion
loop: 'linear' // Constant speed
};
Motion Curves Visualized
/* Real-world examples */
.button {
transition: all var(--duration-fast) var(--ease-out);
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
&:active {
transition-duration: var(--duration-micro);
transform: translateY(0);
}
}
.modal {
animation: modalEnter var(--duration-moderate) var(--ease-spring);
}
@keyframes modalEnter {
from {
opacity: 0;
transform: scale(0.9) translateY(20px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
Section 2: Micro-interactions (700 words)
Interactive Feedback
Micro-interactions provide immediate feedback for user actions, making interfaces feel responsive and alive.
Subtle micro-interactions enhancing user feedback
Hover Interactions
/* Button hover elevation */
.interactive-element {
transition: transform var(--duration-fast) var(--ease-out),
box-shadow var(--duration-fast) var(--ease-out);
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
}
/* Link underline animation */
.link {
position: relative;
&::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: currentColor;
transition: width var(--duration-normal) var(--ease-out);
}
&:hover::after {
width: 100%;
}
}
Click Feedback
/* Ripple effect */
.ripple {
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
transform: translate(-50%, -50%);
transition: width var(--duration-moderate) var(--ease-out),
height var(--duration-moderate) var(--ease-out);
}
&:active::before {
width: 100px;
height: 100px;
}
}
/* Press feedback */
.pressable {
transition: transform var(--duration-micro) var(--ease-out);
&:active {
transform: scale(0.98);
}
}
State Changes
/* Toggle switch */
.switch {
.slider {
transition: transform var(--duration-fast) var(--ease-spring);
transform: translateX(0);
}
&.is-on .slider {
transform: translateX(20px);
}
}
/* Checkbox animation */
.checkbox {
.checkmark {
stroke-dasharray: 30;
stroke-dashoffset: 30;
transition: stroke-dashoffset var(--duration-normal) var(--ease-out);
}
input:checked ~ .checkmark {
stroke-dashoffset: 0;
}
}
Section 3: Page Transitions (700 words)
Navigation Animations
Smooth transitions between pages and sections maintain context and orientation.
Contextual page transitions maintaining spatial relationships
Route Transitions
/* Fade transition */
.page-fade-enter {
opacity: 0;
}
.page-fade-enter-active {
opacity: 1;
transition: opacity var(--duration-moderate) var(--ease-out);
}
.page-fade-exit {
opacity: 1;
}
.page-fade-exit-active {
opacity: 0;
transition: opacity var(--duration-fast) var(--ease-in);
}
/* Slide transition */
.page-slide-enter {
transform: translateX(100%);
}
.page-slide-enter-active {
transform: translateX(0);
transition: transform var(--duration-slow) var(--ease-out);
}
.page-slide-exit-active {
transform: translateX(-20%);
opacity: 0;
transition: all var(--duration-slow) var(--ease-in);
}
πͺ Modal Animations
/* Modal entrance */
@keyframes modalEnter {
from {
opacity: 0;
transform: scale(0.95) translateY(10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
/* Backdrop fade */
@keyframes backdropFade {
from { opacity: 0; }
to { opacity: 1; }
}
.modal {
animation: modalEnter var(--duration-moderate) var(--ease-spring);
}
.modal-backdrop {
animation: backdropFade var(--duration-fast) var(--ease-out);
}
Tab Transitions
// Tab content transitions
const tabTransition = {
'.tab-panel': {
position: 'relative',
'&.entering': {
animation: 'tabEnter 300ms ease-out'
},
'&.exiting': {
animation: 'tabExit 200ms ease-in',
position: 'absolute',
top: 0,
left: 0,
right: 0
}
}
};
// Directional awareness
const getTabAnimation = (oldIndex, newIndex) => {
return oldIndex < newIndex ? 'slideLeft' : 'slideRight';
};
Section 4: Loading & Progress (600 words)
Loading States
Loading animations maintain engagement during wait times while setting accurate expectations.
Progressive loading patterns for different contexts
Skeleton Screens
/* Skeleton pulse animation */
@keyframes skeletonPulse {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
.skeleton {
background: linear-gradient(
90deg,
var(--gray-200) 25%,
var(--gray-100) 50%,
var(--gray-200) 75%
);
background-size: 200% 100%;
animation: skeletonPulse 1.5s ease-in-out infinite;
}
Progress Indicators
/* Determinate progress */
.progress-bar {
.fill {
transition: width var(--duration-moderate) var(--ease-out);
transform-origin: left;
}
}
/* Indeterminate progress */
.progress-indeterminate {
.fill {
animation: progressSlide 1.5s ease-in-out infinite;
}
}
@keyframes progressSlide {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(200%);
}
}
/* Circular spinner */
.spinner {
animation: rotate 1s linear infinite;
.circle {
stroke-dasharray: 150;
stroke-dashoffset: 0;
animation: dash 1.5s ease-in-out infinite;
}
}
@keyframes dash {
0% {
stroke-dashoffset: 150;
}
50% {
stroke-dashoffset: 45;
}
100% {
stroke-dashoffset: 150;
}
}
Section 5: Gesture Animations (500 words)
Touch Interactions
Gesture-based animations provide natural feedback for touch interfaces.
Natural gesture responses for touch interfaces
Swipe Actions
// Swipe to delete
const swipeAnimation = {
threshold: 100, // pixels
onSwipe: (distance) => {
const progress = Math.min(distance / threshold, 1);
element.style.transform = `translateX(${distance}px)`;
element.style.opacity = 1 - progress * 0.5;
},
onRelease: (distance) => {
if (distance > threshold) {
// Complete action
element.style.transition = 'all 200ms ease-out';
element.style.transform = 'translateX(100%)';
element.style.opacity = '0';
} else {
// Snap back
element.style.transition = 'all 200ms ease-out';
element.style.transform = 'translateX(0)';
element.style.opacity = '1';
}
}
};
Pull to Refresh
.pull-to-refresh {
.indicator {
transform: translateY(-100%);
transition: transform var(--duration-normal) var(--ease-out);
&.pulling {
transform: translateY(0);
transition: none;
}
&.refreshing {
animation: spin 1s linear infinite;
}
}
}
Section 6: Accessibility & Performance (400 words)
Motion Accessibility
Respecting user preferences ensures animations enhance rather than hinder the experience.
Accessibility
- Respect prefers-reduced-motion
- Provide pause controls
- Avoid flashing
- Ensure readability during motion
- Test with screen readers
Performance
- Use transform & opacity only
- Enable GPU acceleration
- Batch animations
- Test on low-end devices
- Monitor frame rates
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;
}
/* Keep essential motion */
.spinner {
animation-duration: 1s !important;
}
}
Performance Optimization
/* GPU acceleration */
.animated {
will-change: transform;
transform: translateZ(0);
}
/* Clean up after animation */
.animation-complete {
will-change: auto;
}
Conclusion
Motion is the soul of interaction. Our comprehensive motion system creates interfaces that feel alive and responsive while maintaining performance and accessibility. Every animation serves a purpose, guiding users naturally through their journey.
Next Steps
- Review Component Library for motion in practice
- Explore Design Tokens for animation variables
- Test with Performance Tools
This motion system ensures NudgeCampaign feels delightful and responsive while respecting user preferences and device capabilities.