swiftui-motion
SwiftUI animation foundations - withAnimation, transitions, matchedGeometryEffect, PhaseAnimator, KeyframeAnimator, springs, gestures.
By athevon · 832 installs
npx skills add athevon/genjutsu --skill swiftui-motion
Source repository · Upstream listing
Version sensitive. Every API name, SDK gate and browser support claim below was
verified on 2026 09 08 against primary sources. What against, and when, is in
jutsu/VERSIONS.md . If that date is old, re verify before acting on a version number.
SwiftUI Motion
SwiftUI animation core. Loaded for any SwiftUI project (iOS, macOS, multi target Apple).
Concise rules here. Deep dive in references/ .
Pair with ../motion principles/SKILL.md (foundation) and ../mobile principles/SKILL.md (touch UX).
Animation API decision tree
Need API
Single value over time withAnimation { } + @State or .animation( , value:)
Multiple coordinated states PhaseAnimator(phases) (iOS 17+)
Time based keyframes KeyframeAnimator(initialValue:repeating:content:) (iOS 17+)
Custom property animations @Animatable macro (needs Xcode 26 / SwiftUI 2025 SDK to compile; runtime availability iOS 13.0+ / macOS 10.15+ / watchOS 6.0+ ) or the Animatable protocol by hand (iOS 13+)
Shared element transitions matchedGeometryEffect(id:in:)
Gesture driven DragGesture / MagnifyGesture + .offset / .scaleEffect
Loop forever .animation(.linear.repeatForever(autoreverses: true), value: ...) or .phaseAnimator
Rule: start with withAnimation . Reach for PhaseAnimator only when you have 3+ ordered states. Reach for KeyframeAnimator only when you need parallel time based tracks.
Springs (the only easing you should care about)
SwiftUI ships named spring presets (iOS 17+): .snappy , .bouncy , .smooth , plus the parameterised
.spring(duration:bounce:blendDuration:) and .interactiveSpring(...) . Each of the three named ones
also takes (duration:extraBounce:) overloads. Use them. Tune response / dampingFraction only when
a preset is wrong.
Preset (iOS 17+) Equivalent Mood
.snappy .spring(response: 0.5, dampingFraction: 0.85) UI snappy
.bouncy .spring(response: 0.5, dampingFraction: 0.7) playful
.smooth .spring(response: 0.5, dampingFraction: 1.0) calm, no bounce
.interactiveSpring() .spring(response: 0.15, dampingFraction: 0.86) gesture follow
response is the spring's period its stiffness expressed as a duration, i.e. how long one
oscillation would take. It is not the settling time: a .spring(response: 0.5, dampingFraction: 1.0)
keeps moving well past 0.5s. Lower = snappier, higher = softer. dampingFraction is the overshoot intensity in 0...1 (1 = no overshoot, 0 = perpetual oscillation never use 0). For UI work, stay in response: 0.2...0.5 and dampingFraction: 0.7...1.0 . Deep dive: references/springs cheatsheet.md .
iOS 17+ also exposes .spring(duration:bounce:) where bounce is 0...1 (0 = critically damped, 1 = full bounce). It's the same spring, exposed in a more designer friendly way:
Implicit vs explicit animations
Rule: prefer explicit ( withAnimation ) for state changes triggered by user actions; use implicit when any change to a value should always animate (e.g., a progress bar that updates from anywhere). Never both on the same property the outer withAnimation wins, but the implicit .animation modifier still runs and stacks confusingly.
Transitions
Transitions drive insertion / removal of views inside an if , switch , or ForEach . They run when the parent's animation context fires (so wrap state mutations in withAnimation ).
BAD vanish into a black hole:
GOOD never scale to 0:
iOS 17+ also has the .transition( :) modifier with custom transitions via the Transition protocol useful for shared timing across many views. For 90% of work, the built in combinators ( .move , .opacity , .scale , .slide , .push , .asymmetric , .combined(with:) ) are enough.
matchedGeometryEffect (hero animations)
Tag two views with the same id in the same Namespace . SwiftUI interpolates frame and position when the source view is replaced.
isSource: true (default on the source of truth view) tells SwiftUI which frame to interpolate from. Common gotchas: id collisions across unrelated namespaces, view identity instability (use stable ids, not array indices), and animating out of an if branch where the destination view doesn't exist yet (wrap both branches inside the same parent, use opacity to hide instead of removing).
PhaseAnimator (iOS 17+)
For ordered state choreography. The API takes some Sequence of a phase type constrained to Equatable (not Hashable ); CaseIterable is only a convenience so you can pass Phase.allCases . SwiftUI walks the sequence in order and settles on the last element.
trigger: is optional omit it to advance through phases automatically once on appear. Use it when you need an external signal (button tap, model update). Phases run sequentially, never in parallel if you need parallelism, use KeyframeAnimator .
KeyframeAnimator (iOS 17+)
For continuous, time based animations with parallel tracks. Each KeyframeTrack animates one keypath independently; SwiftUI runs them all together.
Four keyframe types: LinearKeyframe (constant velocity between points), SpringKeyframe (settles with spring), CubicKeyframe (cubic bezier ease), MoveKeyframe (jump cut, no interpolation). Trigger on a value change to re run the animation. Deep dive: references/phase keyframe deep.md .
Animatable / @Animatable
For custom drawing that needs interpolation. The @Animatable macro (introduced with the iOS 26 SDK at WWDC25, so it needs Xcode 26+; its declared availability is iOS 13.0+ / macOS 10.15+ / watchOS 6.0+, so it back deploys) attaches to a struct/class/enum and synthesizes both the Animatable conformance and animatableData from the stored properties that are themselves animatable ( Double , CGFloat , Angle , CGSize , CGPoint , UnitPoint , any VectorArithmetic ). Mark a stored property @AnimatableIgnored (same availability) to keep it out of the synthesized data. Writing animatableData by hand still works and is what you do on an older toolchain.
For multi property shapes use AnimatablePair<A, B (or nested pairs) as animatableData . The @Animatable macro removes that boilerplate: annotate the shape and every stored property conforming to VectorArithmetic ( Double , CGFloat , Angle , CGSize , CGPoint , UnitPoint , ...) is folded into the synthesized animatableData automatically; opt a property out with @AnimatableIgnored .
Gestures
Gesture Type Use
TapGesture discrete tap, double tap ( count: 2 )
LongPressGesture discrete + continuous ( onEnded / onChanged ) context menus, hold to record
DragGesture continuous drag, swipe to dismiss
MagnifyGesture continuous pinch zoom (iOS 17+, replaces MagnificationGesture )
RotateGesture continuous rotate (iOS 17+, replaces RotationGesture )
SpatialTapGesture (iOS 16+, macOS 13+) discrete tap with location info
Three composition operators: .simultaneously(with:) (parallel recognition), .sequenced(before:) (one must complete first), .exclusively(before:) (one or the other, not both). For fine grained control over when child views can claim the gesture, use .simultaneousGesture( , including: GestureMask) with .gesture , .subviews , .all , or .none . Deep dive: references/gestures swiftui.md .
Anti Patterns (BAD / GOOD)
1. Deprecated .animation form (no value binding)
2. Animating frame size directly
3. Scale to 0 (the vanish into nothing trap)
4. withAnimation inside body
Reduced motion respect
Mandatory. SwiftUI exposes the iOS / macOS "Reduce Motion" accessibility setting via the environment. See ../motion principles/SKILL.md for the cross platform rationale.
Rule: cross fades and opacity are still allowed under reduced motion; large translations, scale from zero, parallax, and looping motion must be neutralized.
Quick Reference: Loading sub skills
Need Load
Springs deep dive (response/dampingFraction tuning, mood) references/springs cheatsheet.md
PhaseAnimator + KeyframeAnimator complex sequences references/phase keyframe deep.md
Gesture composition + conflict resolution references/gestures swiftui.md
Advanced visuals (Metal, Liquid Glass) ../swiftui graphics/SKILL.md
Cross platform UX (mobile, desktop) ../mobile principles/SKILL.md , ../desktop principles/SKILL.md
Foundation (timing, easing, a11y) ../motion principles/SKILL.md
Sources
[twostraws/SwiftUI Agent Skill](https://github.com/twostraws/SwiftUI Agent Skill)
[GetStream/swiftui spring animations](https://github.com/GetStream/swiftui spring animations)
[amosgyamfi/open swiftui animations](https://github.com/amosgyamfi/open swiftui animations)
[AvdLee/SwiftUI Agent Skill](https://github.com/AvdLee/SwiftUI Agent Skill)
[Apple SwiftUI Animations](https://developer.apple.com/documentation/swiftui/animations)
[Apple PhaseAnimator](https://developer.apple.com/documentation/swiftui/phaseanimator)
[Apple KeyframeAnimator](https://developer.apple.com/documentation/swiftui/keyframeanimator)
[WWDC23 Animate with springs](https://developer.apple.com/videos/play/wwdc2023/10158/)
[WWDC23 Wind your way through advanced animations](https://developer.apple.com/videos/play/wwdc2023/10157/)