{"id":17091778,"url":"https://github.com/psharanda/easing","last_synced_at":"2026-01-24T22:12:59.047Z","repository":{"id":200826305,"uuid":"88246208","full_name":"psharanda/Easing","owner":"psharanda","description":"Unified set of easing functions","archived":false,"fork":false,"pushed_at":"2024-06-11T23:20:56.000Z","size":853,"stargazers_count":31,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-19T11:02:37.613Z","etag":null,"topics":["easing","interpolation","transition"],"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/psharanda.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}},"created_at":"2017-04-14T07:51:40.000Z","updated_at":"2025-07-23T23:38:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"6400a4a9-cbd5-4b4c-aa30-a3c30a6765b2","html_url":"https://github.com/psharanda/Easing","commit_stats":null,"previous_names":["psharanda/easing"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/psharanda/Easing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psharanda%2FEasing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psharanda%2FEasing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psharanda%2FEasing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psharanda%2FEasing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/psharanda","download_url":"https://codeload.github.com/psharanda/Easing/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psharanda%2FEasing/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28738130,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T22:12:27.248Z","status":"ssl_error","status_checked_at":"2026-01-24T22:12:10.529Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["easing","interpolation","transition"],"created_at":"2024-10-14T13:59:30.102Z","updated_at":"2026-01-24T22:12:59.041Z","avatar_url":"https://github.com/psharanda.png","language":"Swift","readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"Readme/logo.png\" width=\"50%\" alt=\"Easing Logo\" /\u003e\n\u003c/p\u003e\nThe Easing library is a comprehensive set of easing functions, useful for interactive transitions and other time-based calculations.\n\n## Features\n\n- Easy-to-use 'swifty' API to invoke calculations\n- Unified [set](#reference) of easing functions\n- Arbitrary cubic bezier based easings (see `.cubicBezier(...)`)\n- Piecewise linear easings similar to CSS `linear()` (see `piecewiseLinear(...)`)\n- Spring-based easings with physics configuration (see `spring(...)`)\n- Emulate default easings from iOS (see `.caEaseIn`, `.caEaseOut`, `.caEaseInEaseOut`)\n- Interpolation shorthands for commonly used types like `CGPoint`, `CGSize`, `CGAffineTransform`, `UIColor` and `UIBezierPath`\n- Interactive demo app\n- Extensive test coverage and fully documented\n- Supports iOS 12.0+ / Mac OS X 10.13+ / tvOS 12.0+ / watchOS 4.0+ / visionOS 1.0+\n\n## Usage\n\n### Basic\n\n```swift\n\nlet startValue = 20.0\nlet endValue = 60.0\nlet progress = 0.5  // Assume a progress variable that ranges from 0 to 1\n\nlet valueAtProgress = Easing.cubicEaseIn.calculate(\n    d1: startValue,\n    d2: endValue,\n    g: progress\n)\n```\n\n### Ranges (g1/g2 and d1/d2)\n\n`g` is the input (often time or progress). `g1`/`g2` define the input range, and `d1`/`d2` define the output range. The easing maps `g` from `[g1, g2]` to `[d1, d2]` using the chosen curve.\n\n```swift\n// Map input range to output range\nlet output = Easing.quadraticEaseInOut.calculate(\n    g1: 0,\n    d1: 0,\n    g2: 100,\n    d2: 1,\n    g: input\n)\n```\n\nWith `clamp: true` (default), values outside `[g1, g2]` are clamped to the nearest endpoint: for example `g = -20` behaves like `g = 0` and returns `d1`, while `g = 140` behaves like `g = 100` and returns `d2`. With `clamp: false`, those inputs will extrapolate beyond the range (e.g. `g = -20` gives a value below `d1`, `g = 140` gives a value above `d2`).\n\n### Real world example\n\nImagine an interaction with a `UIScrollView` where its header is fully visible when the content offset is zero and fades out completely as the content offset exceeds 100 points. You can express this behavior with the following code in your `scrollViewDidScroll` method:\n\n```swift\nlet minOffset = 0.0\nlet alphaForMinOffset = 0.0\nlet maxOffset = 100.0\nlet alphaForMaxOffset = 1.0\nlet offset = scrollView.contentOffset.y\n\nheaderView.alpha = Easing.quadraticEaseInOut.calculate(\n    g1: minOffset,\n    d1: alphaForMinOffset,\n    g2: maxOffset,\n    d2: alphaForMaxOffset,\n    g: offset\n)\n```\n\n### Interpolatable\n\n```swift\nlet startTransform = CGAffineTransform.identity\nlet endTransform = CGAffineTransform(scaleX: 2, y: 2)\nlet progress = 0.5  // Assume a progress variable that ranges from 0 to 1\n\nview.transform = startTransform.interpolate(to: endTransform,\n                                      progress: progress,\n                                        easing: .linear)\n\n```\n\n### Piecewise linear (CSS `linear()` style)\n\nCSS `linear(0, 0.25 75%, 1)` translates to:\n\n```swift\nlet easing = Easing.piecewiseLinear([\n    PiecewiseLinearStop(0),  // x defaults to 0\n    PiecewiseLinearStop(0.25, at: 0.75), // explicit stop position\n    PiecewiseLinearStop(1) // x defaults to 1\n])\n```\n\n### Spring\n\n```swift\nlet swiftUISpring = Easing.spring(.swiftUISpring, initialVelocity: 0)\n\nlet customSpring = Easing.spring(\n    mass: 1,\n    stiffness: 100,\n    damping: 10,\n    initialVelocity: 0,\n    duration: 1\n)\n```\n\n## Reference\n\n|                        Easing                         |                                                                                                                                               |\n| :---------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------: |\n|                       `.linear`                       |                       \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_linear@3x.png\" width=\"100\"/\u003e                       |\n|          `.piecewiseLinear(0, 0.25@0.75, 1)`          |          \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_piecewiseLinear_0__0_25_0_75__1_@3x.png\" width=\"100\"/\u003e          |\n|              `.piecewiseLinear(spring)`               |              \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_piecewiseLinear_spring_@3x.png\" width=\"100\"/\u003e               |\n|               `.spring(.swiftUISpring)`               |               \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_spring__swiftUISpring_@3x.png\" width=\"100\"/\u003e               |\n|         `.spring(.swiftUIInteractiveSpring)`          |         \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_spring__swiftUIInteractiveSpring_@3x.png\" width=\"100\"/\u003e          |\n|       `.spring(dampingRatio:0.7,response:0.4)`        |       \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_spring_dampingRatio_0_7_response_0_4_@3x.png\" width=\"100\"/\u003e        |\n|     `.spring(response:0.5,dampingFraction:0.825)`     |     \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_spring_response_0_5_dampingFraction_0_825_@3x.png\" width=\"100\"/\u003e     |\n| `.spring(mass:1,stiffness:100,damping:10,duration:1)` | \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_spring_mass_1_stiffness_100_damping_10_duration_1_@3x.png\" width=\"100\"/\u003e |\n|                     `.smoothStep`                     |                     \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_smoothStep@3x.png\" width=\"100\"/\u003e                     |\n|                    `.smootherStep`                    |                    \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_smootherStep@3x.png\" width=\"100\"/\u003e                    |\n|                  `.quadraticEaseIn`                   |                  \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quadraticEaseIn@3x.png\" width=\"100\"/\u003e                   |\n|                  `.quadraticEaseOut`                  |                  \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quadraticEaseOut@3x.png\" width=\"100\"/\u003e                  |\n|                 `.quadraticEaseInOut`                 |                 \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quadraticEaseInOut@3x.png\" width=\"100\"/\u003e                 |\n|                    `.cubicEaseIn`                     |                    \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_cubicEaseIn@3x.png\" width=\"100\"/\u003e                     |\n|                    `.cubicEaseOut`                    |                    \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_cubicEaseOut@3x.png\" width=\"100\"/\u003e                    |\n|                   `.cubicEaseInOut`                   |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_cubicEaseInOut@3x.png\" width=\"100\"/\u003e                   |\n|                   `.quarticEaseIn`                    |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quarticEaseIn@3x.png\" width=\"100\"/\u003e                    |\n|                   `.quarticEaseOut`                   |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quarticEaseOut@3x.png\" width=\"100\"/\u003e                   |\n|                  `.quarticEaseInOut`                  |                  \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quarticEaseInOut@3x.png\" width=\"100\"/\u003e                  |\n|                   `.quinticEaseIn`                    |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quinticEaseIn@3x.png\" width=\"100\"/\u003e                    |\n|                   `.quinticEaseOut`                   |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quinticEaseOut@3x.png\" width=\"100\"/\u003e                   |\n|                  `.quinticEaseInOut`                  |                  \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_quinticEaseInOut@3x.png\" width=\"100\"/\u003e                  |\n|                     `.sineEaseIn`                     |                     \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_sineEaseIn@3x.png\" width=\"100\"/\u003e                     |\n|                    `.sineEaseOut`                     |                    \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_sineEaseOut@3x.png\" width=\"100\"/\u003e                     |\n|                   `.sineEaseInOut`                    |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_sineEaseInOut@3x.png\" width=\"100\"/\u003e                    |\n|                   `.circularEaseIn`                   |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_circularEaseIn@3x.png\" width=\"100\"/\u003e                   |\n|                  `.circularEaseOut`                   |                  \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_circularEaseOut@3x.png\" width=\"100\"/\u003e                   |\n|                 `.circularEaseInOut`                  |                 \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_circularEaseInOut@3x.png\" width=\"100\"/\u003e                  |\n|                 `.exponentialEaseIn`                  |                 \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_exponentialEaseIn@3x.png\" width=\"100\"/\u003e                  |\n|                 `.exponentialEaseOut`                 |                 \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_exponentialEaseOut@3x.png\" width=\"100\"/\u003e                 |\n|                `.exponentialEaseInOut`                |                \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_exponentialEaseInOut@3x.png\" width=\"100\"/\u003e                |\n|                   `.elasticEaseIn`                    |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_elasticEaseIn@3x.png\" width=\"100\"/\u003e                    |\n|                   `.elasticEaseOut`                   |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_elasticEaseOut@3x.png\" width=\"100\"/\u003e                   |\n|                  `.elasticEaseInOut`                  |                  \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_elasticEaseInOut@3x.png\" width=\"100\"/\u003e                  |\n|                     `.backEaseIn`                     |                     \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_backEaseIn@3x.png\" width=\"100\"/\u003e                     |\n|                    `.backEaseOut`                     |                    \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_backEaseOut@3x.png\" width=\"100\"/\u003e                     |\n|                   `.backEaseInOut`                    |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_backEaseInOut@3x.png\" width=\"100\"/\u003e                    |\n|                    `.bounceEaseIn`                    |                    \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_bounceEaseIn@3x.png\" width=\"100\"/\u003e                    |\n|                   `.bounceEaseOut`                    |                   \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_bounceEaseOut@3x.png\" width=\"100\"/\u003e                    |\n|                  `.bounceEaseInOut`                   |                  \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_bounceEaseInOut@3x.png\" width=\"100\"/\u003e                   |\n|                      `.caEaseIn`                      |                      \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_caEaseIn@3x.png\" width=\"100\"/\u003e                      |\n|                     `.caEaseOut`                      |                     \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_caEaseOut@3x.png\" width=\"100\"/\u003e                      |\n|                  `.caEaseInEaseOut`                   |                  \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_caEaseInEaseOut@3x.png\" width=\"100\"/\u003e                   |\n|        `.cubicBezier(0.11, 0.87, 0.21, -0.88)`        |        \u003cimg src=\"Demo/Ref/ReferenceImages_64/DemoTests.EasingDemoTests/test_cubicBezier_0_11__0_87__0_21__0_88_@3x.png\" width=\"100\"/\u003e         |\n\n## Demo app\n\nIn the repo, you will find an interactive demo iOS app to experiment with different easings and discover the most suitable one for your needs.\n\n\u003cimg src=\"Readme/demo.png\" width=\"25%\" align=left/\u003e\u003cimg src=\"Readme/demo.gif\" width=\"25%\" /\u003e\n\n## Integration\n\nUse Swift Package Manager and add dependency to `Package.swift` file.\n\n```swift\n  dependencies: [\n    .package(url: \"https://github.com/psharanda/Easing.git\", .upToNextMajor(from: \"4.0.0\"))\n  ]\n```\n\nAlternatively, in Xcode select `File \u003e Add Package Dependencies…` and add Easing repository URL:\n\n```\nhttps://github.com/psharanda/Easing.git\n```\n\n## References\n\nThe main set of easing functions is a Swift port of https://github.com/warrenm/AHEasing and https://github.com/ai/easings.net\n\n`CubicBezierInterpolator` is a Swift port of `nsSMILKeySpline` code from Mozilla https://github.com/mozilla-services/services-central-legacy/blob/master/content/smil/nsSMILKeySpline.cpp\n\n## Contributing\n\nWe welcome contributions! If you find a bug, have a feature request, or want to contribute code, please open an issue or submit a pull request.\n\n## License\n\nEasing is available under the MIT license. See the LICENSE file for more info.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsharanda%2Feasing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpsharanda%2Feasing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsharanda%2Feasing/lists"}