Use Spine with Phaser 3 and TypeScript in VS Code

Set up a TypeScript Phaser 3 project with SpinePlugin and VS Code IntelliSense

by on 7 minute read


Phaser is a great JavaScript game framework that makes it easy to use amazing Spine animations in your game. And TypeScript makes writing that code more enjoyable.

You get static type checking to avoid bugs, IntelliSense in VS Code or other editors, advanced language features like generics, and much more.

It would almost be silly to create a non-demo or non-prototype Phaser game in plain JavaScript! 🤨

Phaser comes with TypeScript definitions for the Spine runtime but not the SpinePlugin so you won't get code completion or IntelliSense for code described in the docs like:

this.load.spine('stretchyman', 'stretchyman-pro.json', [ 'stretchyman-pma.atlas' ], true)

Or

this.add.spine(512, 650, 'stretchyman')

TypeScript will complain about the .spine() method in the above examples because we have no definition files.

All these problems can be solved and we will do it in this article!

You can find the working example project here.

If you want to know how everything works then keep reading! 🤓

Create a Phaser 3 TypeScript Project

We are using the phaser3-parcel-template to bootstrap our project. Clone it to your local machine like this:

git clone https://github.com/ourcade/phaser3-parcel-template.git my-project-name

Then:

  1. rename the main.js file to main.ts
  2. in index.html change main.js to main.ts
  3. delete src/scenes/HelloWorldScene.js

We now have a barebones Phaser 3 TypeScript project. 🎉

There will be code errors because we deleted HelloWorldScene.js but that will be fixed next.

Check out our Easily Use Typescript with Phaser 3 guide for in-depth instructions.

Create a SpineDemo Scene

We are currently Scene-less and every Phaser game needs at least one Scene so let's make an empty, barebones Scene called SpineDemo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import Phaser from 'phaser'

export default class SpineDemo extends Phaser.Scene
{
	constructor()
	{
		super('spine-demo')
	}

	preload()
	{
	}

	create()
	{
	}

	update()
	{
	}
}

This is where we will add code to load and play Spine animations. For now, we will just tell Phaser to load this Scene instead of HelloWorldScene.

Update main.ts like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import Phaser from 'phaser'

import SpineDemo from './scenes/SpineDemo'

const config: Phaser.Types.Core.GameConfig = {
	type: Phaser.AUTO,
	width: 800,
	height: 600,
	physics: {
		default: 'arcade',
		arcade: {
			gravity: { y: 200 }
		}
	},
	scene: [SpineDemo]
}

export default new Phaser.Game(config)

On line 3 we import SpineDemo instead of the deleted HelloWorldScene. Then we replace HelloWorldScene with SpineDemo in the scene property on line 15.

Give this a try by running:

npm run start

Open http://localhost:8000 and you should see a black screen. You can also launch the browser console (in Chrome: View > Developer > JavaScript Console or right-click and select Inspect) to check that there are no errors.

Import SpinePlugin

The SpinePlugin comes packaged with Phaser when you install from npm. It is located in phaser/plugins/spine under node_modules.

We will import it in main.ts and register it as a plugin in the GameConfig.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import Phaser from 'phaser'
import 'phaser/plugins/spine/dist/SpinePlugin'

import SpineDemo from './scenes/SpineDemo'

const config: Phaser.Types.Core.GameConfig = {
	type: Phaser.AUTO,
	width: 800,
	height: 600,
	physics: {
		default: 'arcade',
		arcade: {
			gravity: { y: 200 }
		}
	},
	scene: [SpineDemo],
	plugins: {
		scene: [
			{ key: 'SpinePlugin', plugin: window.SpinePlugin, mapping: 'spine' }
		]
	}
}

export default new Phaser.Game(config)

VS Code should complain that SpinePlugin does not exist on window and give you an error on line 19.

We can fix that by creating a globals.d.ts file in src/types with the following definition:

1
2
3
4
declare interface Window
{
	SpinePlugin: any
}

We are using TypeScript's Declaration Merging feature to let the language service know that Window has a SpinePlugin property.

The SpinePlugin property is added to window when we import 'phaser/plugins/spine/dist/SpinePlugin' on line 2.

The SpinePlugin is now ready for use and VS Code should be happy! 😄

SpinePlugin Definitions

We can use the SpinePlugin right now but VS Code and the TypeScript Language Server will complain when you try to use this.load.spine and related plugin methods.

We can fix this with definition files.

If you are using Phaser v3.22 or higher then you will already have the definition files in the Phaser package. You just need to reference them and update your tsconfig.json.

Create a @types folder at the root of your project. Then add a phaser folder to @types. Lastly, create a index.d.ts at @types/phaser.

1
2
3
// @types/phaser/index.d.ts
/// <reference path="../../node_modules/phaser/types/SpineGameObject.d.ts" />
/// <reference path="../../node_modules/phaser/types/SpinePlugin.d.ts" />

Now add @types as the first entry for typeRoots in tsconfig.json.

1
2
3
4
5
6
7
8
{
	// ...
	"typeRoots": {
		"@types",
		"node_modules/@types",
		"node_module/phaser/types"
	}
}

If you are using older versions of Phaser you'll have to copy the defintion files into your project.

You can find them here.

You'll need SpineFile.d.ts, SpineGameObject.d.ts, and SpinePlugin.d.ts. Copy those files into your project under src/types.

These files were handcrafted against Phaser v3.21.0 and is included in newer versions of Phaser.

Using Spine Animations

Now that all the setup is done we can start using Spine animations.

There are Spine Boy assets that you can use here. You can use other animations if you have them.

Copy them into public/assets/spine. All your non-code assets like images, sound effects, Spine animations, etc should go in the public folder at the root of your project–the same level as src. The exact layout within that folder is up to you.

Now let's preload the assets in SpineDemo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import Phaser from 'phaser'

const SPINEBOY_KEY = 'spineboy'

export default class SpineDemo extends Phaser.Scene
{
	constructor()
	{
		super('spine-demo')
	}

	preload()
	{
		this.load.setPath('assets/spine/')
		this.load.spine(SPINEBOY_KEY, 'spineboy.json', 'spineboy.atlas')
	}

	// ...
}

We have a constant SPINEBOY_KEY because we are using that string literal in two places. First on line 15 and later–shown below–when we create the animations.

Notice that we set the path to assets/spine/ on line 14 before we call this.load.spine. That tells Phaser where to look for spineboy.json and spineboy.atlas. This path will only work if you placed the assets in the public folder.

Next, let's create the animation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import Phaser from 'phaser'

const SPINEBOY_KEY = 'spineboy'

export default class SpineDemo extends Phaser.Scene
{
	constructor()
	{
		super('spine-demo')
	}

	preload()
	{
		this.load.setPath('assets/spine/')
		this.load.spine(SPINEBOY_KEY, 'spineboy.json', 'spineboy.atlas')
	}

	create()
	{
		this.add.spine(400, 600, SPINEBOY_KEY, 'idle', true)
	}

	// ...
}

We add the Spine Boy animation with a looping 'idle' animation on line 20.

Your browser should automatically refresh at http://localhost:8000 and show an idling Spine Boy! 🎉

Next Steps

Using the SpinePlugin should be fairly straight forward now that you have a working project with proper definition files and VS Code IntelliSense.

Be sure to check out the official Phaser documentation to see what you can do with Spine animations.

This example project demonstrates how to change animations.

Let us know in the comments below if anything doesn’t work or is unclear. We’ll be happy to fix or clarify!

Be sure to sign up for our newsletter so you don't miss any future Phaser 3 game development tips and techniques!

Drop your email into the box below.

Learn to make an Infinite Runner in Phaser 3 with TypeScript!

Drop your email into the box below to get this free 90+ page book and join our newsletter.

Learn more about the book here.

Phaser 3 TypeScript Spine SpinePlugin

Want tips and techniques more suited for you?


You may also like...


Video Guides


Beginner Guides


Articles Recommended For You

Command Pattern to Undo Player Actions

by on

Are you looking for a clean and reusable way to implement undo for player actions? Perhaps you are making a turn-based …

15 minute read

Advanced Logging with the Strategy Pattern

by on

Have you ever tried debugging a problem with your game that only seems to happen in production? The Developer Tools …

7 minute read

State Pattern for Character Movement in Phaser 3

by on

Writing clean and well-organized code is something all game developers aspire to. We want code to be reusable and easy …

7 minute read

Memory Match in Modern Javascript with Phaser 3 - Part 6

by on

If you've got the basics of Phaser 3 in modern JavaScript down then it might be time to try making something a bit more …

8 minute read

Didn't find what you were looking for?


comments powered by Disqus