{"id":19190835,"url":"https://github.com/flocked/anima","last_synced_at":"2025-05-08T04:49:26.469Z","repository":{"id":210194250,"uuid":"725973181","full_name":"flocked/Anima","owner":"flocked","description":"Animation framework for iOS, tvOS, and macOS","archived":false,"fork":false,"pushed_at":"2025-03-23T12:27:51.000Z","size":10833,"stargazers_count":18,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-08T04:49:17.046Z","etag":null,"topics":["animation","animations","appkit","calayer","framework","gesture","ios","macos","nsview","spring","ui","uiview"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flocked.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-12-01T09:06:12.000Z","updated_at":"2025-04-03T11:24:28.000Z","dependencies_parsed_at":"2024-03-14T21:49:50.870Z","dependency_job_id":"24ed2074-d6b1-43ae-9733-7e73b27b4f5e","html_url":"https://github.com/flocked/Anima","commit_stats":{"total_commits":152,"total_committers":2,"mean_commits":76.0,"dds":0.006578947368421018,"last_synced_commit":"9e88a42568c591a752a832fb1514ab0ccb66bdf1"},"previous_names":["flocked/anima"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flocked%2FAnima","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flocked%2FAnima/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flocked%2FAnima/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flocked%2FAnima/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flocked","download_url":"https://codeload.github.com/flocked/Anima/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253002842,"owners_count":21838637,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","animations","appkit","calayer","framework","gesture","ios","macos","nsview","spring","ui","uiview"],"created_at":"2024-11-09T11:35:56.269Z","updated_at":"2025-05-08T04:49:26.447Z","avatar_url":"https://github.com/flocked.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Anima\n\nAnima is an animation framework for iOS, tvOS, and macOS. It lets you animate properties using spring, easing and decay animations.\n\n**Take a look at the included sample app which demonstrates most features.**\n\n**For a full documentation take a look at the** [Online Documentation](https://swiftpackageindex.com/flocked/Anima/documentation/anima).\n\n## Animatable Properties\n\nAny type conforming to `AnimatableProperty` can be animated by `Anima`.\n\nBy default, lots of types already conform to it:\n\n- `Float`\n- `Double`\n- `CGFloat`\n- `CGPoint`\n- `CGSize`\n- `CGRect`\n- `CGColor`/`NSColor`/`UIColor`\n- `CATransform3D` / `CGAffineTransform`\n- Arrays with `AnimatableProperty` values\n- … and many more.\n\n## Animations\n\nThere are two ways you can can create animations: **block-based** and **property-based**.\n\n### Block-Based Animations\n\nBlock-based animation lets you easily animate properties of objects conforming to `AnimatablePropertyProvider`.\n\nMany objects already conform to it and provide animatable properties:\n - macOS: `NSView`, `NSWindow`, `NSTextField`, `NSImageView` and many more.\n - iOS: `UIView`, `UILabel`, `UIImageView` and many more.\n - Shared: `NSLayoutConstraint` and `CALayer`\n \nThe properties can can be accessed via the object's `animator`. To animate them change their values inside an animation block using `Anima.animate(…)`. For example:\n\n```swift\nAnima.animate(withSpring: .bouncy) {\n    view.animator.frame = newFrame\n    view.animator.backgroundColor = .systemBlue\n    textField.animator.fontSize = 20\n}\n```\nTo stop the animation of a property and to update it immediately, change it's value outside an animation block. For example:\n\n```swift\nview.animator.backgroundColor = .systemRed\n```\n\n#### Spring Animation\n\nA spring based animation for fluid animations.\n\nYou provide a `Spring` which describes the spring configuration. `Spring` offers many predefined configurations like `bouncy`, `smooth`, `snappy` or `Spring(duration: CGFloat, bouncy: CGFloat)`).\n\n```swift\nAnima.animate(withSpring: .bouncy) {\n    view.animator.frame = newFrame\n    view.animator.backgroundColor = .systemBlue\n}\n```\n\nWhen changing the value of a property that is currently animated, the animation’s velocity is preserved to provide fluid animations. That's why spring animation is the recommended animation for a responsive and interactive UI.\n\nYou can provide a gesture velocity for spring animations. This can be used to \"inject\" the velocity of a gesture recognizer (when the gesture ends) into the animations.  If you apply a velocity of type `CGPoint` it's used for animating properties of type `GGPoint` and `CGRect`.\n\n```swift\nlet velocity = panGestureRecognizer.velocity(in: view)\n\nAnima.animate(withSpring: .snappy, gestureVelocity: velocity) {\n    view.animator.frame.origin = CGPoint(x: 200, y: 200)\n}\n```\n\n#### Easing Animation\n\nAn easing based animation.\n\nYou provide a `TimingFunction` which describes the easing of the animation (e.g. `easeIn`, `easeInOut` or `linear`) and a duration.\n\n```swift\nAnima.animate(withEasing: .easeIn, duration: 3.0) {\n    view.animator.frame = newFrame\n    view.animator.backgroundColor = .systemBlue\n}\n```\n\n#### Decay Animation\n\nPerforms animations with a decaying acceleration.\n\nYou either provide **values** and the animation will animate the properties to the values with a decelerating acceleration.\n\n```swift\nAnima.animate(withDecay: .value) {\n    view.animator.frame = newFrame\n    view.animator.backgroundColor = .systemBlue\n}\n```\n\nOr you provide **velocity** values. The properties will increase or decrease depending on the velocity values and will slow to a stop. This essentially provides the same \"decaying\" that `UIScrollView` does when you drag and let go. The animation is seeded with velocity, and that velocity decays over time.\n\n```swift\nAnima.animate(withDecay: .velocity) {\n    // The origin's y value will increase 200 points. (e.g. if the origin`s y value is 250 it will move to 450)\n    view.animator.frame.origin.y = 200\n}\n```\n\n### Property-Based Animations\n\nWhile the block-based API is often most convenient, you may want to animate an object that doesn't provide animatable properties. Or, you may want the flexibility of getting the intermediate values of an animation and driving an animation yourself.\n\nTo create an property-based animation you provide an initial value, target value and `valueChanged`, a block that gets called whenever the animation's current value changes.\n\n#### Spring Animation \n\n```swift\nlet value = CGPoint(x: 0, y: 0)\nlet target = CGPoint(x: 100, y: 100)\n\nlet springAnimation = SpringAnimation(spring: .bouncy, value: value, target: target)\nspringAnimation.valueChanged = { newValue in\n    view.frame.origin = newValue\n}\nspringAnimation.start()\n```\n\n#### Easing Animation\n\n```swift\nlet easingAnimation = EasingAnimation(timingFunction: .easeIn, duration: 2.0, value: value, target: target)\neasingAnimation.valueChanged = { newValue in\n    view.frame.origin = newValue\n}\neasingAnimation.start()\n```\n\n#### Decay Animation\n\n```swift\n// Decay animation with target\nlet decayAnimation = DecayAnimation(value: value, target: target)\ndecayAnimation.valueChanged = { newValue in\n    view.frame.origin = newValue\n}\ndecayAnimation.start()\n\n// Decay animation with velocity\nlet decayVelocityAnimation = DecayAnimation(value: value, velocity: velocity)\n```\n\n#### ValueAnimation\n\nTo create your own animations overwrite this `ValueAnimation`. The class isn't animating and you have to provide your own animation logic.\n\n## Additions\n\n### CAKeyframeAnimationEmittable\n\nAll animations in Anima conform to `CAKeyframeAnimationEmittable` and provide a `CAKeyframeAnimation` via `keyframeAnimation` that mirrors the animation. The duration, keyframes and everything else is automatically calculated. The only difference is `valueChanged` and `completion` cannot be used, and you must specify a keypath to animate.\n\nFor example:\n\n```swift\nlet springAnimation = SpringAnimation\u003cCGRect\u003e(spring: .bouncy, value: frame, target: targetFrame)\n\nlet keyframeAnimation = springAnimation.keyframeAnimation()\nkeyframeAnimation.keyPath = \"frame\"\n\nlayer.add(keyframeAnimation, forKey: \"MyAnimation\")\n```\n\n**Note**: If you remove or interrupt the animation and you want it to stay in place on screen, much like all other Core Animation animations, you'll need to grab the value from the layer's `presentationLayer` and apply that to the layer (as well as worry about `fillMode`).\n\n### Rubberbanding\n\nRubberbanding is the act of making values appear to be on a rubberband (they stretch and slip based on interaction). `UIScrollView` does this when you're pulling past the contentSize and by using the rubberband functions in Motion you can re-create this interaction for yourself.\n\n```swift\n bounds.origin.x = rubberband(bounds.origin.x - translation.x, boundsSize: bounds.size.width, contentSize: contentSize.width)\n```\n\n## Acknowledgement\n\nAnima is partly based on [Wave](https://github.com/jtrivedi/Wave) and [Motion](https://github.com/b3ll/Motion). It uses `Waves` spring calculation and some of the animation logic and `Motion`s decay and easing calculation.\n\nWithout these libraries Anima wouldn't have been possible. \n\n## Installation\n\nAdd Anima to your app's Package.swift file, or selecting File -\u003e Add Packages in Xcode:\n\n```swift\n.package(url: \"https://github.com/flocked/Anima\")\n```\n\nIf you clone the repo, you can run the sample app, which contains a few interactive demos to understand what Anima provides.\n\nNote: To enable high frame-rate animations on ProMotion devices (i.e. 120 fps animation), you'll need to add a key/value pair in your Info.plist. Set the key `CADisableMinimumFrameDuration` to `true. Without this entry, animations will be capped at 60 fps.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflocked%2Fanima","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflocked%2Fanima","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflocked%2Fanima/lists"}