Agent skill
animation-patterns
SwiftUI animation patterns including springs, transitions, PhaseAnimator, KeyframeAnimator, and SF Symbol effects. Use when implementing, reviewing, or fixing animation code on iOS/macOS.
Stars
127
Forks
10
Install this agent skill to your Project
npx add-skill https://github.com/rshankras/claude-code-apple-skills/tree/main/skills/design/animation-patterns
SKILL.md
Animation Patterns
Correct API shapes and patterns for SwiftUI animations. Prevents the most common mistakes: mixed spring parameter generations, wrong PhaseAnimator/KeyframeAnimator closure signatures, and using matchedGeometryEffect where matchedTransitionSource is needed.
When This Skill Activates
Use this skill when the user:
- Asks to add, fix, or review animation code
- Mentions spring, bounce, or snappy animations
- Wants view transitions (insertion/removal, hero, zoom)
- Asks about PhaseAnimator or KeyframeAnimator
- Wants SF Symbol effects (bounce, pulse, wiggle, breathe)
- Mentions matchedGeometryEffect or matchedTransitionSource
- Asks about reduce motion / animation accessibility
- Wants to sequence or chain animations
- Mentions withAnimation, animation completions, or Transaction
Decision Tree
Choose the right reference file based on what the user needs:
What are you animating?
│
├─ A state change (opacity, position, color)
│ └─ → core-animations.md
│ ├─ withAnimation { } — explicit animation
│ ├─ .animation(_:value:) — implicit animation
│ └─ Spring configuration — .spring, .bouncy, .snappy, .smooth
│
├─ A multi-step / sequenced animation
│ └─ → phase-keyframe-animators.md (PhaseAnimator)
│ └─ Cycles through discrete phases automatically or on trigger
│
├─ A complex multi-property animation (scale + rotation + offset)
│ └─ → phase-keyframe-animators.md (KeyframeAnimator)
│ └─ Timeline-based keyframes with per-property tracks
│
├─ A view appearing / disappearing
│ └─ → transitions.md
│ ├─ .transition() — insertion/removal
│ ├─ .contentTransition() — text/symbol changes
│ └─ .asymmetric() — different in/out
│
├─ A hero / zoom navigation transition
│ └─ → transitions.md (matchedTransitionSource section)
│ ├─ iOS 18+: matchedTransitionSource + .navigationTransition(.zoom)
│ └─ iOS 14+: matchedGeometryEffect (NOT for NavigationStack)
│
├─ An SF Symbol animation
│ └─ → symbol-effects.md
│ └─ .symbolEffect(.bounce), .pulse, .wiggle, .breathe, .rotate
│
└─ Spring physics / timing configuration
└─ → core-animations.md (Spring Configurations section)
API Availability
| API | Minimum Version | Reference |
|---|---|---|
withAnimation |
iOS 13 | core-animations.md |
.animation(_:value:) |
iOS 13 | core-animations.md |
.spring(response:dampingFraction:) |
iOS 13 | core-animations.md |
.matchedGeometryEffect |
iOS 14 | transitions.md |
.transition(.push(from:)) |
iOS 16 | transitions.md |
.contentTransition(.numericText()) |
iOS 16 | transitions.md |
PhaseAnimator |
iOS 17 | phase-keyframe-animators.md |
KeyframeAnimator |
iOS 17 | phase-keyframe-animators.md |
.spring(duration:bounce:) |
iOS 17 | core-animations.md |
Spring presets (.bouncy, .snappy, .smooth) |
iOS 17 | core-animations.md |
withAnimation(_:completionCriteria:_:completion:) |
iOS 17 | core-animations.md |
.symbolEffect() |
iOS 17 | symbol-effects.md |
.transition(.blurReplace) |
iOS 17 | transitions.md |
.contentTransition(.symbolEffect(.replace)) |
iOS 17 | transitions.md |
.matchedTransitionSource |
iOS 18 | transitions.md |
.navigationTransition(.zoom) |
iOS 18 | transitions.md |
Top 5 Mistakes — Quick Reference
| # | Mistake | Fix | Details |
|---|---|---|---|
| 1 | spring(response:bounce:) — mixing parameter generations |
Use either spring(response:dampingFraction:) (iOS 13) or spring(duration:bounce:) (iOS 17) |
core-animations.md |
| 2 | .animation(.spring()) without value: parameter |
Always pass value: — the no-value variant is deprecated (iOS 15) |
core-animations.md |
| 3 | Wrong PhaseAnimator closure signature | PhaseAnimator(phases) { content, phase in } — not { phase in } |
phase-keyframe-animators.md |
| 4 | Using matchedGeometryEffect for NavigationStack transitions |
Use matchedTransitionSource + .navigationTransition(.zoom) on iOS 18+ |
transitions.md |
| 5 | Using withAnimation for SF Symbol effects |
Use .symbolEffect() modifier instead |
symbol-effects.md |
Review Checklist
When reviewing animation code, verify:
- Reduce motion — animations respect
AccessibilityMotionEffectorUIAccessibility.isReduceMotionEnabled; provide non-motion alternatives - Duration limits — no animation exceeds ~0.5s for UI feedback; longer only for decorative/ambient effects
- Spring vs linear — springs for interactive/physical motion; linear/easeInOut only for opacity fades or progress indicators
- No deprecated APIs —
.animation(.spring())withoutvalue:is deprecated;.animation(nil)is replaced bywithTransaction - Correct spring generation — parameter names match the same API generation (never mix
responsewithbounce) - Completion handlers — using
withAnimation(_:completionCriteria:_:completion:)(iOS 17+), not inventing.onAnimationCompleted - Transition scope —
.transition()only affects views insideif/switchcontrolled by state; not for views that are always present
Reference Files
| File | Content |
|---|---|
| core-animations.md | withAnimation, springs, completions, transactions, timing curves |
| phase-keyframe-animators.md | PhaseAnimator, KeyframeAnimator, custom animations |
| transitions.md | View transitions, matched geometry, navigation transitions |
| symbol-effects.md | SF Symbol effects, accessibility |
Didn't find tool you were looking for?