From a layered PSD to an animated Spine character in Phaser 4
A step-by-step walk from layered art to a character that plays in a Phaser 4 game: the rig is made from a PSD, exported as Spine 4.2 JSON and loaded with the official Spine plugin for Phaser. The demo below is the finished result — click it to switch animations.
The result
A cat at a laptop with four animations: idle (a loop, nodding to the music), hack, glitch and bigwin (one-shots that return to idle). The whole demo is one HTML page and a short main.js; open it on its own and view the source. Using PixiJS instead? The same rig in PixiJS 8; Unity? The Unity version.
From layered art to a rig
The art is a layered PSD with 15 parts: body, head, two eyes and pupils, headphones, the arm in two pieces, laptop screen and keyboard, laces and tail. Each part on its own layer is all a skeleton needs — bones move layers, they do not redraw them.
The rig was made in Riggy by describing the motion in chat:
- “idle — the cat nods its head to music at 90 BPM, as if listening.”
- “hack — new animation: the cat lifts its paw and hits the keys sharply.”
- “bigwin — the cat sways its head left and right to the music, raises a paw a little and waves it.”
The result is 18 bones and four animations. You can get the same files by rigging in the Spine editor by hand — the Phaser part below does not care where the skeleton came from.
Export Spine 4.2 JSON
The export is plain Spine 4.2 data:
skeleton.json bones, slots, skins and the four animations skeleton.atlas where each part sits on the texture page page.png the texture page itself images/ every part as its own PNG, to repack the atlas if you want
Phaser needs the first three. Two things to check in any export, not only Riggy's. First, the runtime version must match the export: these files say 4.2, so the plugin must be a 4.2 build. Second, the .atlas file must start with the page image name. The Phaser plugin takes the first line of the file as the page name, so an atlas that starts with an empty line (the old 3.x style) makes it load a folder instead of page.png and fail with Failed to process file: image.
Add Phaser and the Spine plugin
Esoteric Software publishes the plugin as @esotericsoftware/spine-phaser-v4 for Phaser 4 and spine-phaser-v3 for Phaser 3. Their latest tag already points to Spine 4.3, so pin a 4.2 version for 4.2 exports. From a CDN:
<script src="https://cdn.jsdelivr.net/npm/phaser@4.2.1/dist/phaser.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@esotericsoftware/spine-phaser-v4@4.2.120/dist/iife/spine-phaser-v4.min.js"></script>
or from npm:
npm install phaser@4.2.1 @esotericsoftware/spine-phaser-v4@4.2.120
Register the plugin as a scene plugin in the game config:
new Phaser.Game({
type: Phaser.WEBGL,
parent: "game",
width: 800,
height: 600,
...
plugins: {
scene: [{ key: "spine.SpinePlugin", plugin: spine.SpinePlugin, mapping: "spine" }],
},
});Load the skeleton and play it
The plugin adds two loader types — spineJson for the skeleton and spineAtlas for the atlas, which also loads its page images from the same folder:
preload() {
this.load.spineJson("cat-data", "assets/skeleton.json");
this.load.spineAtlas("cat-atlas", "assets/skeleton.atlas");
}In create, this.add.spine places the skeleton. The x, y point is where the root bone stands — for this rig, the bottom center — and the skeleton is scaled down to fit an 800×600 canvas:
const cat = this.add.spine(400, 580, "cat-data", "cat-atlas");
cat.setScale(0.45);
// blend 0.2 s between any two animations instead of snapping
cat.animationState.data.defaultMix = 0.2;
cat.animationState.setAnimation(0, "idle", true);defaultMix crossfades every switch between animations, so the cat never snaps from one pose to another.
One-shots that return to the loop
A one-shot such as hack should play once and hand control back to idle. Queue the loop right behind it on the same track:
// play the one-shot once, then go back to the idle loop
cat.animationState.setAnimation(0, name, false);
cat.animationState.addAnimation(0, "idle", true, 0);The last argument of addAnimation is a delay; 0 starts idle as soon as the one-shot ends, blended by the same default mix.
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. - Skin not found — the same for skins; the unnamed skin is
default. - Anything else from the runtime: Spine runtime errors, explained, or check the file with the Spine JSON validator.
Licensing
The Phaser plugin is part of the Spine Runtimes. Shipping a game with them requires a Spine license from Esoteric Software, whoever made the skeleton. What that means for exported rigs is on the licensing page. Riggy is an independent tool, not affiliated with Esoteric Software or Phaser.