Skip to content

Spine Animation

The SpineAnimation component plays Spine skeletal animations. Add it to an entity in the scene editor along with LocalTransform.

Properties

PropertyTypeDefaultDescription
skeletonPathstring''Path to skeleton JSON file
atlasPathstring''Path to atlas file
skinstring''Active skin name
animationstring''Current animation name
timeScalenumber1.0Playback speed multiplier
loopbooleantrueWhether to loop the animation
playingbooleantrueWhether currently playing
flipXbooleanfalseFlip horizontally
flipYbooleanfalseFlip vertically
colorColor{r:1, g:1, b:1, a:1}Tint color RGBA
layernumber0Render order
skeletonScalenumber1.0Skeleton scale factor
materialnumber0Material ID

Setup

  1. Place Spine export files (.json + .atlas + images) in your project’s assets/ folder
  2. In the scene editor: create an entity → add LocalTransform and SpineAnimation
  3. Set skeletonPath and atlasPath to point to your Spine files
  4. Set animation to the name of the animation to play

Controlling Animations

Query the SpineAnimation component in a system to change animations at runtime:

import { defineSystem, addSystem, Res, Input, Query, Mut, SpineAnimation } from 'esengine';
import { Player } from './components';
addSystem(defineSystem(
[Res(Input), Query(Mut(SpineAnimation), Player)],
(input, query) => {
for (const [entity, spine] of query) {
if (input.isKeyPressed('Space')) {
spine.animation = 'jump';
spine.loop = false;
} else if (input.isKeyDown('KeyD') || input.isKeyDown('KeyA')) {
spine.animation = 'run';
spine.loop = true;
} else {
spine.animation = 'idle';
spine.loop = true;
}
}
}
));

Skins

Switch skins to change the character’s appearance:

spine.skin = 'warrior';

Playback Control

spine.playing = false; // Pause
spine.playing = true; // Resume
spine.timeScale = 2.0; // Double speed
spine.timeScale = 0.5; // Half speed

Flipping

spine.flipX = true; // Face left
spine.flipX = false; // Face right (default)

Color Tinting

spine.color = { r: 1, g: 0, b: 0, a: 1 }; // Red tint
spine.color = { r: 1, g: 1, b: 1, a: 0.5 }; // 50% transparent

Example: Character Controller

Define a CharacterState component, attach it with SpineAnimation on the entity in the editor:

import {
defineComponent, defineSystem, addSystem,
Res, Input, Time, Query, Mut, LocalTransform, SpineAnimation
} from 'esengine';
const CharacterState = defineComponent('CharacterState', {
speed: 200,
currentAnim: 'idle'
});
addSystem(defineSystem(
[Res(Input), Res(Time), Query(Mut(LocalTransform), Mut(SpineAnimation), CharacterState)],
(input, time, query) => {
for (const [entity, transform, spine, state] of query) {
let moving = false;
if (input.isKeyDown('KeyD')) {
transform.position.x += state.speed * time.delta;
spine.flipX = false;
moving = true;
}
if (input.isKeyDown('KeyA')) {
transform.position.x -= state.speed * time.delta;
spine.flipX = true;
moving = true;
}
const newAnim = moving ? 'run' : 'idle';
if (state.currentAnim !== newAnim) {
state.currentAnim = newAnim;
spine.animation = newAnim;
spine.loop = true;
}
}
}
));