Skip to content
This repository was archived by the owner on Feb 21, 2026. It is now read-only.

Raven v0.6.0 - Phase 12: Animation Foundation

Choose a tag to compare

@briannadoubt briannadoubt released this 04 Feb 06:25
· 214 commits to main since this release

Raven v0.6.0 - Phase 12: Animation Foundation

This massive release brings Raven's SwiftUI API coverage from ~80% to ~85% with a complete animation system including implicit/explicit animations, transitions, and keyframe animations.

🌟 Highlights

  • Complete Animation System - Timing curves, spring physics, custom Bézier
  • Implicit & Explicit Animations - .animation() modifier and withAnimation()
  • 8 Transition Types - View appearance/disappearance animations
  • Keyframe Animations - Multi-step animations with interpolation
  • 218+ Tests - Comprehensive coverage
  • Complete Documentation - 1,550+ line animation guide

✨ New Features

Animation Foundation

Animation Types:

// Standard curves
.animation(.default)      // Ease-in-out
.animation(.linear)       // Constant speed
.animation(.easeIn)       // Slow start
.animation(.easeOut)      // Slow end

// Spring physics
.animation(.spring())
.animation(.spring(response: 0.3, dampingFraction: 0.6))

// Custom curves
.animation(.timingCurve(0.4, 0.0, 0.2, 1.0, duration: 0.3))

Animation Modifiers:

.animation(.spring()
    .delay(0.1)
    .speed(1.5)
    .repeatCount(3, autoreverses: true))

Implicit Animations (.animation() Modifier)

Automatically animate property changes:

@State private var isExpanded = false

Circle()
    .scaleEffect(isExpanded ? 1.5 : 1.0)
    .animation(.spring())  // Animates when isExpanded changes

Button("Toggle") {
    isExpanded.toggle()  // Triggers animation
}

Value-Based Animation (More Efficient):

Text("Count: \(count)")
    .animation(.easeInOut, value: count)  // Only animates when count changes

Two Variants:

  • .animation(_:) - Animate all changes
  • .animation(_:value:) - Animate only when value changes

Explicit Animations (withAnimation() Function)

Animate state changes explicitly:

Button("Animate") {
    withAnimation(.spring()) {
        isExpanded.toggle()
        opacity = 0.5
        scale = 1.2
    }  // All changes animated with spring
}

With Completion:

withAnimation(.easeOut, {
    showDetails = true
}, completion: {
    print("Animation finished!")
})

Features:

  • Nested animation support
  • Completion callbacks
  • Error propagation
  • Thread-safe with @mainactor

Transition System

8 Transition Types for view appearance/disappearance:

// Fade in/out
if showView {
    DetailView()
        .transition(.opacity)
}

// Scale from center
if showCard {
    CardView()
        .transition(.scale)
}

// Slide from edge
if showMenu {
    MenuView()
        .transition(.move(edge: .leading))
}

// Custom translation
if showBanner {
    BannerView()
        .transition(.offset(y: -100))
}

// Navigation-style push
if showDetail {
    DetailPage()
        .transition(.push(from: .trailing))
}

Available Transitions:

  1. .identity - No animation
  2. .opacity - Fade in/out
  3. .scale(scale:anchor:) - Scale with anchor point
  4. .slide - Slide from bottom
  5. .move(edge:) - Slide from specific edge
  6. .offset(x:y:) - Custom translation
  7. .push(from:) - Navigation-style (maintains opacity)
  8. .modifier(active:identity:) - Custom via ViewModifiers

Composition:

// Combine multiple transitions
CardView()
    .transition(.scale.combined(with: .opacity))

// Different insert/remove
CardView()
    .transition(
        .asymmetric(
            insertion: .scale,
            removal: .opacity
        )
    )

Keyframe Animations (iOS 17+)

Multi-step animations with different interpolation per step:

Circle()
    .keyframeAnimator(
        initialValue: AnimationValues(scale: 1.0, opacity: 1.0),
        repeating: true
    ) { content, value in
        content
            .scaleEffect(value.scale)
            .opacity(value.opacity)
    } keyframes: { track in
        // Linear interpolation
        track.linear(.init(scale: 1.2, opacity: 0.8), duration: 0.3)
        
        // Spring physics
        track.spring(.init(scale: 1.0, opacity: 1.0), duration: 0.4, bounce: 0.2)
        
        // Instant change
        track.move(.init(scale: 1.5, opacity: 0.5))
        
        // Cubic ease
        track.cubic(.init(scale: 1.0, opacity: 1.0), duration: 0.3)
    }

Keyframe Types:

  • LinearKeyframe - Constant speed
  • SpringKeyframe - Physics-based (bounce: 0.0 - 1.0)
  • CubicKeyframe - Smooth ease-in-out
  • MoveKeyframe - Instant jump

Interpolatable Types:

  • Double, Float, CGFloat
  • CGPoint, CGSize, CGRect
  • Extensible for custom types

📚 Documentation

New Documentation:

  • Documentation/Phase12.md (~1,550 lines)
    • Complete animation system guide
    • All animation types with physics explanation
    • Implicit vs explicit animations
    • Complete transition guide (8 types)
    • Keyframe animation tutorial
    • Web implementation (CSS, GPU acceleration)
    • Performance optimization tips
    • Browser compatibility matrix
    • Common animation patterns
    • Troubleshooting guide
    • Migration guide from static UI

Updated Documentation:

  • README.md - What's New in v0.6.0
  • CHANGELOG.md - Complete version history (~600 lines)
  • API-Overview.md - Animation section (~300 lines)

Additional Guides:

  • WithAnimationImplementation.md - Architecture details
  • Task summaries and implementation notes

🎯 Examples

12 Comprehensive Examples:

  1. Animated Button - Spring bounce on press
  2. List Transitions - Insert/remove with smooth animations
  3. Loading Spinner - Keyframe-based rotation
  4. Animated Counter - Number with scale effect
  5. Page Transitions - Navigation-style push/slide
  6. Shape Morphing - Smooth shape transformations
  7. Animated UI Flow - Complete multi-step interaction
  8. Interactive Card Stack - Drag and spring animations
  9. Expandable Card - Height animation with content reveal
  10. Animated Tab Bar - Selection with bounce
  11. Transition Gallery - All 8 transition types demonstrated
  12. Animation Patterns - Common UI animation recipes

All examples include detailed comments and are ready to use!


🧪 Testing

218+ Comprehensive Tests:

  • AnimationTests: 34 tests

    • Animation types and curves
    • Spring physics
    • Custom timing
    • CSS generation
  • AnimationModifierTests: 23 tests

    • .animation() implicit animations
    • Value-based triggering
    • Animation stacking
  • WithAnimationTests: 24 tests

    • Explicit animation blocks
    • Nested animations
    • Error handling
  • WithAnimationIntegrationTests: 18 tests

    • Cross-feature integration
    • Real-world scenarios
  • TransitionTests: 37 tests

    • All 8 transition types
    • Composition
    • Asymmetric transitions
  • KeyframeAnimatorTests: 31 tests

    • Keyframe track building
    • Interpolation
    • CSS generation
  • Phase12VerificationTests: 50+ integration tests

    • Cross-feature testing
    • Complex UI scenarios
    • Performance validation

Test Coverage:

  • 218+ total tests
  • ~2,500+ lines of test code
  • Test/Code ratio: ~0.94 (excellent)
  • All animation features covered

🌐 Web Implementation

CSS Transitions:

/* Generated automatically */
transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1.0);

CSS Animations (@Keyframes):

@keyframes animation-123 {
    0% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.2); opacity: 0.8; }
    100% { transform: scale(1); opacity: 1; }
}

GPU Acceleration:

  • Transform and opacity use GPU
  • will-change hints for optimization
  • 60fps target performance
  • Minimal layout reflow

Browser Compatibility:

Feature Chrome Safari Firefox Edge
CSS Transitions All All All All
CSS Animations All All All All
Transform/Opacity GPU All All All All
Cubic-bezier() All All All All

📊 Statistics

  • 24 files added/modified
  • 11,471 lines added
  • API Coverage: 80% → 85%
  • Tests: 218+ tests
  • Examples: 12 comprehensive examples
  • Documentation: 2,450+ lines

🎓 Common Patterns

Button Bounce:

Button("Press Me") { }
    .scaleEffect(isPressed ? 0.9 : 1.0)
    .animation(.spring(response: 0.3, dampingFraction: 0.6))

List Insert/Remove:

ForEach(items) { item in
    ItemRow(item)
        .transition(.move(edge: .trailing).combined(with: .opacity))
}

Loading Spinner:

Circle()
    .trim(from: 0, to: 0.7)
    .stroke(lineWidth: 3)
    .keyframeAnimator(initialValue: 0.0, repeating: true) { content, angle in
        content.rotationEffect(Angle(degrees: angle))
    } keyframes: { track in
        track.linear(360, duration: 1.0)
    }

Page Transition:

if showDetail {
    DetailView()
        .transition(.push(from: .trailing))
}
withAnimation(.easeOut) {
    showDetail = true
}

🚀 Migration Guide

From Static to Animated

Before:

@State private var scale: CGFloat = 1.0

Circle()
    .scaleEffect(scale)

Button("Grow") {
    scale = 1.5  // Instant change
}

After:

@State private var scale: CGFloat = 1.0

Circle()
    .scaleEffect(scale)
    .animation(.spring(), value: scale)  // Smooth animation

Button("Grow") {
    scale = 1.5  // Animated change
}

Choosing Animation Style

Use .animation() when:

  • Property changes should always animate
  • Simple property-based animations
  • Visual feedback on state changes

Use withAnimation() when:

  • Multiple related state changes
  • Conditional animation
  • Need completion callbacks
  • Complex animation choreography

📦 Installation

```swift
dependencies: [
.package(url: "https://github.com/briannadoubt/Raven.git", from: "0.6.0")
]
```


🙏 Acknowledgments

This release represents a complete implementation of Phase 12 from the Raven roadmap, bringing professional animations and transitions to SwiftUI web development with CSS-based GPU acceleration.

Built with ❤️ using Swift 6.2 and SwiftWasm

See the Documentation for complete guides and API reference.