swiftui-animation
Implement, diagnose, or review SwiftUI motion using explicit and scoped implicit animations, springs, transitions, PhaseAnimator, KeyframeAnimator, matched geometry or navigation zoom, SF Symbol effects, and custom Animation types. Use when views should animate on state changes, insertion, removal,
By dpearson2699 · 4,614 installs
npx skills add dpearson2699/swift-ios-skills --skill swiftui-animation
Source repository · Upstream listing
SwiftUI Animation (iOS 26+)
Review, write, and fix SwiftUI animations. Apply modern animation APIs with
correct timing, transitions, and accessibility handling using Swift 6.3 patterns.
Contents
[Triage Workflow]( triage workflow)
[withAnimation (Explicit Animation)]( withanimation explicit animation)
[Implicit Animation]( implicit animation)
[Spring Type (iOS 17+)]( spring type ios 17)
[PhaseAnimator (iOS 17+)]( phaseanimator ios 17)
[KeyframeAnimator (iOS 17+)]( keyframeanimator ios 17)
[ @Animatable Macro ]( animatable macro)
[matchedGeometryEffect (iOS 14+)]( matchedgeometryeffect ios 14)
[Navigation Zoom Transition (iOS 18+)]( navigation zoom transition ios 18)
[Transitions (iOS 17+)]( transitions ios 17)
[ContentTransition (iOS 16+)]( contenttransition ios 16)
[Symbol Effects (iOS 17+)]( symbol effects ios 17)
[Symbol Rendering Modes]( symbol rendering modes)
[Common Mistakes]( common mistakes)
[Review Checklist]( review checklist)
[References]( references)
Triage Workflow
Step 1: Identify the animation category
Category API When to use
State driven withAnimation , .animation( :body:) , .animation( :value:) Explicit state changes, selective modifier animation, or simple value bound changes
Multi phase PhaseAnimator Sequenced multi step animations
Keyframe KeyframeAnimator Complex multi property choreography
Shared element matchedGeometryEffect Layout driven hero transitions
Navigation matchedTransitionSource + .navigationTransition(.zoom) NavigationStack push/pop zoom
View lifecycle .transition() Insertion and removal
Text content .contentTransition() In place text/number changes
Symbol .symbolEffect() SF Symbol animations
Custom CustomAnimation protocol Novel timing curves
Core Animation bridge CALayer , CAAnimation , CADisplayLink Read references/core animation bridge.md before advising
Step 2: Choose the animation curve
Use [the advanced catalog](references/animation advanced.md spring type all initializer variants)
when presets do not express the intended motion.
Step 3: Apply and verify
Confirm animation triggers on the correct state change.
Test with Accessibility Reduce Motion enabled.
Verify no expensive work runs inside animation content closures.
For CA bridges, use Coordinators for delegates, invalidate display links, treat frame rate ranges as hints, and adapt work to the actual refresh rate.
withAnimation (Explicit Animation)
Implicit Animation
Use withAnimation for state mutation ownership, .animation( :body:) for
selected modifiers, and .animation( :value:) for simple value bound changes.
Spring Type (iOS 17+)
Prefer the perceptual form or a preset. Load the advanced reference only when
physical, response based, or settling parameters are required.
PhaseAnimator (iOS 17+)
Cycle through discrete phases with per phase animation curves.
Trigger based variant advances to the next phase on each trigger change:
KeyframeAnimator (iOS 17+)
Animate multiple properties along independent timelines.
Keyframe types: LinearKeyframe (linear), CubicKeyframe (smooth curve),
SpringKeyframe (spring physics), MoveKeyframe (instant jump).
Use repeating: true for looping keyframe animations.
Swift 6: keyframe closures are @Sendable ; capture state/env values before the modifier.
@Animatable Macro
Replaces manual AnimatableData boilerplate. Attach to any type with
animatable stored properties.
Rules:
Stored properties must conform to VectorArithmetic .
Use @AnimatableIgnored to exclude non animatable properties.
Computed properties are never included.
matchedGeometryEffect (iOS 14+)
Synchronize geometry between views for shared element animations.
Exactly one source view per ID should be visible; otherwise results are undefined.
Navigation Zoom Transition (iOS 18+)
Pair matchedTransitionSource on the source view with
.navigationTransition(.zoom(...)) on the destination.
Apply .navigationTransition on the destination view, not on inner containers.
Transitions (iOS 17+)
Control how views animate on insertion and removal.
See [All Transition Types](references/animation advanced.md all transition types ios 17)
for the built in catalog and custom Transition examples.
Asymmetric transitions:
ContentTransition (iOS 16+)
Animate in place content changes without insertion/removal.
Types: .identity , .interpolate , .opacity ,
.numericText(countsDown:) , .numericText(value:) , .symbolEffect .
Symbol Effects (iOS 17+)
Animate SF Symbols with semantic effects. .bounce , .pulse , .variableColor ,
.scale , .appear , .disappear , and .replace are iOS 17+; .breathe ,
.rotate , and .wiggle require iOS 18+.
Scope: .byLayer , .wholeSymbol . Direction varies per effect.
Symbol Rendering Modes
Choose .monochrome , .hierarchical , .multicolor , or .palette with
.symbolRenderingMode( :) ; use .foregroundStyle to supply palette colors.
Variable symbols: use Image(systemName:variableValue:) (iOS 16+) for percentage fill. Use .symbolVariableValueMode( :) (iOS 26+) to choose .draw or .color .
Docs: [SymbolRenderingMode](https://sosumi.ai/documentation/swiftui/symbolrenderingmode) · [symbolRenderingMode( :)](https://sosumi.ai/documentation/swiftui/view/symbolrenderingmode( :)) · [Image(systemName:variableValue:)](https://sosumi.ai/documentation/swiftui/image/init(systemname:variablevalue:)) · [symbolVariableValueMode( :)](https://sosumi.ai/documentation/swiftui/view/symbolvariablevaluemode( :))
Common Mistakes
1. Using bare .animation( :) when you need precise scope
2. Expensive work or actor isolated reads inside animation closures
keyframeAnimator / PhaseAnimator content closures run every frame. Precompute expensive values, animate only visual properties, and capture state/env values before @Sendable keyframe closures.
3. Missing reduce motion support
For symbols, remove inherited effects; gate larger motion with reduceMotion ? .none : animation .
4. Multiple matchedGeometryEffect sources
Only one source view per ID should be visible at a time. Multiple visible sources with the same ID cause undefined layout.
5. Using DispatchQueue or UIView.animate
6. Forgetting animation on ContentTransition
7. navigationTransition on wrong view
Apply .navigationTransition(.zoom(sourceID:in:)) on the outermost destination view, not inside a container.
Review Checklist
[ ] Animation curve matches intent (spring for natural, ease for mechanical)
[ ] withAnimation wraps the state change; implicit animation uses .animation( :body:) for selective modifier scope or .animation( :value:) with an explicit value
[ ] matchedGeometryEffect has exactly one source per ID; zoom uses matching id / namespace
[ ] @Animatable macro used when synthesis fits; manual animatableData kept only when custom packing is clearer
[ ] accessibilityReduceMotion checked; no DispatchQueue / UIView.animate
[ ] Transitions use .transition() ; contentTransition is paired with animation and uses the narrowest implicit animation scope that fits
[ ] Animated state changes on @MainActor; animation driving types are Sendable
References
See [references/animation advanced.md](references/animation advanced.md) for CustomAnimation protocol, Spring variants, Transition types, symbol effects, Transaction system, UnitCurve, and performance guidance; Core Animation bridging patterns: [references/core animation bridge.md](references/core animation bridge.md).