From a layered PSD to an animated Spine character in PixiJS 8
Layered art to a character playing in PixiJS 8: the rig is made from a PSD, exported as Spine 4.2 JSON and loaded with the official spine-pixi-v8 runtime. The demo below is the finished result — click it to switch animations.
The result
The same cat as in the Phaser 4 version of this walk-through: idle loops, hack, glitch and bigwin play once and return to it. Open the demo on its own and view the source. Shipping in Unity instead? The Unity version.
The rig
A layered PSD with 15 parts, rigged in Riggy by describing the motion in chat — “the cat nods its head to music at 90 BPM”, “lifts its paw and hits the keys sharply”. 18 bones and four animations. The export is skeleton.json, skeleton.atlas and page.png; a skeleton rigged by hand in the Spine editor loads the same way.
Add PixiJS and the Spine runtime
Esoteric Software publishes @esotericsoftware/spine-pixi-v8 for PixiJS 8 and spine-pixi-v7 for PixiJS 7. The latest tag already points to Spine 4.3, so pin a 4.2 version for a 4.2 export — the runtime's major and minor version must match the export's. From a CDN:
<script src="https://cdn.jsdelivr.net/npm/pixi.js@8.21.0/dist/pixi.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@esotericsoftware/spine-pixi-v8@4.2.120/dist/iife/spine-pixi-v8.min.js"></script>
or from npm:
npm install pixi.js@8.21.0 @esotericsoftware/spine-pixi-v8@4.2.120
Unlike Phaser, there is no plugin to register: loading the runtime teaches PIXI.Assets the Spine file types.
Load the skeleton and play it
Add both files to the asset loader; the atlas brings its page image from the same folder:
PIXI.Assets.add({ alias: "catData", src: "assets/skeleton.json" });
PIXI.Assets.add({ alias: "catAtlas", src: "assets/skeleton.atlas" });
await PIXI.Assets.load(["catData", "catAtlas"]);Create the Spine object from the two aliases, set a default mix and start the idle loop:
const cat = spine.Spine.from({ skeleton: "catData", atlas: "catAtlas", scale: 0.45 });
// blend 0.2 s between any two animations instead of snapping
cat.state.data.defaultMix = 0.2;
cat.state.setAnimation(0, "idle", true);
app.stage.addChild(cat);The object's position is the skeleton's root bone — the bottom center for this rig — so place it at the bottom center of the screen:
cat.x = app.screen.width / 2;
cat.y = app.screen.height - 20;One-shots that return to the loop
Play a one-shot on the same track and queue the loop right behind it:
// play the one-shot once, then go back to the idle loop
cat.state.setAnimation(0, name, false);
cat.state.addAnimation(0, "idle", true, 0);cat.state is the same AnimationState as in every Spine runtime, so the calls are identical to the Phaser version — only loading and placing differ.
When it does not load
- Region not found in atlas — the skeleton and the atlas are from different exports.
- Animation not found — the name in
setAnimationdiffers from the skeleton, case included. - Moving the same files to Phaser? Its plugin, unlike PixiJS, fails on an atlas that starts with an empty line — see the Phaser walk-through.
- Anything else: Spine runtime errors, explained, or the Spine JSON validator.
Licensing
spine-pixi-v8 is part of the Spine Runtimes. Shipping a game with them requires a Spine license from Esoteric Software, whoever made the skeleton — see the licensing page. Riggy is an independent tool, not affiliated with Esoteric Software or PixiJS.