/****************************************************************************** * Spine Runtimes License Agreement * Last updated April 5, 2025. Replaces all prior versions. * * Copyright (c) 2013-2025, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and * conditions of Section 2 of the Spine Editor License Agreement: * http://esotericsoftware.com/spine-editor-license * * Otherwise, it is permitted to integrate the Spine Runtimes into software * or otherwise create derivative works of the Spine Runtimes (collectively, * "Products"), provided that each user of the Products must obtain their own * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ import { AnimationState, type Bone, Color, MeshAttachment, RegionAttachment, Skeleton, SkeletonBounds, SkeletonData, type Slot, type TrackEntry } from '@esotericsoftware/spine-core'; import { type Bounds, Container, type ContainerOptions, type DestroyOptions, type PointData, Texture, Ticker, ViewContainer } from 'pixi.js'; import type { ISpineDebugRenderer } from './SpineDebugRenderer.js'; /** * Options to create a {@link Spine} using {@link Spine.from}. */ export interface SpineFromOptions { /** the asset name for the skeleton `.skel` or `.json` file previously loaded into the Assets */ skeleton: string; /** the asset name for the atlas file previously loaded into the Assets */ atlas: string; /** The value passed to the skeleton reader. If omitted, 1 is passed. See {@link SkeletonBinary.scale} for details. */ scale?: number; /** Set the {@link Spine.autoUpdate} value. If omitted, it is set to `true`. */ autoUpdate?: boolean; /** * If `true`, use the dark tint renderer to render the skeleton * If `false`, use the default pixi renderer to render the skeleton * If `undefined`, use the dark tint renderer if at least one slot has tint black */ darkTint?: boolean; /** The bounds provider to use. If undefined the bounds will be dynamic, calculated when requested and based on the current frame. */ boundsProvider?: SpineBoundsProvider; /** Set {@link AtlasAttachmentLoader.allowMissingRegions} property on the AtlasAttachmentLoader. */ allowMissingRegions?: boolean; /** The ticker to use when {@link autoUpdate} is `true`. Defaults to {@link Ticker.shared}. */ ticker?: Ticker; } /** A bounds provider calculates the bounding box for a skeleton, which is then assigned as the size of the SpineGameObject. */ export interface SpineBoundsProvider { /** Returns the bounding box for the skeleton, in skeleton space. */ calculateBounds(gameObject: Spine): { x: number; y: number; width: number; height: number; }; } /** A bounds provider that provides a fixed size given by the user. */ export declare class AABBRectangleBoundsProvider implements SpineBoundsProvider { private x; private y; private width; private height; constructor(x: number, y: number, width: number, height: number); calculateBounds(): { x: number; y: number; width: number; height: number; }; } /** A bounds provider that calculates the bounding box from the setup pose. */ export declare class SetupPoseBoundsProvider implements SpineBoundsProvider { private clipping; /** * @param clipping If true, clipping attachments are used to compute the bounds. False, by default. */ constructor(clipping?: boolean); calculateBounds(gameObject: Spine): { x: number; y: number; width: number; height: number; }; } /** A bounds provider that calculates the bounding box by taking the maximumg bounding box for a combination of skins and specific animation. */ export declare class SkinsAndAnimationBoundsProvider implements SpineBoundsProvider { private animation; private skins; private timeStep; private clipping; /** * @param animation The animation to use for calculating the bounds. If null, the setup pose is used. * @param skins The skins to use for calculating the bounds. If empty, the default skin is used. * @param timeStep The time step to use for calculating the bounds. A smaller time step means more precision, but slower calculation. * @param clipping If true, clipping attachments are used to compute the bounds. False, by default. */ constructor(animation: string | null, skins?: string[], timeStep?: number, clipping?: boolean); calculateBounds(gameObject: Spine): { x: number; y: number; width: number; height: number; }; } export interface SpineOptions extends ContainerOptions { /** the {@link SkeletonData} used to instantiate the skeleton */ skeletonData: SkeletonData; /** See {@link SpineFromOptions.autoUpdate}. */ autoUpdate?: boolean; /** See {@link SpineFromOptions.darkTint}. */ darkTint?: boolean; /** See {@link SpineFromOptions.boundsProvider}. */ boundsProvider?: SpineBoundsProvider; /** See {@link SpineFromOptions.ticker}. */ ticker?: Ticker; } /** * AnimationStateListener {@link https://en.esotericsoftware.com/spine-api-reference#AnimationStateListener events} exposed for Pixi. */ export interface SpineEvents { complete: [trackEntry: TrackEntry]; dispose: [trackEntry: TrackEntry]; end: [trackEntry: TrackEntry]; event: [trackEntry: TrackEntry, event: Event]; interrupt: [trackEntry: TrackEntry]; start: [trackEntry: TrackEntry]; } export interface ClippedData { vertices: Float32Array; uvs: Float32Array; indices: Uint16Array; vertexCount: number; indicesCount: number; } export interface AttachmentCacheData { id: string; clipped: boolean; vertices: Float32Array; uvs: Float32Array; indices: number[]; color: Color; darkColor: Color; darkTint: boolean; skipRender: boolean; texture: Texture; clippedData?: ClippedData; } /** * The class to instantiate a {@link Spine} game object in Pixi. * Create and customize the default configuration using the static method {@link Spine.createOptions}, * then pass it to the constructor. */ export declare class Spine extends ViewContainer { batched: boolean; buildId: number; readonly renderPipeId = "spine"; _didSpineUpdate: boolean; beforeUpdateWorldTransforms: (object: Spine) => void; afterUpdateWorldTransforms: (object: Spine) => void; /** The skeleton for this Spine game object. */ skeleton: Skeleton; /** The animation state for this Spine game object. */ state: AnimationState; skeletonBounds?: SkeletonBounds; private darkTint; private _debug?; readonly _slotsObject: Record; private clippingSlotToPixiMasks; private getSlotFromRef; spineAttachmentsDirty: boolean; spineTexturesDirty: boolean; private _lastAttachments; private _stateChanged; private attachmentCacheData; get debug(): ISpineDebugRenderer | undefined; /** Pass a {@link SpineDebugRenderer} or create your own {@link ISpineDebugRenderer} to render bones, meshes, ... * @example spineGO.debug = new SpineDebugRenderer(); */ set debug(value: ISpineDebugRenderer | undefined); private _autoUpdate; private _ticker; get autoUpdate(): boolean; /** When `true`, the Spine AnimationState and the Skeleton will be automatically updated using the {@link ticker}. */ set autoUpdate(value: boolean); /** The ticker to use when {@link autoUpdate} is `true`. Defaults to {@link Ticker.shared}. */ get ticker(): Ticker; /** Sets the ticker to use when {@link autoUpdate} is `true`. If `autoUpdate` is already `true`, the update callback will be moved from the old ticker to the new one. */ set ticker(value: Ticker); private _boundsProvider?; /** The bounds provider to use. If undefined the bounds will be dynamic, calculated when requested and based on the current frame. */ get boundsProvider(): SpineBoundsProvider | undefined; set boundsProvider(value: SpineBoundsProvider | undefined); private hasNeverUpdated; private _physicsPositionInheritanceFactorX; private _physicsPositionInheritanceFactorY; private _physicsRotationInheritanceFactor; private hasLastPhysicsTransform; private lastPhysicsX; private lastPhysicsY; private lastPhysicsRotation; private readonly currentPhysicsPosition; private readonly lastPhysicsPosition; /** Scales how much horizontal translation of this Pixi container is inherited by skeleton physics constraints. */ get physicsPositionInheritanceFactorX(): number; /** Scales how much vertical translation of this Pixi container is inherited by skeleton physics constraints. */ get physicsPositionInheritanceFactorY(): number; /** * Sets how much translation of this Pixi container is inherited by skeleton physics constraints. * The default is (1, 1), which applies container translation normally. Use (0, 0) * to prevent container translation from affecting physics constraints. */ setPhysicsPositionInheritanceFactor(x: number, y: number): void; /** * Scales how much rotation of this Pixi container is inherited by skeleton physics constraints. * The default is `1`, which applies container rotation normally. Use `0` to prevent container * rotation from affecting physics constraints. */ get physicsRotationInheritanceFactor(): number; set physicsRotationInheritanceFactor(value: number); constructor(options: SkeletonData | SpineOptions | SpineFromOptions); /** If {@link Spine.autoUpdate} is `false`, this method allows to update the AnimationState and the Skeleton with the given delta. */ update(dt: number): void; protected internalUpdate(ticker?: Ticker, deltaSeconds?: number): void; /** Resets the position used for calculating inherited physics translation. */ resetPhysicsPosition(): void; /** Resets the rotation used for calculating inherited physics rotation. */ resetPhysicsRotation(): void; /** Resets the transform used for calculating inherited physics translation and rotation. */ resetPhysicsTransform(): void; private applyTransformMovementToPhysics; private applyPositionMovementToPhysics; private applyRotationMovementToPhysics; private setLastPhysicsTransform; private getPhysicsRotation; private getRotationDelta; get bounds(): Bounds; /** * Set the position of the bone given in input through a {@link IPointData}. * @param bone: the bone name or the bone instance to set the position * @param outPos: the new position of the bone. * @throws {Error}: if the given bone is not found in the skeleton, an error is thrown */ setBonePosition(bone: string | Bone, position: PointData): void; /** * Return the position of the bone given in input into an {@link IPointData}. * @param bone: the bone name or the bone instance to get the position from * @param outPos: an optional {@link IPointData} to use to return the bone position, rathern than instantiating a new object. * @returns {IPointData | undefined}: the position of the bone, or undefined if no matching bone is found in the skeleton */ getBonePosition(bone: string | Bone, outPos?: PointData): PointData | undefined; /** * Advance the state and skeleton by the given time, then update slot objects too. * The container transform is not updated. * * @param time the time at which to set the state */ private _updateAndApplyState; /** * - validates the attachments - to flag if the attachments have changed this state * - transforms the attachments - to update the vertices of the attachments based on the new positions * @internal */ _validateAndTransformAttachments(): void; private validateAttachments; private currentClippingSlot; private updateAndSetPixiMask; private transformAttachments; private updateClippingData; /** * ensure that attached containers map correctly to their slots * along with their position, rotation, scale, and visibility. */ private updateSlotObjects; private updateSlotObject; /** @internal */ _getCachedData(slot: Slot, attachment: RegionAttachment | MeshAttachment): AttachmentCacheData; private initCachedData; protected onViewUpdate(): void; /** * Attaches a PixiJS container to a specified slot. This will map the world transform of the slots bone * to the attached container. A container can only be attached to one slot at a time. * * @param container - The container to attach to the slot * @param slotRef - The slot id or slot to attach to * @param options - Optional settings for the attachment. * @param options.followAttachmentTimeline - If true, the attachment will follow the slot's attachment timeline. * @param options.followSlotColor - If true, the container tint will follow the skeleton and slot colors. */ addSlotObject(slot: number | string | Slot, container: Container, options?: { followAttachmentTimeline?: boolean; followSlotColor?: boolean; }): void; /** * Removes a PixiJS container from the slot it is attached to. * * @param container - The container to detach from the slot * @param slotOrContainer - The container, slot id or slot to detach from */ removeSlotObject(slotOrContainer: number | string | Slot | Container): void; /** * Removes all PixiJS containers attached to any slot. */ removeSlotObjects(): void; /** * Returns a container attached to a slot, or undefined if no container is attached. * * @param slotRef - The slot id or slot to get the attachment from * @returns - The container attached to the slot */ getSlotObject(slot: number | string | Slot): Container | undefined; protected updateBounds(): void; /** @internal */ addBounds(bounds: Bounds): void; /** * Destroys this sprite renderable and optionally its texture. * @param options - Options parameter. A boolean will act as if all options * have been set to that value * @param {boolean} [options.texture=false] - Should it destroy the current texture of the renderable as well * @param {boolean} [options.textureSource=false] - Should it destroy the textureSource of the renderable as well */ destroy(options?: DestroyOptions): void; /** Converts a point from the skeleton coordinate system to the Pixi world coordinate system. */ skeletonToPixiWorldCoordinates(point: { x: number; y: number; }): void; /** Converts a point from the Pixi world coordinate system to the skeleton coordinate system. */ pixiWorldCoordinatesToSkeleton(point: { x: number; y: number; }): void; /** Converts a point from the Pixi world coordinate system to the bone's local coordinate system. */ pixiWorldCoordinatesToBone(point: { x: number; y: number; }, bone: Bone): void; /** * Get a convenient initialization configuration for your Spine game object. * Before instantiating a Spine game object, the skeleton (`.skel` or `.json`) and the atlas text files must be loaded into the {@link Assets}. For example: * ``` * PIXI.Assets.add("sackData", "/assets/sack-pro.skel"); * PIXI.Assets.add("sackAtlas", "/assets/sack-pma.atlas"); * await PIXI.Assets.load(["sackData", "sackAtlas"]); * ``` * Once a Spine game object is created, its skeleton data is cached into {@link Cache} using the key: * `${skeletonAssetName}-${atlasAssetName}-${options?.scale ?? 1}` * * @param options - Options to configure the Spine game object. See {@link SpineFromOptions} * @returns {SpineOptions} The configuration ready to be passed to the Spine constructor */ static createOptions({ skeleton, atlas, scale, darkTint, autoUpdate, boundsProvider, allowMissingRegions, ticker }: SpineFromOptions): SpineOptions; /** * @deprecated Use directly the Spine constructor or {@link createOptions} to make options and customize it to pass to the constructor * Use this method to instantiate a Spine game object. * Before instantiating a Spine game object, the skeleton (`.skel` or `.json`) and the atlas text files must be loaded into the Assets. For example: * ``` * PIXI.Assets.add("sackData", "/assets/sack-pro.skel"); * PIXI.Assets.add("sackAtlas", "/assets/sack-pma.atlas"); * await PIXI.Assets.load(["sackData", "sackAtlas"]); * ``` * Once a Spine game object is created, its skeleton data is cached into {@link Cache} using the key: * `${skeletonAssetName}-${atlasAssetName}-${options?.scale ?? 1}` * * @param options - Options to configure the Spine game object. See {@link SpineFromOptions} * @returns {Spine} The Spine game object instantiated */ static from(options: SpineFromOptions): Spine; }