Repository navigation
Raven v0.6.0 - Phase 12: Animation Foundation
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 changesTwo 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:
.identity- No animation.opacity- Fade in/out.scale(scale:anchor:)- Scale with anchor point.slide- Slide from bottom.move(edge:)- Slide from specific edge.offset(x:y:)- Custom translation.push(from:)- Navigation-style (maintains opacity).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 speedSpringKeyframe- Physics-based (bounce: 0.0 - 1.0)CubicKeyframe- Smooth ease-in-outMoveKeyframe- 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:
- Animated Button - Spring bounce on press
- List Transitions - Insert/remove with smooth animations
- Loading Spinner - Keyframe-based rotation
- Animated Counter - Number with scale effect
- Page Transitions - Navigation-style push/slide
- Shape Morphing - Smooth shape transformations
- Animated UI Flow - Complete multi-step interaction
- Interactive Card Stack - Drag and spring animations
- Expandable Card - Height animation with content reveal
- Animated Tab Bar - Selection with bounce
- Transition Gallery - All 8 transition types demonstrated
- 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.