Files

11 KiB

name, description
name description
spine-godot spine-godot runtime for Godot 4 — Spine skeleton display, animation playback, bone/slot manipulation, skin mixing, 2D lighting, and runtime asset loading. Use when working with Spine skeletons, animations, SpineSprite nodes, SpineBoneNode, SpineSlotNode, or SpineAnimationTrack in this project.

spine-godot Skill

The spine-godot runtime provides Godot nodes and APIs to load, display, animate, and manipulate skeletons exported from Spine. It wraps the spine-cpp runtime and exposes it to GDScript and C#.

Official docs: https://en.esotericsoftware.com/spine-godot Spine Runtimes Guide: https://en.esotericsoftware.com/spine-runtimes-guide Source: https://github.com/EsotericSoftware/spine-runtimes (under spine-godot/)

Architecture Overview

spine-godot Runtime
├── SpineSprite              — displays a skeleton from SkeletonDataResource
│   ├── SpineSkeleton        — skeleton instance (bones, slots, attachments, skins, constraints)
│   ├── SpineAnimationState  — animation playback, queuing, mixing via tracks
│   └── Signals              — animation_started, animation_completed, animation_event, etc.
├── SpineBoneNode            — follows or drives a bone's transform
├── SpineSlotNode            — inserts nodes into drawing order or overrides slot materials
└── SpineAnimationTrack      — animates a SpineSprite via Godot AnimationPlayer (C++ engine module only)

Resource Types

Resource Purpose
SpineSkeletonFileResource Imported .skel or .spine-json skeleton data
SpineAtlasResource Imported .atlas texture atlas data (uses normal map prefix n_ by default)
SpineSkeletonDataResource Combines a SpineSkeletonFileResource + SpineAtlasResource + animation mix times. Shared across SpineSprite instances.

Asset Management

Exporting from Spine Editor

Export these files from the Spine Editor:

  1. Skeleton data: skeleton-name.spine-json or skeleton-name.skel (binary, smaller/faster — preferred).
  2. Texture atlas: skeleton-name.atlas
  3. Atlas pages: One or more .png image files.

Prefer .skel binary exports. If using JSON, use .spine-json extension (not .json). Pre-multiplied alpha atlases are not supported — Godot's default bleed handles artifacts.

Importing into Godot

  1. Drag .skel/.spine-json, .atlas, and .png files into a Godot project folder.
  2. The importer creates a SpineSkeletonFileResource, a SpineAtlasResource, and Godot texture resources.
  3. Create a SpineSkeletonDataResource: Right-click folder → New Resource...SpineSkeletonDataResource.
  4. Assign the atlas resource and skeleton file resource in the inspector. Set animation mix times here.

A SpineSkeletonDataResource should be shared by all SpineSprite instances displaying the same skeleton. Do not use inline resources.

Updating Assets During Development

Overwrite the source files re-exported from Spine. Godot auto-detects changes and re-imports. If it doesn't, force re-import in the import settings panel.

Runtime Loading from Disk (modding)

Load skeleton and atlas files from arbitrary paths at runtime:

# Load skeleton file
var skeleton_file_res = SpineSkeletonFileResource.new()
skeleton_file_res.load_from_file("/path/to/skeleton.skel")

# Load atlas file
var atlas_res = SpineAtlasResource.new()
atlas_res.load_from_atlas_file("/path/to/skeleton.atlas")

# Create shared skeleton data resource
var skeleton_data_res = SpineSkeletonDataResource.new()
skeleton_data_res.skeleton_file_res = skeleton_file_res
skeleton_data_res.atlas_res = atlas_res

# Create sprite from data
var sprite = SpineSprite.new()
sprite.skeleton_data_res = skeleton_data_res
sprite.position = Vector2(200, 200)
sprite.get_animation_state().set_animation("animation", true, 0)
add_child(sprite)

Nodes

SpineSprite Node

Displays skeleton data from a SkeletonDataResource. Provides access to the animation state and skeleton instance.

Creating a SpineSprite

  1. Add a SpineSprite node via the + button in the scene panel.
  2. Assign a SkeletonDataResource in the inspector.
  3. Transform the node freely in the editor viewport.

Editor Features

  • Debug view: Check bones, slots, attachments in the Debug property section. Hover over parts in the viewport to see names.
  • Animation preview: Use the Preview section to set an animation and scrub through time with the slider.
  • Custom materials: Set per-blend-mode materials in the Materials section (applied to all slots). Use SpineSlotNode to override per-slot.
  • Update Mode: Process (default, every frame), Physics (fixed interval, 60fps), Manual (call update_skeleton() yourself in _process/_physics_process).

Animating a SpineSprite

extends SpineSprite

func _ready():
    var animation_state = get_animation_state()

    # Set an animation on track 0, looping
    animation_state.set_animation("walk", true, 0)

    # Queue an animation after a delay (mix duration implied by mix times)
    animation_state.add_animation("idle", 0.5, true, 0)

    # Set a reversed animation
    var track_entry = animation_state.set_animation("walk", true, 0)
    track_entry.set_reverse(true)

    # Mix to an empty animation (reset to setup pose)
    animation_state.set_empty_animation(0, 0.5)
    animation_state.add_empty_animation(0, 0.5, 0.5)

    # Clear tracks
    animation_state.clear_track(0)          # clear one track
    animation_state.clear_tracks()          # clear all tracks

    # Reset skeleton poses
    get_skeleton().set_to_setup_pose()     # bones + slots
    get_skeleton().set_slots_to_setup_pose()  # slots only

Animation State API

Method Purpose
set_animation(name, loop, track) Play animation. Returns SpineTrackEntry.
add_animation(name, delay, loop, track) Queue animation after delay. Returns SpineTrackEntry.
set_empty_animation(track, mix_duration) Mix out to empty pose immediately.
add_empty_animation(track, mix_duration, delay) Queue empty animation mix-out.
clear_track(track) Immediately clear one track.
clear_tracks() Immediately clear all tracks.

Important: Do not hold SpineTrackEntry references across frames. They are reused internally and become invalid once the animation completes.

SpineTrackEntry Properties

Method Purpose
set_reverse(true) Play animation in reverse.
set_mix_duration(seconds) Override mix duration.
set_alpha(value) Mix alpha for blending (0-1).
set_time_scale(scale) Animation speed multiplier.
set_track_time(time) Jump to specific time in seconds.

SpineSprite Signals

Animation state signals:

  • animation_started(track_entry) — animation started playing.
  • animation_interrupted(track_entry) — track cleared or new animation set.
  • animation_completed(track_entry) — animation finished one full loop.
  • animation_ended(track_entry) — animation will never be applied again.
  • animation_disposed(track_entry) — track entry disposed.
  • animation_event(track_entry, event) — user-defined Spine event triggered.

Lifecycle signals:

  • before_animation_state_update — before animation state is updated with delta.
  • before_animation_state_apply — before animation state is applied to skeleton pose.
  • before_world_transforms_change — before bone world transforms update. Use to set bone transforms manually.
  • world_transforms_changed — after bone world transforms update.

Mix-and-Match Skins

Combine multiple skins to create custom avatars:

var custom_skin = new_skin("custom-skin")
var data = get_skeleton().get_data()

custom_skin.add_skin(data.find_skin("skin-base"))
custom_skin.add_skin(data.find_skin("nose/short"))
custom_skin.add_skin(data.find_skin("eyes/violet"))
custom_skin.add_skin(data.find_skin("hair/brown"))
custom_skin.add_skin(data.find_skin("clothes/hoodie-orange"))

get_skeleton().set_skin(custom_skin)
get_skeleton().set_slots_to_setup_pose()

Getting and Setting Bone Transforms

# Get a bone's global transform in Godot canvas space
var transform = get_global_bone_transform("bone_name")

# Set a bone's transform (must be called before world transforms update)
set_global_bone_transform("bone_name", Transform2D(0, Vector2(100, 200)))

When manually setting bone transforms, connect to before_world_transforms_change signal. Alternatively, use SpineBoneNode for simpler bone manipulation.

SpineBoneNode

A child node of SpineSprite that either follows or drives a bone.

Must be a direct child of a SpineSprite.

Inspector properties:

  • Bone Name — dropdown of all available bones.
  • Bone ModeFollow (node moves with bone) or Drive (node controls bone position).
  • Enabled — toggle following/driving on/off.

Use cases:

  • Drive mode: Control a bone via mouse position or other input (e.g., aiming).
  • Follow mode: Attach other nodes (CollisionShape, Marker2D) to follow a bone.

See examples: example/05-mouse-following (drive), example/06-bone-following (follow).

SpineSlotNode

A child node of SpineSprite that inserts children into the skeleton's drawing order or overrides a slot's materials.

Must be a direct child of a SpineSprite.

Inspector properties:

  • Slot Name — dropdown of all available slots.
  • Materials — custom materials that override the slot's default materials.

Use cases:

  • Attach particle systems, custom sprites, or other SpineSprite nodes on top of a slot.
  • Override materials per-slot (overrides SpineSprite's global materials).

See examples: example/07-slot-node (drawing order), example/09-custom-material (material override).

SpineAnimationTrack (C++ Engine Module Only)

Animates a SpineSprite via Godot's AnimationPlayer and animation editor. Ideal for cutscenes.

Experimental. Not available in the GDExtension.

Must be a direct child of a SpineSprite.

  • Creates a child AnimationPlayer automatically.
  • Key animations on the child AnimationPlayer; key animation properties (loop, reverse, etc.) on the SpineAnimationTrack.
  • Multiple SpineAnimationTrack nodes on one SpineSprite enable multi-track layering.
  • Each track gets a unique track index — higher tracks override lower tracks' skeleton properties.

Mix times from SpineSkeletonDataResource cannot be previewed in the editor.

See example: example/08-animation-player.

2D Lighting

spine-godot integrates with Godot's 2D lighting system.

Setup

  1. Provide normal map .png images alongside atlas page images with prefix n_ (default): e.g., raptor.pngn_raptor.png.
  2. The normal map prefix is configurable in the atlas import settings.
  3. After importing, apply Godot 2D lights to SpineSprite nodes.

See example: example/10-2d-lighting.

Spine Runtimes API Access

Almost all spine-cpp API is mapped 1:1 to GDScript. Objects from SpineSprite (via get_skeleton(), get_animation_state()) mirror the C++ API.

GDScript Limitations

  • Returned arrays/maps are copies — mutations don't affect internals.
  • Cannot set per-track-entry listeners — use SpineSprite signals instead.
  • Cannot create/add/remove bones, slots, or other Spine objects directly.
  • C++ class hierarchies of attachments and timelines are not exposed.