# Spine 2D (/start/canvas-spine2d)





<Callout title="This page is under construction" type="warn">
  This library is currently in **testing phase**, so it may change significantly between versions.
</Callout>

**What is Spine 2D?** Spine 2D is a powerful 2D animation software specifically designed for game development. It uses a skeletal animation system, meaning that characters and objects are animated through a hierarchy of **bones** that control the movement of attached parts.

You can learn more about Spine 2D on the [official Spine 2D website](https://it.esotericsoftware.com/).

Within your **Pixi’VN** project, you can use the Spine 2D integration to create complex and smooth animations for your characters and objects.\
This integration is essentially a wrapper around the official [Spine 2D runtime for PixiJS](https://it.esotericsoftware.com/spine-pixi), allowing you to use all Spine 2D features directly inside your Pixi’VN project.

Why? [#why]

By using the Spine 2D integration in Pixi’VN, you can easily add animated components while taking advantage of both Pixi’VN and Spine 2D features, such as:

* Saving the current animation state within game save files.
* Using the <DynamicLink href="/start/canvas-position">additional Pixi’VN positioning properties</DynamicLink>.
* Starting animation sequences quickly and easily.
* Accessing additional features shared with other Pixi’VN components.

Installation [#installation]

To install the Spine 2D package in an existing JavaScript project, use one of the following commands:

<CodeBlockTabs defaultValue="npm">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npm install @drincs/pixi-vn-spine
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm add @drincs/pixi-vn-spine
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn add @drincs/pixi-vn-spine
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun add @drincs/pixi-vn-spine
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Initialize [#initialize]

Due to compatibility issues with Lazy components, the library must be imported when the game is initialized, so that it can be used inside Lazy components.

```ts title="main.ts"
import "@drincs/pixi-vn-spine"; // [!code focus]

Game.init(body, {
    // ...
});
```

Usage [#usage]

You can use the `Spine` component just like any other Pixi’VN component.\
However, you must first load the Spine 2D assets (**skeleton** and **atlas**) before using it.

This component has two required properties: `skeleton` and `atlas`, which must match the names of the loaded assets.

For example:

<CodeBlockTabs defaultValue="main.ts">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="main.ts">
      main.ts
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="assets/manifest.ts">
      assets/manifest.ts
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="main.ts">
    ```ts
    import { Assets, canvas } from "@drincs/pixi-vn";
    import { Spine } from "@drincs/pixi-vn-spine";

    await Assets.load(["spineboySkeleton", "spineboyAtlas"]);
    const spine = new Spine({
        atlas: "spineboyAtlas",
        skeleton: "spineboySkeleton",
    });
    canvas.add("spine", spine);
    ```
  </CodeBlockTab>

  <CodeBlockTab value="assets/manifest.ts">
    ```ts
    import { AssetsManifest } from "@drincs/pixi-vn";

    /**
     * Manifest for the assets used in the game.
     * You can read more about the manifest here: https://pixijs.com/8.x/guides/components/assets#loading-multiple-assets
     */
    const manifest: AssetsManifest = {
        bundles: [
            {
                name: "start",
                assets: [
                    {
                        alias: "spineboySkeleton",
                        src: "https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pro.skel",
                    },
                    {
                        alias: "spineboyAtlas",
                        src: "https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pma.atlas",
                    },
                ],
            },
        ],
    };
    export default manifest;
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Animation [#animation]

<CodeBlockTabs defaultValue="content/labels/start.label.ts">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="content/labels/start.label.ts">
      content/labels/start.label.ts
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="assets/manifest.ts">
      assets/manifest.ts
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="content/labels/start.label.ts">
    ```ts
    import { Assets, canvas, newLabel } from "@drincs/pixi-vn";
    import { Spine } from "@drincs/pixi-vn-spine";

    export const startLabel = newLabel("start", [
        async () => {
            await Assets.load(["spineboySkeleton", "spineboyAtlas"]);
            const spine = new Spine({
                atlas: "spineboyAtlas",
                skeleton: "spineboySkeleton",
                xAlign: 0.5,
                yAlign: 1,
            });
            spine.addAnimation("idle", { loop: true });
            canvas.add("spine", spine);
        },
    ]);
    ```
  </CodeBlockTab>

  <CodeBlockTab value="assets/manifest.ts">
    ```ts
    import { AssetsManifest } from "@drincs/pixi-vn";

    /**
     * Manifest for the assets used in the game.
     * You can read more about the manifest here: https://pixijs.com/8.x/guides/components/assets#loading-multiple-assets
     */
    const manifest: AssetsManifest = {
        bundles: [
            {
                name: "start",
                assets: [
                    {
                        alias: "spineboySkeleton",
                        src: "https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pro.skel",
                    },
                    {
                        alias: "spineboyAtlas",
                        src: "https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pma.atlas",
                    },
                ],
            },
        ],
    };
    export default manifest;
    ```
  </CodeBlockTab>
</CodeBlockTabs>

<AnimationExample />

Spine + motion.js animations [#spine--motionjs-animations]

<CodeBlockTabs defaultValue="content/labels/start.label.ts">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="content/labels/start.label.ts">
      content/labels/start.label.ts
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="assets/manifest.ts">
      assets/manifest.ts
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="content/labels/start.label.ts">
    ```ts
    import { Assets, canvas, newLabel } from "@drincs/pixi-vn";
    import { Spine } from "@drincs/pixi-vn-spine";

    export const startLabel = newLabel("start", [
        async () => {
            await Assets.load(["spineboySkeleton", "spineboyAtlas"]);
            const spine = new Spine({
                atlas: "spineboyAtlas",
                skeleton: "spineboySkeleton",
                xAlign: 0,
                yAlign: 1,
            });
            spine.addAnimation("walk", { loop: true });
            canvas.add("spine", spine);
            canvas.animate(
                spine,
                [
                    [{ xAlign: 1 }, { duration: 1, ease: "linear" }],
                    [{ scaleX: -1 }, { duration: 0.2 }],
                    [{ xAlign: 0 }, { duration: 1, ease: "linear" }],
                    [{ scaleX: 1 }, { duration: 0.2 }],
                ],
                { repeat: Infinity },
            );
        },
    ]);
    ```
  </CodeBlockTab>

  <CodeBlockTab value="assets/manifest.ts">
    ```ts
    import { AssetsManifest } from "@drincs/pixi-vn";

    /**
     * Manifest for the assets used in the game.
     * You can read more about the manifest here: https://pixijs.com/8.x/guides/components/assets#loading-multiple-assets
     */
    const manifest: AssetsManifest = {
        bundles: [
            {
                name: "start",
                assets: [
                    {
                        alias: "spineboySkeleton",
                        src: "https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pro.skel",
                    },
                    {
                        alias: "spineboyAtlas",
                        src: "https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pma.atlas",
                    },
                ],
            },
        ],
    };
    export default manifest;
    ```
  </CodeBlockTab>
</CodeBlockTabs>

<MotionExample />

Animations sequence [#animations-sequence]

<CodeBlockTabs defaultValue="content/labels/start.label.ts">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="content/labels/start.label.ts">
      content/labels/start.label.ts
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="assets/manifest.ts">
      assets/manifest.ts
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="content/labels/start.label.ts">
    ```ts
    import { Assets, canvas, newLabel } from "@drincs/pixi-vn";
    import { Spine } from "@drincs/pixi-vn-spine";

    export const startLabel = newLabel("start", [
        async () => {
            await Assets.load(["spineboySkeleton", "spineboyAtlas"]);
            const spine = new Spine({
                atlas: "spineboyAtlas",
                skeleton: "spineboySkeleton",
                xAlign: 0.5,
                yAlign: 1,
            });
            spine.playSequence([["idle", { loop: true, duration: 2 }], "jump"], {
                repeat: Infinity,
            });
            canvas.add("spine", spine);
        },
    ]);
    ```
  </CodeBlockTab>

  <CodeBlockTab value="assets/manifest.ts">
    ```ts
    import { AssetsManifest } from "@drincs/pixi-vn";

    /**
     * Manifest for the assets used in the game.
     * You can read more about the manifest here: https://pixijs.com/8.x/guides/components/assets#loading-multiple-assets
     */
    const manifest: AssetsManifest = {
        bundles: [
            {
                name: "start",
                assets: [
                    {
                        alias: "spineboySkeleton",
                        src: "https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pro.skel",
                    },
                    {
                        alias: "spineboyAtlas",
                        src: "https://raw.githubusercontent.com/pixijs/spine-v8/main/examples/assets/spineboy-pma.atlas",
                    },
                ],
            },
        ],
    };
    export default manifest;
    ```
  </CodeBlockTab>
</CodeBlockTabs>

<AnimationSequenceExample />
