SwiftUI & AppKit Animation Best Practices
Comprehensive animation guide for Apple platform interfaces, adapted from Emil Kowalski's web animation principles and Framer Motion best practices. Contains 80 rules across 10 categories targeting iOS 17+, prioritized by impact.
When to Apply
Reference these guidelines when:
- •Adding animations to SwiftUI views
- •Choosing easing curves, springs, or timing values
- •Implementing gesture-based interactions (drag, tap, long press)
- •Building transitions and navigation animations
- •Using
matchedGeometryEffectfor shared element transitions - •Creating scroll-linked or parallax effects
- •Using iOS 17+
PhaseAnimatororKeyframeAnimator - •Optimizing animation performance
- •Ensuring animation accessibility with
accessibilityReduceMotion - •Writing AppKit/macOS-specific animations
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Timing Curves & Easing | CRITICAL | ease- |
| 2 | Duration & Timing | CRITICAL | timing- |
| 3 | Animation Properties | HIGH | props- |
| 4 | Transforms & Effects | HIGH | transform- |
| 5 | Gesture & Interaction | HIGH | gesture- |
| 6 | Transitions & Navigation | MEDIUM-HIGH | transition- |
| 7 | Scroll & Parallax | MEDIUM | scroll- |
| 8 | Strategic Animation | MEDIUM | strategy- |
| 9 | Accessibility & Polish | MEDIUM | polish- |
| 10 | AppKit Specific | LOW-MEDIUM | appkit- |
Quick Reference
1. Timing Curves & Easing (CRITICAL)
- •
ease-prefer-easeout- Use easeOut as your default easing - •
ease-avoid-linear- Avoid linear easing for UI animations - •
ease-spring-default- Prefer springs for natural motion - •
ease-spring-ios17- Use iOS 17 Spring struct with bounce/duration - •
ease-custom-timing-curve- Create custom curves with timingCurve - •
ease-ease-in-for-exits- Use easeIn for exit animations - •
ease-ease-inout-for-emphasis- Use easeInOut for emphasis motion - •
ease-spring-response- Configure spring response for duration feel - •
ease-spring-damping- Configure spring damping for bounce - •
ease-match-context- Match easing to animation context
2. Duration & Timing (CRITICAL)
- •
timing-200ms-default- Use 200ms as default UI animation duration - •
timing-100ms-micro- Use 100ms for micro-interactions - •
timing-300ms-emphasis- Keep emphasis animations under 300ms - •
timing-stagger-children- Stagger child animations for orchestration - •
timing-delay-strategic- Use delay strategically for sequencing
3. Animation Properties (HIGH)
- •
props-opacity-scale- Prefer opacity and scale for performance - •
props-avoid-size-animate- Avoid animating frame size directly - •
props-transform-origin- Set anchor points for transforms - •
props-drawing-group- Use drawingGroup for complex hierarchies - •
props-animation-disable- Use animation(nil) to prevent animations - •
props-explicit-animation- Use withAnimation for explicit control - •
props-implicit-animation- Use .animation modifier for implicit animations
4. Transforms & Effects (HIGH)
- •
transform-scale-subtle- Use subtle scale values (0.95-0.98) - •
transform-rotation-purposeful- Apply rotation with purpose - •
transform-translate-direction- Translate in meaningful directions - •
transform-3d-perspective- Use rotation3DEffect for depth - •
transform-order-matters- Modifier order affects output - •
transform-anchor-point- Set anchor for rotation/scale origin - •
transform-combine-effects- Combine transforms purposefully
5. Gesture & Interaction (HIGH)
- •
gesture-tap-feedback- Provide immediate tap feedback - •
gesture-long-press- Animate long press states - •
gesture-drag-basic- Implement smooth drag interactions - •
gesture-drag-constraints- Constrain drag within bounds - •
gesture-drag-velocity- Use velocity for momentum effects - •
gesture-gesture-state- Use @GestureState for transient values - •
gesture-updating-modifier- Use .updating for live feedback - •
gesture-simultaneous-vs-exclusive- Choose gesture composition - •
gesture-magnify-gesture- Implement pinch-to-zoom - •
gesture-rotation-gesture- Implement rotation gestures - •
gesture-hover-macos- Handle hover on macOS - •
gesture-sensory-feedback- Pair gestures with haptics - •
gesture-spring-on-release- Spring back on gesture end - •
gesture-cancellation- Handle gesture cancellation gracefully
6. Transitions & Navigation (MEDIUM-HIGH)
- •
transition-builtin-types- Use built-in transition types - •
transition-asymmetric- Use asymmetric for different enter/exit - •
transition-combined- Combine transitions for richer effects - •
transition-custom-modifier- Create custom transition modifiers - •
transition-matched-geometry- Use matchedGeometryEffect properly - •
transition-namespace-scope- Manage @Namespace lifecycle - •
transition-navigation-transitions- Customize navigation transitions - •
transition-sheet-presentations- Animate sheet presentations - •
transition-id-for-replacement- Use .id() for view replacement - •
transition-content-transition- Use contentTransition for text
7. Scroll & Parallax (MEDIUM)
- •
scroll-geometry-reader- Use GeometryReader for scroll position - •
scroll-preference-key- Use PreferenceKey for scroll data - •
scroll-parallax-effect- Create parallax scroll effects - •
scroll-sticky-header- Implement animated sticky headers - •
scroll-scroll-transition- Use iOS 17 scrollTransition modifier - •
scroll-visual-effect- Use iOS 17 visualEffect modifier
8. Strategic Animation (MEDIUM)
- •
strategy-purposeful-motion- Every animation needs purpose - •
strategy-hierarchy-emphasis- Use motion to show hierarchy - •
strategy-state-communication- Animate state changes clearly - •
strategy-spatial-continuity- Maintain spatial relationships - •
strategy-brand-expression- Express brand through motion
9. Accessibility & Polish (MEDIUM)
- •
polish-reduce-motion- Respect accessibilityReduceMotion - •
polish-phase-animator- Use PhaseAnimator for sequences - •
polish-keyframe-animator- Use KeyframeAnimator for complex paths - •
polish-animation-completions- Handle animation completion - •
polish-interruptible-animations- Make animations interruptible - •
polish-animation-debugging- Debug animations effectively - •
polish-performance-profiling- Profile animation performance - •
polish-symbol-effects- Use SF Symbol effects - •
polish-text-animations- Animate text with contentTransition - •
polish-haptic-pairing- Pair animations with haptic feedback
10. AppKit Specific (LOW-MEDIUM)
- •
appkit-nsanimation-context- Use NSAnimationContext for grouping - •
appkit-core-animation- Use Core Animation layers - •
appkit-layer-backed-views- Enable layer backing for performance - •
appkit-implicit-animations- Leverage implicit layer animations - •
appkit-spring-animation- Create spring animations in AppKit - •
appkit-animator-proxy- Use animator proxy for view animations
Key Values Reference
| Value | Usage |
|---|---|
.spring(duration: 0.3, bounce: 0.2) | Standard iOS 17 spring animation |
.spring(response: 0.3, dampingFraction: 0.7) | Classic spring configuration |
.easeOut(duration: 0.2) | Standard UI transition |
scaleEffect(0.97) | Button press feedback |
scaleEffect(0.95) | Minimum enter scale (never scale to 0) |
0.2 seconds | Default micro-interaction duration |
0.3 seconds | Maximum duration for UI animations |
0.5 seconds | Sheet/drawer animation duration |
Concept Mapping (Web to SwiftUI)
| Web Concept | SwiftUI Equivalent |
|---|---|
ease-out | .easeOut or Animation.easeOut(duration:) |
cubic-bezier(a,b,c,d) | .timingCurve(a, b, c, d, duration:) |
| Framer Motion spring | .spring(duration:bounce:) (iOS 17+) |
transform: scale(0.97) | .scaleEffect(0.97) |
transform-origin | .scaleEffect(anchor: .topLeading) |
useMotionValue | @State / @GestureState |
AnimatePresence | .transition() + .id() |
layoutId | .matchedGeometryEffect(id:in:) |
useScroll | GeometryReader + PreferenceKey |
whileHover/whileTap | .onHover {} / gesture modifiers |
dragConstraints | DragGesture with onChange bounds |
prefers-reduced-motion | @Environment(\.accessibilityReduceMotion) |
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for new rules |
| metadata.json | Version and reference information |