axiom-swiftui-animation-ref

0
1
Source

Use when implementing SwiftUI animations, understanding VectorArithmetic, using @Animatable macro, zoom transitions, UIKit/AppKit animation bridging, choosing between spring and timing curve animations, or debugging animation behavior - comprehensive animation reference from iOS 13 through iOS 26

Install

mkdir -p .claude/skills/axiom-swiftui-animation-ref && curl -L -o skill.zip "https://mcp.directory/api/skills/download/6765" && unzip -o skill.zip -d .claude/skills/axiom-swiftui-animation-ref && rm skill.zip

Installs to .claude/skills/axiom-swiftui-animation-ref

About this skill

SwiftUI Animation

Overview

Comprehensive guide to SwiftUI's animation system, from foundational concepts to advanced techniques. This skill covers the Animatable protocol, the iOS 26 @Animatable macro, animation types, and the Transaction system.

Core principle Animation in SwiftUI is mathematical interpolation over time, powered by the VectorArithmetic protocol. Understanding this foundation unlocks the full power of SwiftUI's declarative animation system.

System Requirements

  • iOS 13+: Animatable protocol, timing/spring animations
  • iOS 17+: Default spring animations, scoped animations, PhaseAnimator, KeyframeAnimator
  • iOS 18+: Zoom transitions, UIKit/AppKit animation bridging
  • iOS 26+: @Animatable macro

Part 1: Understanding Animation

What Is Interpolation

Animation is the process of generating intermediate values between a start and end state.

Example: Opacity animation

.opacity(0) → .opacity(1)

While this animation runs, SwiftUI computes intermediate values:

0.0 → 0.02 → 0.05 → 0.1 → 0.25 → 0.4 → 0.6 → 0.8 → 1.0

How values are distributed

  • Determined by the animation's timing curve or velocity function
  • Spring animations use physics simulation
  • Timing curves use bezier curves
  • Each animation type calculates values differently

VectorArithmetic Protocol

SwiftUI requires animated data to conform to VectorArithmetic — providing subtraction, scaling, addition, and a zero value. This enables SwiftUI to interpolate between any two values.

Built-in conforming types: CGFloat, Double, Float, Angle (1D), CGPoint, CGSize (2D), CGRect (4D).

Key insight Vector arithmetic abstracts over dimensionality. SwiftUI animates all these types with a single generic implementation.

Why Int Can't Be Animated

Int doesn't conform to VectorArithmetic — no fractional intermediates exist between 3 and 4. SwiftUI simply snaps the value.

Solution: Use Float/Double and display as Int:

@State private var count: Float = 0
// ...
Text("\(Int(count))")
    .animation(.spring, value: count)

Model vs Presentation Values

Animatable attributes conceptually have two values:

Model Value

  • The target value set by your code
  • Updated immediately when state changes
  • What you write in your view's body

Presentation Value

  • The current interpolated value being rendered
  • Updates frame-by-frame during animation
  • What the user actually sees

Example

.scaleEffect(selected ? 1.5 : 1.0)

When selected becomes true:

  • Model value: Immediately becomes 1.5
  • Presentation value: Interpolates 1.0 → 1.1 → 1.2 → 1.3 → 1.4 → 1.5 over time

Part 2: Animatable Protocol

Overview

The Animatable protocol allows views to animate their properties by defining which data should be interpolated.

protocol Animatable {
    associatedtype AnimatableData: VectorArithmetic

    var animatableData: AnimatableData { get set }
}

SwiftUI builds an animatable attribute for any view conforming to this protocol.

Built-in Animatable Views

Many SwiftUI modifiers conform to Animatable:

Visual Effects

  • .scaleEffect() — Animates scale transform
  • .rotationEffect() — Animates rotation
  • .offset() — Animates position offset
  • .opacity() — Animates transparency
  • .blur() — Animates blur radius
  • .shadow() — Animates shadow properties

All Shape types

  • Circle, Rectangle, RoundedRectangle
  • Capsule, Ellipse, Path
  • Custom Shape implementations

AnimatablePair for Multi-Dimensional Data

When animating multiple properties, use AnimatablePair to combine vectors. For example, scaleEffect combines CGSize (2D) and UnitPoint (2D) into a 4D vector via AnimatablePair<CGSize.AnimatableData, UnitPoint.AnimatableData>. Access components via .first and .second. The @Animatable macro (iOS 26+) eliminates this boilerplate entirely.

Custom Animatable Conformance

When to use

  • Animating custom layout (like RadialLayout)
  • Animating custom drawing code
  • Animating properties that affect shape paths

Example: Animated number view

struct AnimatableNumberView: View, Animatable {
    var number: Double

    var animatableData: Double {
        get { number }
        set { number = newValue }
    }

    var body: some View {
        Text("\(Int(number))")
            .font(.largeTitle)
    }
}

// Usage
AnimatableNumberView(number: value)
    .animation(.spring, value: value)

How it works

  1. number changes from 0 to 100
  2. SwiftUI calls body for every frame of the animation
  3. Each frame gets a new number value: 0 → 5 → 15 → 30 → 55 → 80 → 100
  4. Text updates to show the interpolated integer

Performance Warning

Custom Animatable conformance is expensive — SwiftUI calls body for every frame on the main thread. Built-in effects (.scaleEffect(), .opacity()) run off-main-thread and don't call body. Use custom conformance only when built-in modifiers can't achieve the effect (e.g., animating a custom Layout that repositions subviews per-frame).


Part 3: @Animatable Macro (iOS 26+)

Overview

The @Animatable macro eliminates the boilerplate of manually conforming to the Animatable protocol.

Before iOS 26, you had to:

  1. Manually conform to Animatable
  2. Write animatableData getter and setter
  3. Use AnimatablePair for multiple properties
  4. Exclude non-animatable properties manually

iOS 26+, you just add @Animatable:

@MainActor
@Animatable
struct MyView: View {
    var scale: CGFloat
    var opacity: Double

    var body: some View {
        // ...
    }
}

The macro automatically:

  • Generates Animatable conformance
  • Inspects all stored properties
  • Creates animatableData from VectorArithmetic-conforming properties
  • Handles multi-dimensional data with AnimatablePair

Before/After Comparison

Before @Animatable macro

struct HikingRouteShape: Shape {
    var startPoint: CGPoint
    var endPoint: CGPoint
    var elevation: Double
    var drawingDirection: Bool // Don't want to animate this

    // Tedious manual animatableData declaration
    var animatableData: AnimatablePair<AnimatablePair<CGFloat, CGFloat>,
                        AnimatablePair<Double, AnimatablePair<CGFloat, CGFloat>>> {
        get {
            AnimatablePair(
                AnimatablePair(startPoint.x, startPoint.y),
                AnimatablePair(elevation, AnimatablePair(endPoint.x, endPoint.y))
            )
        }
        set {
            startPoint = CGPoint(x: newValue.first.first, y: newValue.first.second)
            elevation = newValue.second.first
            endPoint = CGPoint(x: newValue.second.second.first, y: newValue.second.second.second)
        }
    }

    func path(in rect: CGRect) -> Path {
        // Drawing code
    }
}

After @Animatable macro

@Animatable
struct HikingRouteShape: Shape {
    var startPoint: CGPoint
    var endPoint: CGPoint
    var elevation: Double

    @AnimatableIgnored
    var drawingDirection: Bool // Excluded from animation

    func path(in rect: CGRect) -> Path {
        // Drawing code
    }
}

Lines of code: 20 → 12 (40% reduction)

@AnimatableIgnored

Use @AnimatableIgnored to exclude properties from animation.

When to use

  • Debug values — Flags for development only
  • IDs — Identifiers that shouldn't animate
  • Timestamps — When the view was created/updated
  • Internal state — Non-visual bookkeeping
  • Non-VectorArithmetic types — Colors, strings, booleans

Example

@MainActor
@Animatable
struct ProgressView: View {
    var progress: Double // Animated
    var totalItems: Int // Animated (if Float, not if Int)

    @AnimatableIgnored
    var title: String // Not animated

    @AnimatableIgnored
    var startTime: Date // Not animated

    @AnimatableIgnored
    var debugEnabled: Bool // Not animated

    var body: some View {
        VStack {
            Text(title)
            ProgressBar(value: progress)
            if debugEnabled {
                Text("Started: \(startTime.formatted())")
            }
        }
    }
}

Real-World Use Case

@Animatable works for any numeric display — stock prices, heart rate, scores, timers, progress bars:

@MainActor
@Animatable
struct AnimatedValueView: View {
    var value: Double
    var changePercent: Double

    @AnimatableIgnored
    var label: String

    var body: some View {
        VStack(alignment: .trailing) {
            Text("\(value, format: .number.precision(.fractionLength(2)))")
                .font(.title)
            Text("\(changePercent > 0 ? "+" : "")\(changePercent, format: .percent)")
                .foregroundStyle(changePercent > 0 ? .green : .red)
        }
    }
}

// Usage
AnimatedValueView(value: currentPrice, changePercent: 0.025, label: "Price")
    .animation(.spring(duration: 0.8), value: currentPrice)

Part 4: Animation Types

Timing Curve Animations

Timing curve animations use bezier curves to control the speed of animation over time.

Built-in presets

.animation(.linear)          // Constant speed
.animation(.easeIn)          // Starts slow, ends fast
.animation(.easeOut)         // Starts fast, ends slow
.animation(.easeInOut)       // Slow start and end, fast middle

Custom timing curves

let customCurve = UnitCurve(
    startControlPoint: CGPoint(x: 0.2, y: 0),
    endControlPoint: CGPoint(x: 0.8, y: 1)
)

.animation(.timingCurve(customCurve, duration: 0.5))

Duration

All timing curve animations accept an optional duration:

.animation(.easeInOut(duration: 0.3))
.animation(.linear(duration: 1.0))

Default: 0.35 seconds

Spring Animations

Spring animations use physics simulation to create natural, organic motion.

Built-in presets

`


Content truncated.

axiom-swiftui-nav-diag

CharlesWiltgen

Use when debugging navigation not responding, unexpected pops, deep links showing wrong screen, state lost on tab switch or background, crashes in navigationDestination, or any SwiftUI navigation failure - systematic diagnostics with production crisis defense

54

axiom-swiftui-26-ref

CharlesWiltgen

Use when implementing iOS 26 SwiftUI features - covers Liquid Glass design system, performance improvements, @Animatable macro, 3D spatial layout, scene bridging, WebView/WebPage, AttributedString rich text editing, drag and drop enhancements, and visionOS integration for iOS 26+

33

axiom-extensions-widgets-ref

CharlesWiltgen

Use when implementing widgets, Live Activities, Control Center controls, or app extensions - comprehensive API reference for WidgetKit, ActivityKit, App Groups, and extension lifecycle for iOS 14+

13

axiom-ios-build

CharlesWiltgen

Use when ANY iOS build fails, test crashes, Xcode misbehaves, or environment issue occurs before debugging code. Covers build failures, compilation errors, dependency conflicts, simulator problems, environment-first diagnostics.

253

axiom-camera-capture-ref

CharlesWiltgen

Reference — AVCaptureSession, AVCapturePhotoSettings, AVCapturePhotoOutput, RotationCoordinator, photoQualityPrioritization, deferred processing, AVCaptureMovieFileOutput, session presets, capture device APIs

42

axiom-swiftdata

CharlesWiltgen

Use when working with SwiftData - @Model definitions, @Query in SwiftUI, @Relationship macros, ModelContext patterns, CloudKit integration, iOS 26+ features, and Swift 6 concurrency with @MainActor — Apple's native persistence framework

12

You might also like

flutter-development

aj-geddes

Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.

1,6831,428

ui-ux-pro-max

nextlevelbuilder

"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."

1,2601,320

drawio-diagrams-enhanced

jgtolentino

Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.

1,5291,146

godot

bfollington

This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.

1,350807

nano-banana-pro

garg-aayush

Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.

1,262727

pdf-to-markdown

aliceisjustplaying

Convert entire PDF documents to clean, structured Markdown for full context loading. Use this skill when the user wants to extract ALL text from a PDF into context (not grep/search), when discussing or analyzing PDF content in full, when the user mentions "load the whole PDF", "bring the PDF into context", "read the entire PDF", or when partial extraction/grepping would miss important context. This is the preferred method for PDF text extraction over page-by-page or grep approaches.

1,475681