| name | motion |
| description | Material motion - meaningful animation, physical metaphors |
Matías Duarte - Motion Design
Animation is not decoration. Motion communicates relationships, hierarchy, and state changes.
Core Philosophy
Motion is Meaning
Every animation must answer: "What does this motion communicate?"
If the answer is "it looks cool" - remove it.
Physical Metaphors
Digital objects should feel like they have mass and respond to physics:
- Heavy objects move slower
- Light objects move faster
- Objects accelerate and decelerate (no linear motion)
- Objects don't teleport - they travel through space
Choreography
Multiple moving elements must be coordinated:
- Staggered, not simultaneous
- Parent leads, children follow
- Same direction = same intent
Motion Principles
1. Responsive
Acknowledge user input instantly.
.button:active {
transform: scale(0.98);
transition: transform 0.05s ease-out;
}
2. Natural
Use easing that mimics physical objects.
--ease-out: cubic-bezier(0.0, 0.0, 0.2, 1);
--ease-in: cubic-bezier(0.4, 0.0, 1, 1);
--ease-in-out: cubic-bezier(0.4, 0.0, 0.2, 1);
3. Aware
Elements know about each other.
.card.expanded ~ .card {
transform: translateY(100px);
transition: transform 0.3s var(--ease-out);
}
4. Intentional
Motion creates hierarchy and focus.
.modal {
animation: modal-enter 0.3s var(--ease-out);
}
@keyframes modal-enter {
from {
opacity: 0;
transform: scale(0.95) translateY(10px);
}
}
Prescriptive Rules
Duration Scale
--duration-instant: 50ms;
--duration-fast: 150ms;
--duration-normal: 300ms;
--duration-slow: 500ms;
Easing Usage
| Motion Type | Easing | Duration |
|---|
| Element entering | ease-out | 300ms |
| Element exiting | ease-in | 200ms |
| Element moving on-screen | ease-in-out | 300ms |
| Hover state | ease-out | 150ms |
| Button press | ease-out | 50ms |
Transform Order
.element {
transform: translate() scale() rotate();
}
.card {
transform-origin: center center;
}
Stagger Pattern
items.forEach((item, i) => {
item.style.animationDelay = `${i * 50}ms`;
});
Enter/Exit Asymmetry
.modal-enter {
animation: fade-in 0.3s ease-out,
slide-up 0.3s ease-out;
}
.modal-exit {
animation: fade-out 0.2s ease-in;
}
Common Patterns
Fade
.fade-enter {
opacity: 0;
animation: fade-in 0.2s ease-out forwards;
}
@keyframes fade-in {
to { opacity: 1; }
}
Slide
.slide-enter {
transform: translateY(20px);
opacity: 0;
animation: slide-in 0.3s ease-out forwards;
}
@keyframes slide-in {
to {
transform: translateY(0);
opacity: 1;
}
}
Scale
.scale-enter {
transform: scale(0.95);
opacity: 0;
animation: scale-in 0.2s ease-out forwards;
}
@keyframes scale-in {
to {
transform: scale(1);
opacity: 1;
}
}
Expand/Collapse
.expandable {
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.expandable.closed {
max-height: 0;
}
.expandable.open {
max-height: 500px;
}
When NOT to Animate
- User has
prefers-reduced-motion enabled
- Repeated actions (don't animate every keystroke)
- Background/utility actions (auto-save)
- When animation would delay task completion
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
Review Checklist
Anti-Patterns
| Bad | Why | Fix |
|---|
| Linear easing | Robotic, unnatural | Use ease-out/ease-in |
| > 500ms duration | Feels slow, blocking | Speed up |
| Bounce/elastic | Playful but distracting | Simple ease curves |
| Animation on scroll | Janky, performance issue | Use sparingly |
| Animation blocking input | Frustrating | Allow interruption |
| Same duration in/out | Exit should be faster | Asymmetric timing |
Duarte Score
| Score | Meaning |
|---|
| 10 | Motion is communication, never decoration |
| 7-9 | Purposeful but some unnecessary animation |
| 4-6 | Decorative animation, inconsistent timing |
| 0-3 | Distracting, janky, or blocks interaction |
Integration
Combine with:
/visual - Material properties that motion must respect
/usability - Feedback timing requirements
/interaction - Input response expectations