{"id":2356,"url":"https://github.com/mmick66/kinieta","last_synced_at":"2025-04-10T00:02:19.497Z","repository":{"id":56917963,"uuid":"106298328","full_name":"mmick66/kinieta","owner":"mmick66","description":"A Fast Animation Engine with an Intuitive API","archived":false,"fork":false,"pushed_at":"2017-11-12T23:08:30.000Z","size":1158,"stargazers_count":46,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T01:43:09.534Z","etag":null,"topics":["animation-engine","animation-library","animations","graphics-engine","graphics-library","ios","ios-swift","swift4","tween","tweening"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mmick66.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}},"created_at":"2017-10-09T15:02:32.000Z","updated_at":"2023-10-04T13:29:42.000Z","dependencies_parsed_at":"2022-08-20T17:10:29.647Z","dependency_job_id":null,"html_url":"https://github.com/mmick66/kinieta","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmick66%2Fkinieta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmick66%2Fkinieta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmick66%2Fkinieta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmick66%2Fkinieta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mmick66","download_url":"https://codeload.github.com/mmick66/kinieta/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247648977,"owners_count":20972945,"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-engine","animation-library","animations","graphics-engine","graphics-library","ios","ios-swift","swift4","tween","tweening"],"created_at":"2024-01-05T20:16:11.724Z","updated_at":"2025-04-10T00:02:19.452Z","avatar_url":"https://github.com/mmick66.png","language":"Swift","funding_links":[],"categories":["UI","Libs","Animation [🔝](#readme)"],"sub_categories":["Animation","Other free courses"],"readme":"\u003cp align=\"center\"\u003e \n  \u003cimg src=\"https://github.com/mmick66/kinieta/blob/master/Assets/Kinieta_Logo.png\"\u003e\n\u003c/p\u003e\n\n## Kinieta\nAn Animation Engine for iOS with an Intuitive API and Readable Code! (Written in Swift 4.0.)\n\n## Why another?\n\nI decided to build an Animation Engine from scratch for the usual reason: No other did what I wanted **how** I wanted it! While there are some great libraries out there, my requiremenets where pretty restrictive as what I wanted was:\n\n* A library written in **Swift 4.0**\n* With a **timeline** approach where animations can run in **parallel** at different start and end points\n* The ability to **group** various animations from different views with a single complete block\n* A **simple API** where I could just throw in some variables and the rest would be dealt by the library\n* A **convention over configuration** approach where many variables would be assumed when not passed\n* Efficient interpolation with infinite **easing functions** based on custom Bezier curves\n* Provides **real color interpolation** using the advanced HCL color space rather than plain RGB\n* Code that was **extremely** easy to read and new developers from the community could join in in no time!\n\n## Installation\n\n#### Cocoa Pods\n\n```\npod 'Kinieta', '~\u003e 0.5'\n```\n\n#### Manual\n\nFor the moment, just copy the files in the Kinieta (virtual) folder\n\n## How to Use\n\n```swift\nsquare.move(to: [\"x\": 374], during: 1.0).easeInOut(.Back).wait(for: 1.0).complete {\n    square.move(to: [\"x\": 74])\n}\n```\n\n![Basic Move with Ease](https://github.com/mmick66/kinieta/blob/master/Assets/move.easeInOut.Back.gif)\n\n### Basic Usage\n\nAn extension on `UIView` that is included in the code will provide the entry point for the animations. The interface object is the `Kinieta` and there is one for every view.\n\n```swift\n// This will snap the view to the given coordinates\naView.move(to: [\"x\": 250, \"y\": 500])\n\n// This will animate the same view to the coordinates in 0.5 seconds\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5)\n\n// This will delay the start of the animation by 0.5 seconds\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).delay(for: 0.5)\n\n// And this will ease the whole thing\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).delay(for: 0.5).easeInOut()\n\n// While this will ease it with a bounce-back\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).delay(for: 0.5).easeInOut(.Back)\n\n// And call the complete block when the animation is finished\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).delay(for: 0.5).easeInOut(.Back).complete { print(\"♥\") }\n```\n\nThe UIView properties that can be animated, together with their keys are:\n\n\n| Key                       | Value Type    |   Metric    | Property Animated  |\n| -------------             |:-------------:|:-------------:|               -----:|\n| **\"x\"**                       | Any Numeric   | screen points |   `frame.origin.x` |\n| **\"y\"**                       | Any Numeric   | screen points  |  `frame.origin.y` |\n| **\"w\"** or **\"width\"**            | Any Numeric   |  screen points |`frame.size.width` |\n| **\"h\"** or **\"height\"**           | Any Numeric   | screen points |`frame.size.height` |\n| **\"a\"** or **\"alpha\"**            | Any Numeric   |  0 to 1 transparency |           `alpha` |\n| **\"r\"** or **\"rotation\"**            | Any Numeric   |  **degrees** |           `transform` |\n| **\"frame\"**                   | CGRect        |  composite  |         `frame` |\n| **\"bg\"** or **\"background\"**      | UIColor       | color |  `backgroundColor` |\n| **\"brc\"** or **\"borderColor\"**    | UIColor       | color |`layer.borderColor` |\n| **\"brw\"** or **\"borderWidth\"**    | UIColor       | screen points |`layer.borderWidth` |\n| **\"crd\"** or **\"cornerRadius\"**   | UIColor       | bevel radius | `layer.cornerRadius` |\n\nNote: When two synonymous keys (like \"bg\" and \"background\") are passed in the same list the most **verbose** (ie. \"background\") will win over and the other will be silently ignored.\n\n### Easing\n\nEvery move can be smoothed by calling one of the 3 easing functions and pass:\n\n```swift\n// When no curve is passed `.Quad` is used\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).easeIn()\n\n// Ease at start, end and both ends respectively\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).easeIn(.Cubic)\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).easeOut(.Cubic)\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).easeInOut(.Cubic)\n```\n\nAn default argument can be passed to provide an easing functions to be used, Quad being the default. All easing is based on Bezier curves and many are provided by default as seen in the `Easing.Types` enum. \n\n```swift\nenum Types {\n    case Sine\n    case Quad\n    case Cubic\n    case Quart\n    case Quint\n    case Expo\n    case Back \n    case Custom(Bezier)\n}\n ```\n \nThe last type `.Custom` will capture a custom Bezier curve and use that as an easing function. A 3rd degree (or cubic) Bezier curve is composed of 4 points called control points. The first and last is by convetion (0.0, 0.0) and (1.0, 1.0) while the other 2 define the curvature. You will not have to figure out these numbers by hand of course as they are useful tools throughout the web to help with that, [cubic-bezier](http://cubic-bezier.com/) being one of them. \n\nFor example, for a very fast start and sudden slow down animation I used [this curve](http://cubic-bezier.com/#.16,.73,.89,.24) as taken from the site, and plugged the numbers in a Bezier instance:\n\n```swift\nlet myBezier = Bezier(0.16, 0.73, 0.89, 0.24)\naView.move(to: [\"x\": 250, \"y\": 500], during: 1.0).easeInOut(.Custom(myBezier))\n ```\n \n ![Move with Custom Ease](https://github.com/mmick66/kinieta/blob/master/Assets/move.easeInOut.Custom.gif)\n \n All the curves passed are **prebaked** into tables for fast resolution!\n\n### Sequencing\n\nYou can string a few animations together very easily:\n\n```swift\nlet start = [\"x\": aView.x, \"y\": aView.y]\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).easeInOut(.Cubic)\n     .move(to: [\"x\": 300, \"y\": 200], during: 0.5).easeInOut(.Cubic)\n     .move(to: start, during: 0.5).easeInOut(.Cubic)\n```\n\nThe dictionary with the animations can be saved and passed later as the example above shows. You can also add a pause between animations by calling the `wait(for time: TimeInterval)` function:\n\n```swift\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).easeInOut(.Cubic)\n     .wait(for: 0.5)\n     .move(to: [\"x\": 300, \"y\": 200], during: 0.5).easeInOut(.Cubic)\n```\n\nFinally, you can repeat the animation sequence with the `again(times: Int = 1)` function.\n\n```swift\naView.move(to: [\"x\": 250, \"y\": 500], during: 0.5).easeInOut(.Cubic)\n     .move(to: [\"x\": 300, \"y\": 200], during: 0.5).easeInOut(.Cubic)\n     .again()\n```\n\n### Parallelizing\n\nYou can run various animations together to achieve more complicated effects. For example, we can add a short fade at the end of a move and have a single callback when everything finishes:\n\n```swift\naView.move(to: [\"x\": 200, \"y\": 500], during: 1.0).easeInOut(.Cubic)\n     .move(to: [\"a\": 0], during: 0.2).delay(for: 0.8).easeOut()\n     .parallel()\n     .complete { print(\"Finished All\") }\n```\n\n ![Move with Custom Ease](https://github.com/mmick66/kinieta/blob/master/Assets/move.easeInOut.fade.gif)\n \n #### Potential Pitfalls in Combining Groups\n \n What `.parallel()` does is to create an internal group with all the actions **that preceded the call** added inside. This might cause a problem when two or more parallel groups need to be run sequencially. For example:\n \n ```swift\naView.move(to: [\"x\": 300], during: 1.0).easeInOut() // this needs to run first,\n     .move(to: [\"x\": 200], during: 1.0).easeInOut() // then this...\n     .move(to: [\"a\": 0], during: 0.2).easeOut()     // ...parallel with this!\n     .parallel()\n```\n\nThe code above will take **all three moves** and run then in parallel, esentially ignoring the first. What we wanted however is for the first move to run on its own **followed** by the other 2 in parallel. To achive this we call the `then` property as follows:\n\n ```swift\naView.move(to: [\"x\": 300], during: 1.0).easeInOut() \n     .then        \n     .move(to: [\"x\": 200], during: 1.0).easeInOut() \n     .move(to: [\"a\": 0], during: 0.2).easeOut()     \n     .parallel()\n```\n\nFor more information on how the engine works to combine actions please consult the [wiki](https://github.com/mmick66/kinieta/wiki/Parallelizing).\n \n ### Grouping\n \n You can group multiple animation of different views and get a common complete handler when they all finish.\n \n ```swift\n Engine.shared.group([\n     aView.move(to: [\"x\": 374], during: 1.0).easeInOut(.Cubic)\n          .move(to: [\"a\": 0], during: 0.2).delay(for: 0.8).easeOut().parallel(),\n     otherView.move(to: [\"x\": 100, \"r\": 30], during: 1.0).easeInOut(.Cubic)\n]) { print(\"Both Finished\") }\n```\n\nRemember that calls to the Kinieta API return an object so one could also do:\n\n ```swift\n let move1 = aView.move(to: [\"x\": 374], during: 1.0).easeInOut(.Cubic)\n let move2 = otherView.move(to: [\"x\": 100, \"r\": 30], during: 1.0).easeInOut(.Cubic)\n Engine.shared.group([move1, move2]) { print(\"Both Finished\") }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmick66%2Fkinieta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmmick66%2Fkinieta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmick66%2Fkinieta/lists"}