{"id":15061047,"url":"https://github.com/reececomo/pixijs-actions","last_synced_at":"2025-06-21T16:36:32.009Z","repository":{"id":234923544,"uuid":"789768762","full_name":"reececomo/pixijs-actions","owner":"reececomo","description":"🎬 Powerful, high-performance animations for PixiJS","archived":false,"fork":false,"pushed_at":"2025-06-04T05:06:52.000Z","size":400,"stargazers_count":14,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-04T11:58:55.140Z","etag":null,"topics":["actions","animate","animation","cocos2d","cocos2d-x","interpolation","pixi","pixi-action","pixi-js","pixijs","skaction","transition","tween"],"latest_commit_sha":null,"homepage":"https://npmjs.com/pixijs-actions","language":"TypeScript","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/reececomo.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":"2024-04-21T14:05:51.000Z","updated_at":"2025-06-04T05:06:54.000Z","dependencies_parsed_at":"2024-04-21T15:25:23.716Z","dependency_job_id":"832a3adc-af30-4b99-a6c4-b2a19cb114fd","html_url":"https://github.com/reececomo/pixijs-actions","commit_stats":null,"previous_names":["reececomo/pixijs-actions"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/reececomo/pixijs-actions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-actions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-actions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-actions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-actions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reececomo","download_url":"https://codeload.github.com/reececomo/pixijs-actions/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-actions/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261159509,"owners_count":23118027,"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":["actions","animate","animation","cocos2d","cocos2d-x","interpolation","pixi","pixi-action","pixi-js","pixijs","skaction","transition","tween"],"created_at":"2024-09-24T23:08:34.303Z","updated_at":"2025-06-21T16:36:26.988Z","avatar_url":"https://github.com/reececomo.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🎬 pixijs-actions \u0026nbsp;[![NPM version](https://img.shields.io/npm/v/pixijs-actions.svg)](https://www.npmjs.com/package/pixijs-actions) [![Minzipped](https://badgen.net/bundlephobia/minzip/pixijs-actions@latest)](https://bundlephobia.com/package/pixijs-actions) [![Downloads per month](https://img.shields.io/npm/dm/pixijs-actions.svg)](https://www.npmjs.com/package/pixijs-actions) [![Tests](https://github.com/reececomo/pixijs-actions/actions/workflows/tests.yml/badge.svg)](https://github.com/reececomo/pixijs-actions/actions/workflows/tests.yml) [![License](https://badgen.net/npm/license/pixijs-actions)](https://github.com/reececomo/pixijs-actions/blob/main/LICENSE)\n\n⚡ Powerful, high-performance animations for PixiJS\n\n| | |\n| ------ | ------ |\n| 🔮 Simple, declarative API | 🎬 Based on [Cocos2d](https://docs.cocos2d-x.org/cocos2d-x/v3/en/actions/getting_started.html)/[SKActions](https://developer.apple.com/documentation/spritekit/getting_started_with_actions) |\n| 🚀 35+ [built-in actions](#action-initializers), 30+ [timing modes](#timing-modes) | 🔀 Reuseable, chainable \u0026 reversible |\n| 🍃 No dependencies \u0026 tree-shakeable | ⌚ Full speed/pausing control |\n| 🤏 \u003c5kB minzipped | ✨ Supports PixiJS 8+, 7+, 6.3+ |\n\n\n## Sample Usage\n\n*Create, configure, and run animations \u0026 actions.*\n\n```ts\n// Define an action\nconst spinAction = Action.sequence([\n  Action.rotateByDegrees(360, 0.2).easeIn(),\n  Action.fadeOut(0.2),\n  Action.run(() =\u003e console.info('✨ done!'))\n]);\n\n// Run an action\nmySprite.run(spinAction);\n```\n\n## Getting Started with PixiJS Actions\n\n*Everything you need to quickly build beautiful animations.*\n\n**PixiJS Actions** is based off the idiomatic and expressive [**SKActions API**](https://developer.apple.com/documentation/spritekit/getting_started_with_actions), extending `Container` to add first-class support for running and managing actions.\n\nThe core concepts are:\n\n1. **Nodes:** _Any container (e.g. `Container`, `Sprite`, `Graphics`)_\n2. **Actions:** _Stateless, reusable recipes_ (e.g. animations, triggers, and more)\n3. **TimingMode \u0026 speed:** _Controls for the speed \u0026 smoothness of actions and animations_\n\n\u003e [!NOTE]\n\u003e _See [Timing Modes](#timing-modes) and [Manipulating Action Speed](#manipulating-action-speed) for more information._\n\n\n## Installation\n\n*Quick start guide.*\n\n**1.** Install the latest `pixijs-actions` package:\n\n```sh\n# npm\nnpm install pixijs-actions -D\n\n# yarn\nyarn add pixijs-actions --dev\n```\n\n**2.** Register the mixin \u0026 ticker:\n\n```ts\nimport * as PIXI from 'pixi.js';\nimport { Action, registerPixiJSActionsMixin } from 'pixijs-actions';\n\n// register container mixin\nregisterPixiJSActionsMixin(PIXI.Container);\n\n// register `Action.tick(...)` with shared ticker\nTicker.shared.add(ticker =\u003e Action.tick(ticker.elapsedMS));\n```\n\n\u003e [!TIP]\n\u003e **PixiJS 7 / 6.3+:**\n\u003e \n\u003e ```ts\n\u003e Ticker.shared.add(() =\u003e Action.tick(Ticker.shared.elapsedMS));\n\u003e // or\n\u003e Ticker.shared.add((dt) =\u003e Action.tick(dt));\n\u003e ```\n\n\u003e [!NOTE]\n\u003e _If not using a PixiJS ticker, then just put `Action.tick(elapsedMs)` in the appropriate equivalent place (i.e. your `requestAnimationFrame()` render loop)._\n\n**3.** Done!\n\n✨ You are now ready to run your first action!\n\n## Running Actions\n\n*Running actions in your canvas.*\n\n```ts\n// Hide me instantly!\nmySprite.run(Action.hide(), () =\u003e {\n  console.log('where did I go?');\n});\n```\n\nNodes are extended with a few new methods and properties to make it easy to interact with actions.\n\n| Property | Description |\n| :----- | :------ |\n| `speed` | A speed modifier applied to all actions executed by the node and its descendants. Defaults to `1.0`. |\n| `isPaused` | A boolean value that determines whether actions on the node and its descendants are processed. Defaults to `false`. |\n\n| Method | Description |\n| :----- | :------ |\n| `run(action)` | Run an action. |\n| `run(action, completion)` | Run an action with a completion handler. |\n| `runWithKey(action, withKey)` | Run an action, and store it so it can be retrieved later. |\n| `runAsPromise(action): Promise\u003cvoid\u003e` | Run an action as a promise. |\n| `action(forKey): Action \\| undefined` | Return an action associated with a specified key. |\n| `hasActions(): boolean` | Return a boolean indicating whether the node is executing actions. |\n| `removeAllActions(): void` | End and removes all actions from the node. |\n| `removeAction(forKey): void` | Remove an action associated with a specified key. |\n\n### Running Identifiable Actions\n\n```ts\n// Repeat an action forever!\nconst spin = Action.repeatForever(Action.rotateBy(5, 1.0));\nmySprite.runWithKey(spin, 'spinForever');\n\n// Or remove it later.\nmySprite.removeAction('spinForever');\n```\n\n### Pausing All Actions\n\n```ts\nmySprite.isPaused = true;\n// All actions will stop running.\n```\n\n### Manipulating Action Speed\n\nSpeed can be manipulated on both actions and nodes.\n\n```ts\nconst moveAction = Action.moveByX(10, 4.0);\nmoveAction.speed = 2.0;\n// moveAction will now take only 2 seconds instead of 4.\n\nconst repeatAction = Action.repeat(moveAction, 5);\nrepeatAction.speed = 2.0;\n// Each moveAction will only take 1 second, for a total of 5 seconds.\n\nmySprite.run(moveAction);\nmySprite.speed = 2.0;\n// mySprite is running at 2x speed!\n// The entire action should now take ~2.5 seconds.\n\nmySprite.parent!.speed = 1 / 4;\n// Now we've slowed down mySprite's parent.\n// The entire action will now take ~10 seconds.\n```\n\n\u003e [!NOTE]\n\u003e Changes to nodes' `speed` will take effect immediately, however changes to an `Action` initializer's `speed` or `timingMode` will not affect any actions that have already begun running.\n\n## Action Initializers\n\n*Combine these initializers to create expressive animations and behaviors.*\n\nMost actions implement specific predefined animations that are ready to use. If your animation needs fall outside of the suite provided here, then you should implement a custom action (see [Creating Custom Actions](#creating-custom-actions)).\n\n| Action | Description | Reversible? |\n| :----- | :---------- | :---------- |\n|***Chaining Actions***|||\n| `Action.group(actions)` | Run multiple actions in parallel. | Yes |\n| `Action.sequence(actions)` | Run multiple actions sequentially. | Yes |\n| `Action.repeat(action, count)` | Repeat an action a specified number of times. | Yes |\n| `Action.repeatForever(action)` | Repeat an action indefinitely. | Yes |\n|***Animating a Node's Position in a Linear Path***|||\n| `Action.moveBy(vector, duration)` | Move a node by a relative vector `{ x, y }` (e.g. `PIXI.Point`). | Yes |\n| `Action.moveBy(dx, dy, duration)` | Move a node by relative values. | Yes |\n| `Action.moveByX(dx, duration)` | Move a node horizontally by a relative value. | Yes |\n| `Action.moveByY(dy, duration)` | Move a node vertically by a relative value. | Yes |\n| `Action.moveTo(position, duration)` | Move a node to a specified position `{ x, y }` (e.g. `PIXI.Point`, `PIXI.Container`). |  _*No_ |\n| `Action.moveTo(x, y, duration)` | Move a node to a specified position. |  _*No_ |\n| `Action.moveToX(x, duration)` | Move a node to a specified horizontal position. |  _*No_ |\n| `Action.moveToY(y, duration)` | Move a node to a specified vertical position. |  _*No_ |\n|***Animating a Node's Position Along a Custom Path***|||\n| `Action.follow(path, duration)` | Move a node along a path, optionally orienting the node to the path. |  Yes | Yes |\n| `Action.followAtSpeed(path, speed)` | Move a node along a path at a specified speed, optionally orienting the node to the path. |  Yes |\n|***Animating the Rotation of a Node***|||\n| `Action.rotateBy(delta, duration)` | Rotate a node by a relative value (in radians). | Yes |\n| `Action.rotateByDegrees(delta, duration)` | Rotate a node by a relative value (in degrees). | Yes |\n| `Action.rotateTo(radians, duration)` | Rotate a node to a specified value (in radians). |  _*No_ |\n| `Action.rotateToDegrees(degrees, duration)` | Rotate a node to a specified value (in degrees). | _*No_ |\n|***Animating the Scaling of a Node***|||\n| `Action.scaleBy(vector, duration)` | Scale a node by a relative vector `{ x, y }` (e.g. `PIXI.Point`). | Yes |\n| `Action.scaleBy(scale, duration)` | Scale a node by a relative value. | Yes |\n| `Action.scaleBy(dx, dy, duration)` | Scale a node in each axis by relative values. | Yes |\n| `Action.scaleByX(dx, duration)` | Scale a node horizontally by a relative value. | Yes |\n| `Action.scaleByY(dy, duration)` | Scale a node vertically by a relative value. | Yes |\n| `Action.scaleTo(size, duration)` | Scale a node to achieve a specified size `{ width, height }` (e.g. `PIXI.ISize`, `PIXI.Container`). |  _*No_ |\n| `Action.scaleTo(scale, duration)` | Scale a node to a specified value. |  _*No_ |\n| `Action.scaleTo(x, y, duration)` | Scale a node in each axis to specified values. |  _*No_ |\n| `Action.scaleToX(x, duration)` | Scale a node horizontally to a specified value. |  _*No_ |\n| `Action.scaleToY(y, duration)` | Scale a node vertically to a specified value. |  _*No_ |\n|***Animating the Transparency of a Node***|||\n| `Action.fadeIn(duration)` | Fade the alpha to `1.0`. | Yes |\n| `Action.fadeOut(duration)` | Fade the alpha to `0.0`. | Yes |\n| `Action.fadeAlphaBy(delta, duration)` | Fade the alpha by a relative value. | Yes |\n| `Action.fadeAlphaTo(alpha, duration)` | Fade the alpha to a specified value. |  _*No_ |\n|***Animating a Sprite by Changing its Texture***|||\n| `Action.animate({frames, …})` | Animate a sprite by changing its texture. See options. | Yes |\n| `Action.animate({spritesheet, …})` | Animate a sprite by changing its texture using a spritesheet's frames. See options. | Yes |\n|***Controlling a Node's Visibility***|||\n| `Action.unhide()` | Set a node's `visible` property to `true`. | Yes |\n| `Action.hide()` | Set a node's `visible` property to `false`. | Yes |\n|***Removing a Node from the Canvas***|||\n| `Action.destroy(options?)` | Remove and destroy a node and its actions. |  _†Identical_ |\n| `Action.removeFromParent()` | Remove a node from its parent. | _†Identical_ |\n|***Running Actions on Children***|||\n| `Action.runOnChild(childLabel, action)` | Add an action to a child node. | Yes |\n|***Delaying Actions***|||\n| `Action.waitForDuration(duration)` | Idle for a specified period of time. | _†Identical_ |\n| `Action.waitForDurationWithRange(duration, range)` | Idle for a randomized period of time. | _†Identical_ |\n|***Triggers and Custom Actions***|||\n| `Action.run(callback)` | Execute a custom function. | _†Identical_ |\n| `Action.customAction(duration, callback)` | Execute a custom stepping function over the action duration. | _†Identical_ |\n|***Manipulating the Action Speed of a Node***|||\n| `Action.speedBy(delta, duration)` | Change how fast a node executes its actions by a relative value. | Yes |\n| `Action.speedTo(speed, duration)` | Set how fast a node executes actions to a specified value. |  _*No_ |\n\n\u003e [!IMPORTANT]\n\u003e #### Reversing Actions\n\u003e Every action initializer has a `.reversed()` method which will return a new action. Some actions are **not reversible**, and these cases are noted in the table above:\n\u003e - _**†Identical**_ \u0026mdash; The reversed action is identical to the original action.\n\u003e - _**\\*No**_ \u0026mdash; The reversed action will idle for the equivalent duration.\n\n### Action Chaining\n\nMany actions can be joined together using `Action.sequence()`, `Action.group()`, `Action.repeat()` and `Action.repeatForever()` to quickly create complex animations:\n\n```ts\nimport { Action } from 'pixijs-actions';\n\n// Expand and contract smoothly over 2 seconds\nconst pulsate = Action.sequence([\n  Action.scaleTo(1.5, 1.0).easeOut(),\n  Action.scaleTo(1, 1.0).easeIn()\n]);\n\n// Follow a complex path (e.g. a bezier curve)\nconst path = [\n  { x: 0, y: 0 },\n  { x: 100, y: 0 },\n  { x: 100, y: 100 },\n  { x: 200, y: 200 }\n];\nconst followPath = Action.follow(path, 5.0);\n\n// Create a 10 second loop that goes back and forth\nconst moveBackAndForthWhilePulsating = Action.group([\n  Action.repeat(pulsate, 5),\n  Action.sequence([followPath, followPath.reversed()]),\n]);\n\n// ✨ Animate continuously\nmySprite.run(Action.repeatForever(moveBackAndForthWhilePulsating));\n```\n\n## Timing Modes\n\nEvery action has a `timingMode` which controls the timing curve of its execution.\n\nThe default timingMode for all actions is `TimingMode.linear`, which causes an animation to occur evenly over its duration.\n\nYou can customize the speed curve of actions in many ways:\n\n```ts\n// Default easings:\nAction.fadeIn(0.3).easeIn();\nAction.fadeIn(0.3).easeOut();\nAction.fadeIn(0.3).easeInOut();\n\n// Set a specific TimingMode:\nAction.fadeIn(0.3).setTimingMode(TimingMode.easeInOutCubic);\n\n// Set a custom timing function:\nAction.fadeIn(0.3).setTimingMode(x =\u003e x * x);\n```\n\n\u003e [!IMPORTANT]\n\u003e **Timing Mutators:** The `.easeIn()`, `.easeOut()`, `.easeInOut()`, `setTimingMode(…)`, `setSpeed(…)` methods mutate the underlying action.\n\n### Built-in TimingMode Options\n\nSee the following table for default `TimingMode` options.\n\n| Pattern | Ease In, Ease Out | Ease In | Ease Out | Description |\n| --------------- | ----- | -- | --- | ----------- |\n| **Linear** | `linear` | - | - | Constant motion with no acceleration or deceleration. |\n| **Sine** | `easeInOutSine` | `easeInSine` | `easeOutSine` | Gentle start and end, with accelerated motion in the middle. |\n| **Circular** | `easeInOutCirc` | `easeInCirc` | `easeOutCirc` | Smooth start and end, faster acceleration in the middle, circular motion. |\n| **Cubic** | `easeInOutCubic` | `easeInCubic` | `easeOutCubic` | Gradual acceleration and deceleration, smooth motion throughout. |\n| **Quadratic** | `easeInOutQuad` | `easeInQuad` | `easeOutQuad` | Smooth acceleration and deceleration, starts and ends slowly, faster in the middle. |\n| **Quartic** | `easeInOutQuart` | `easeInQuart` | `easeOutQuart` | Slower start and end, increased acceleration in the middle. |\n| **Quintic** | `easeInOutQuint` | `easeInQuint` | `easeOutQuint` | Very gradual start and end, smoother acceleration in the middle. |\n| **Exponential** | `easeInOutExpo` | `easeInExpo` | `easeOutExpo` | Very slow start, exponential acceleration, slow end. |\n| **Back** | `easeInOutBack` | `easeInBack` | `easeOutBack` | Starts slowly, overshoots slightly, settles into final position. |\n| **Bounce** | `easeInOutBounce` | `easeInBounce` | `easeOutBounce` | Bouncy effect at the start or end, with multiple rebounds. |\n| **Elastic** | `easeInOutElastic` | `easeInElastic` | `easeOutElastic` | Stretchy motion with overshoot and multiple oscillations. |\n\n### Default Timing Modes\n\nThe `.easeIn()`, `.easeOut()`, `.easeInOut()`, and `.linear()` mutator methods on `Action` instances will set the timing mode of that action to the global default timing mode for that curve type.\n\n| TimingMode mutator | Global setting | Default value |\n| :--- | :--- | :--- |\n| `action.easeIn()` | `Action.DefaultTimingModeEaseIn` | `TimingMode.easeInSine` |\n| `action.easeOut()` | `Action.DefaultTimingModeEaseOut` | `TimingMode.easeOutSine` |\n| `action.easeInOut()` | `Action.DefaultTimingModeEaseInOut` | `TimingMode.easeInOutSine` |\n| `action.linear()` | _(n/a)_ | `TimingMode.linear` |\n\nGlobal default timing modes can be set like so:\n\n```ts\n// set default\nAction.DefaultTimingModeEaseIn = TimingMode.easeInQuad;\n\n// apply\nmyNode.run(myAction.easeIn());\n\nmyAction.timingMode\n// TimingMode.easeInQuad\n```\n\n## Creating Custom Actions\n\nBeyond combining chaining actions like `sequence()`, `group()`, `repeat()` and `repeatForever()`, you can provide code that implements your own action.\n\n### Composite Actions\n\nActions are stateless and reusable, so you can create complex animations once, and then run them on many nodes.\n\n```ts\n/** A nice gentle rock back and forth. */\nconst rockBackAndForth = Action.repeatForever(\n  Action.group([\n    Action.sequence([\n      Action.moveByX(5, 0.33).easeOut(),\n      Action.moveByX(-10, 0.34).easeInOut(),\n      Action.moveByX(5, 0.33).easeIn(),\n    ]),\n    Action.sequence([\n      Action.rotateByDegrees(-2, 0.33).easeOut(),\n      Action.rotateByDegrees(4, 0.34).easeInOut(),\n      Action.rotateByDegrees(-2, 0.33).easeIn(),\n    ]),\n  ])\n);\n\n// Run it over here\nsomeSprite.run(rockBackAndForth);\n\n// Run it somewhere else\nsomeOtherContainer.run(rockBackAndForth);\n```\n\nYou can combine these with dynamic actions for more variety:\n\n```ts\nconst MyActions = {\n  squash: (amount: number, duration: number = 0.3) =\u003e Action.sequence([\n    Action.scaleTo(amount, 1 / amount, duration / 2).easeOut(),\n    Action.scaleTo(1, duration / 2).easeIn()\n  ]),\n  stretch: (amount: number, duration: number = 0.3) =\u003e Action.sequence([\n    Action.scaleTo(1 / amount, amount, duration / 2).easeOut(),\n    Action.scaleTo(1, duration / 2).easeIn()\n  ]),\n  squashAndStretch: (amount: number, duration: number = 0.3) =\u003e Action.sequence([\n    MyActions.squash(amount, duration / 2),\n    MyActions.stretch(amount, duration / 2),\n  ]),\n};\n\n// Small squish!\nmySprite.run(MyActions.squashAndStretch(1.25));\n\n// Big squish!\nmySprite.run(MyActions.squashAndStretch(2.0));\n```\n\n### Custom Action (Basic)\n\nYou can use the built-in `Action.customAction(duration, stepHandler)` to provide custom actions:\n\n```ts\nconst rainbowColors = Action.customAction(5.0, (target, t, dt) =\u003e {\n  // Calculate color based on time \"t\".\n  const colorR = Math.sin(0.3 * t + 0) * 127 + 128;\n  const colorG = Math.sin(0.3 * t + 2) * 127 + 128;\n  const colorB = Math.sin(0.3 * t + 4) * 127 + 128;\n\n  // Apply random color with time-based variation.\n  target.tint = (colorR \u003c\u003c 16) + (colorG \u003c\u003c 8) + colorB;\n});\n\n// Start rainbow effect\nmySprite.runWithKey(Action.repeatForever(rainbowColors), 'rainbow');\n\n// Stop rainbow effect\nmySprite.removeAction('rainbow');\n```\n\n\u003e **Step functions:**\n\u003e - `target` = The node the aciton is runnning against.\n\u003e - `t` = Progress of time from 0 to 1, which has been passed through the `timingMode` function.\n\u003e - `dt` = delta/change in `t` since last step. Use for relative actions.\n\u003e\n\u003e _Note: `t` can be outside of 0 and 1 in timing mode functions which overshoot, such as `TimingMode.easeInOutBack`._\n\nThis function will be called as many times as the renderer asks over the course of its duration.\n\n### Custom Action (with State)\n\nHere is a practical example:\n\n```ts\n// Create a custom action that relies on\n// state (radius, inital target position).\nconst makeOrbitAction = (\n  radius: number,\n  duration: number\n): Action =\u003e {\n  let startPos: PIXI.IPointData;\n\n  return Action.customAction(duration, (target, t, td) =\u003e {\n    if (!startPos) {\n      // Capture on first run\n      startPos = { x: target.x, y: target.y };\n    }\n\n    const angle = Math.PI * 2 * t;\n\n    target.position.set(\n      startPos.x + radius * Math.cos(angle),\n      startPos.y + radius * Math.sin(angle)\n    );\n  });\n};\n\n// Run the custom action\nmySprite.run(\n  Action.repeatForever(makeOrbitAction(10, 15.0))\n);\n```\n\n## Container Lifecycle\n\nAs soon as a node is destroyed, all actions on the node are canceled (including chained actions like `Action.group()` and `Action.sequence()`).\n\n### Destructive Actions\n\nThe **destroy(…)** action will remove a node from the scene graph, canceling any other remaining or in-progress animations.\n\n```ts\nconst killAndRemoveAnimation = Action.sequence([\n  Action.group([\n    Action.rotateByDegrees( 360, 1.0 ).easeIn(),\n    Action.fadeOut( 1.0 )\n  ]),\n  Action.destroy(true),\n  Action.run(() =\u003e console.info('✨ done!')) // 🚨 Unreachable!\n]);\n\nmySprite.run( killAndRemoveAnimation );\n```\n\n### Contributions\n\n**PixiJS Actions** was originally based on [srpatel](https://github.com/srpatel)'s awesome [pixi-actions](https://github.com/srpatel/pixi-actions) library.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freececomo%2Fpixijs-actions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freececomo%2Fpixijs-actions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freececomo%2Fpixijs-actions/lists"}