Skip to main content

Overview

Spine integration is built on @esotericsoftware/spine-pixi-v8. Load skeleton data via the asset manifest with type: 'spine', then compose the animation with the components below. A typical hierarchy:
<SpineProvider key="character">
  <SpineEventEmitterProvider>      <!-- optional: enables beforeUpdateWorldTransforms events -->
    <SpineTrack trackIndex={0} animationName="idle" loop={true} />
    <SpineTrack trackIndex={1} animationName="blink" loop={false} />
    <SpineSlot slotName="weapon">
      <Sprite key="sword" />
    </SpineSlot>
  </SpineEventEmitterProvider>
</SpineProvider>

<SpineProvider>

The root component for a Spine skeleton. Looks up the SkeletonData from stateApp.loadedAssets by key, calculates scale from the declared width/height, and provides the Spine instance to all child components via context.

Props

key
string
required
Asset manifest key for a spine asset. The loaded SkeletonData is resolved automatically.
width
number
Desired display width in pixels. When provided, the skeleton is scaled to fit. If only width is given, the skeleton is scaled proportionally.
height
number
Desired display height in pixels. When provided, the skeleton is scaled to fit. If only height is given, the skeleton is scaled proportionally.
anchor
PixiPoint
Controls the pivot point of the skeleton. 0 = top-left, 0.5 = centre. Accepts a number or { x, y }. Default undefined.
scale
PixiPoint
Additional scale multiplier applied on top of the width/height-derived scale. Accepts a number or { x, y }. Default { x: 1, y: 1 }.
x
number
Horizontal position. Default 0.
y
number
Vertical position. Default 0.
alpha
number
Opacity from 0 to 1. Default 1.
visible
boolean
Whether the skeleton is rendered. Default true.
zIndex
number
Sort order within the parent. Default 0.
debug
boolean
When true, logs an error and dumps loadedAssets to the console if the key is not found. Useful during development.
cursor
Cursor
CSS cursor string.
children
Snippet
required
<SpineTrack>, <SpineSlot>, <SpineBone>, and <SpineEventEmitterProvider> components.
<SpineProvider> uses {#key spineData} internally — the entire subtree is remounted whenever the resolved skeleton data changes.

<BaseSpineProvider>

The lower-level Spine component used internally by <SpineProvider>. Use it directly when you already have a SPINE_PIXI.SkeletonData object and do not need the key-lookup and auto-scaling behaviour.

Props

spineData
SPINE_PIXI.SkeletonData
required
A fully loaded Spine skeleton data object. Passed directly to new SPINE_PIXI.Spine(spineData).
x
number
Horizontal position. Default 0.
y
number
Vertical position. Default 0.
scale
number | PointData
Scale applied to the spine object. Default 1.
pivot
number | PointData
Pivot point for rotation and positioning.
alpha
number
Opacity. Default 1.
visible
boolean
Whether the skeleton is rendered. Default true.
zIndex
number
Sort order within the parent. Default 0.
cursor
Cursor
CSS cursor string.
children
Snippet
required
Spine child components.

<SpineTrack>

Plays a named animation on a specific track of the parent <SpineProvider> skeleton. Must be a child of <SpineProvider> or <BaseSpineProvider>. When trackIndex or animationName changes, the previous animation is cleared with setEmptyAnimation before the new one starts.

Props

trackIndex
number
required
The track index to set the animation on. Track 0 is the base layer; higher indices layer on top.
animationName
string
required
The name of the animation to play, as defined in the Spine editor.
loop
boolean
Whether the animation loops. Default false.
timeScale
number
Playback speed multiplier for this track. 1 = normal, 2 = double speed. Inherited from SPINE_PIXI.TrackEntry.
alpha
number
Mix alpha (blend weight) for this track. 1 = full influence. Inherited from SPINE_PIXI.TrackEntry.

Example

<SpineProvider key="character" width={256} anchor={0.5} x={400} y={500}>
  <!-- Base animation on track 0 -->
  <SpineTrack trackIndex={0} animationName="idle" loop={true} />
  <!-- Layered animation on track 1 (e.g. a win reaction) -->
  <SpineTrack trackIndex={1} animationName="celebrate" loop={false} />
</SpineProvider>

<SpineBone>

Directly manipulates a named bone in the parent skeleton. All props from SPINE_PIXI.Bone are accepted and synced reactively.
The y axis is inverted — <SpineBone> negates the y value before writing it to the bone (bone.y = -props.y). This matches the Svelte/PixiJS coordinate system where y increases downward.

Props

boneName
string
required
The name of the bone to control, as defined in the Spine editor.
x
number
Local x position of the bone.
y
number
Local y position of the bone (negated before being written to Spine’s coordinate system).
rotation
number
Local rotation of the bone in degrees (Spine’s native unit).
scaleX
number
Local x scale of the bone.
scaleY
number
Local y scale of the bone.

Example

<script lang="ts">
  let headX = $state(0);
</script>

<SpineProvider key="character" width={256} x={400} y={500}>
  <SpineTrack trackIndex={0} animationName="idle" loop={true} />
  <SpineBone boneName="head" x={headX} />
</SpineProvider>

<SpineSlot>

Attaches a container to a named slot in the parent skeleton. Child components are positioned and transformed to follow that slot’s world transform each frame. When used inside a <SpineEventEmitterProvider>, the slot’s children are hidden automatically when the slot has no active attachment.

Props

slotName
string
required
The name of the slot to attach to, as defined in the Spine editor.
children
Snippet
required
Components to render inside the slot container. They are positioned relative to the slot’s world transform.

Example

<SpineProvider key="character" width={256} x={400} y={500}>
  <SpineTrack trackIndex={0} animationName="idle" loop={true} />
  <SpineSlot slotName="rightHand">
    <Sprite key="coin" anchor={0.5} />
  </SpineSlot>
</SpineProvider>

<SpineEventEmitterProvider>

Wraps a <SpineProvider> subtree and bridges Spine’s beforeUpdateWorldTransforms and afterUpdateWorldTransforms lifecycle hooks into a PixiJS EventEmitter. Required for <SpineSlot> visibility toggling based on slot attachment state. Must be placed inside a <SpineProvider>.

Props

children
Snippet
required
<SpineTrack>, <SpineSlot>, and <SpineBone> components.

Example

<SpineProvider key="character" width={256} anchor={0.5} x={400} y={500}>
  <SpineEventEmitterProvider>
    <SpineTrack trackIndex={0} animationName="idle" loop={true} />

    <!--
      With SpineEventEmitterProvider, this slot's children
      are hidden when the slot has no active attachment.
    -->
    <SpineSlot slotName="weapon">
      <Sprite key="sword" anchor={0.5} />
    </SpineSlot>
  </SpineEventEmitterProvider>
</SpineProvider>

Common pattern: GlobalMultiplier

A common use case is to scale a Spine skeleton based on a global multiplier (for example, to handle different screen sizes or win-celebration scaling effects).
<!-- GlobalMultiplier.svelte -->
<script lang="ts">
  import { SpineProvider, SpineTrack } from 'pixi-svelte';

  let { multiplier = 1 } = $props<{ multiplier?: number }>();
</script>

<SpineProvider
  key="character"
  width={256}
  scale={multiplier}
  anchor={0.5}
  x={400}
  y={500}
>
  <SpineTrack trackIndex={0} animationName="idle" loop={true} />
</SpineProvider>

Build docs developers (and LLMs) love