@esotericsoftware/spine-core
Version:
The official Spine Runtimes for the web.
4 lines • 963 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/Utils.ts", "../../src/Texture.ts", "../../src/TextureAtlas.ts", "../../src/attachments/Attachment.ts", "../../src/attachments/MeshAttachment.ts", "../../src/attachments/RegionAttachment.ts", "../../src/attachments/Sequence.ts", "../../src/Animation.ts", "../../src/AnimationState.ts", "../../src/AnimationStateData.ts", "../../src/AssetManagerBase.ts", "../../src/attachments/BoundingBoxAttachment.ts", "../../src/attachments/ClippingAttachment.ts", "../../src/attachments/PathAttachment.ts", "../../src/attachments/PointAttachment.ts", "../../src/AtlasAttachmentLoader.ts", "../../src/PosedData.ts", "../../src/BoneData.ts", "../../src/BonePose.ts", "../../src/Posed.ts", "../../src/PosedActive.ts", "../../src/Bone.ts", "../../src/Constraint.ts", "../../src/DrawOrder.ts", "../../src/ConstraintData.ts", "../../src/Event.ts", "../../src/EventData.ts", "../../src/IkConstraintPose.ts", "../../src/IkConstraint.ts", "../../src/IkConstraintData.ts", "../../src/PathConstraintPose.ts", "../../src/PathConstraintData.ts", "../../src/PathConstraint.ts", "../../src/Physics.ts", "../../src/PhysicsConstraintPose.ts", "../../src/SlotPose.ts", "../../src/Slot.ts", "../../src/Skeleton.ts", "../../src/PhysicsConstraint.ts", "../../src/PhysicsConstraintData.ts", "../../src/polyfills.ts", "../../src/SliderPose.ts", "../../src/Slider.ts", "../../src/SliderData.ts", "../../src/SkeletonData.ts", "../../src/Skin.ts", "../../src/SlotData.ts", "../../src/TransformConstraintPose.ts", "../../src/TransformConstraint.ts", "../../src/TransformConstraintData.ts", "../../src/SkeletonBinary.ts", "../../src/SkeletonBounds.ts", "../../src/Triangulator.ts", "../../src/SkeletonClipping.ts", "../../src/SkeletonJson.ts", "../../src/SkeletonRendererCore.ts"],
"sourcesContent": ["/******************************************************************************\n * Spine Runtimes License Agreement\n * Last updated April 5, 2025. Replaces all prior versions.\n *\n * Copyright (c) 2013-2025, Esoteric Software LLC\n *\n * Integration of the Spine Runtimes into software or otherwise creating\n * derivative works of the Spine Runtimes is permitted under the terms and\n * conditions of Section 2 of the Spine Editor License Agreement:\n * http://esotericsoftware.com/spine-editor-license\n *\n * Otherwise, it is permitted to integrate the Spine Runtimes into software\n * or otherwise create derivative works of the Spine Runtimes (collectively,\n * \"Products\"), provided that each user of the Products must obtain their own\n * Spine Editor license and redistribution of the Products in any form must\n * include this license and copyright notice.\n *\n * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,\n * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *****************************************************************************/\n\n/** biome-ignore-all lint/complexity/noStaticOnlyClass: too much things to update */\n\nimport type { Skeleton } from \"./Skeleton.js\";\n\nexport interface StringMap<T> {\n\t[key: string]: T;\n}\n\nexport class IntSet {\n\tarray = [] as (number | undefined)[];\n\n\tadd (value: number): boolean {\n\t\tconst contains = this.contains(value);\n\t\tthis.array[value | 0] = value | 0;\n\t\treturn !contains;\n\t}\n\n\tcontains (value: number) {\n\t\treturn this.array[value | 0] !== undefined;\n\t}\n\n\tremove (value: number) {\n\t\tthis.array[value | 0] = undefined;\n\t}\n\n\tclear () {\n\t\tthis.array.length = 0;\n\t}\n}\n\nexport class StringSet {\n\tentries: StringMap<boolean> = {};\n\tsize = 0;\n\n\tadd (value: string): boolean {\n\t\tconst contains = this.entries[value];\n\t\tthis.entries[value] = true;\n\t\tif (!contains) {\n\t\t\tthis.size++;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\taddAll (values: string[]): boolean {\n\t\tconst oldSize = this.size;\n\t\tfor (let i = 0, n = values.length; i < n; i++)\n\t\t\tthis.add(values[i]);\n\t\treturn oldSize !== this.size;\n\t}\n\n\tcontains (value: string) {\n\t\treturn this.entries[value];\n\t}\n\n\tclear () {\n\t\tthis.entries = {};\n\t\tthis.size = 0;\n\t}\n}\n\nexport type NumberArrayLike = Array<number> | Float32Array;\nexport type IntArrayLike = Array<number> | Int16Array;\n\nexport interface Disposable {\n\tdispose (): void;\n}\n\nexport interface Restorable {\n\trestore (): void;\n}\n\nexport class Color {\n\tpublic static WHITE = new Color(1, 1, 1, 1);\n\tpublic static RED = new Color(1, 0, 0, 1);\n\tpublic static GREEN = new Color(0, 1, 0, 1);\n\tpublic static BLUE = new Color(0, 0, 1, 1);\n\tpublic static MAGENTA = new Color(1, 0, 1, 1);\n\n\tconstructor (public r: number = 0, public g: number = 0, public b: number = 0, public a: number = 0) {\n\t}\n\n\tset (r: number, g: number, b: number, a: number) {\n\t\tthis.r = r;\n\t\tthis.g = g;\n\t\tthis.b = b;\n\t\tthis.a = a;\n\t\treturn this.clamp();\n\t}\n\n\tsetFromColor (c: Color) {\n\t\tthis.r = c.r;\n\t\tthis.g = c.g;\n\t\tthis.b = c.b;\n\t\tthis.a = c.a;\n\t\treturn this;\n\t}\n\n\tsetFromString (hex: string) {\n\t\thex = hex.charAt(0) === '#' ? hex.substr(1) : hex;\n\t\tthis.r = parseInt(hex.substr(0, 2), 16) / 255;\n\t\tthis.g = parseInt(hex.substr(2, 2), 16) / 255;\n\t\tthis.b = parseInt(hex.substr(4, 2), 16) / 255;\n\t\tthis.a = hex.length !== 8 ? 1 : parseInt(hex.substr(6, 2), 16) / 255;\n\t\treturn this;\n\t}\n\n\tadd (r: number, g: number, b: number, a: number) {\n\t\tthis.r += r;\n\t\tthis.g += g;\n\t\tthis.b += b;\n\t\tthis.a += a;\n\t\treturn this.clamp();\n\t}\n\n\tclamp () {\n\t\tif (this.r < 0) this.r = 0;\n\t\telse if (this.r > 1) this.r = 1;\n\n\t\tif (this.g < 0) this.g = 0;\n\t\telse if (this.g > 1) this.g = 1;\n\n\t\tif (this.b < 0) this.b = 0;\n\t\telse if (this.b > 1) this.b = 1;\n\n\t\tif (this.a < 0) this.a = 0;\n\t\telse if (this.a > 1) this.a = 1;\n\t\treturn this;\n\t}\n\n\tstatic rgba8888ToColor (color: Color, value: number) {\n\t\tcolor.r = ((value & 0xff000000) >>> 24) / 255;\n\t\tcolor.g = ((value & 0x00ff0000) >>> 16) / 255;\n\t\tcolor.b = ((value & 0x0000ff00) >>> 8) / 255;\n\t\tcolor.a = ((value & 0x000000ff)) / 255;\n\t}\n\n\tstatic rgb888ToColor (color: Color, value: number) {\n\t\tcolor.r = ((value & 0x00ff0000) >>> 16) / 255;\n\t\tcolor.g = ((value & 0x0000ff00) >>> 8) / 255;\n\t\tcolor.b = ((value & 0x000000ff)) / 255;\n\t}\n\n\ttoRgb888 () {\n\t\tconst hex = (x: number) => (`0${(x * 255).toString(16)}`).slice(-2);\n\t\treturn Number(`0x${hex(this.r)}${hex(this.g)}${hex(this.b)}`);\n\t}\n\n\tstatic fromString (hex: string, color = new Color()): Color {\n\t\treturn color.setFromString(hex);\n\t}\n}\n\nexport class MathUtils {\n\tstatic epsilon = 0.00001;\n\tstatic epsilon2 = MathUtils.epsilon * MathUtils.epsilon;\n\t// biome-ignore lint/suspicious/noApproximativeNumericConstant: reference runtime\n\tstatic PI = 3.1415927;\n\tstatic PI2 = MathUtils.PI * 2;\n\tstatic invPI2 = 1 / MathUtils.PI2;\n\tstatic radiansToDegrees = 180 / MathUtils.PI;\n\tstatic radDeg = MathUtils.radiansToDegrees;\n\tstatic degreesToRadians = MathUtils.PI / 180;\n\tstatic degRad = MathUtils.degreesToRadians;\n\n\tstatic clamp (value: number, min: number, max: number) {\n\t\tif (value < min) return min;\n\t\tif (value > max) return max;\n\t\treturn value;\n\t}\n\n\tstatic cosDeg (degrees: number) {\n\t\treturn Math.cos(degrees * MathUtils.degRad);\n\t}\n\n\tstatic sinDeg (degrees: number) {\n\t\treturn Math.sin(degrees * MathUtils.degRad);\n\t}\n\n\tstatic atan2Deg (y: number, x: number) {\n\t\treturn Math.atan2(y, x) * MathUtils.radDeg;\n\t}\n\n\tstatic signum (value: number): number {\n\t\treturn value > 0 ? 1 : value < 0 ? -1 : 0;\n\t}\n\n\tstatic toInt (x: number) {\n\t\treturn x > 0 ? Math.floor(x) : Math.ceil(x);\n\t}\n\n\tstatic cbrt (x: number) {\n\t\tconst y = Math.pow(Math.abs(x), 1 / 3);\n\t\treturn x < 0 ? -y : y;\n\t}\n\n\tstatic randomTriangular (min: number, max: number): number {\n\t\treturn MathUtils.randomTriangularWith(min, max, (min + max) * 0.5);\n\t}\n\n\tstatic randomTriangularWith (min: number, max: number, mode: number): number {\n\t\tconst u = Math.random();\n\t\tconst d = max - min;\n\t\tif (u <= (mode - min) / d) return min + Math.sqrt(u * d * (mode - min));\n\t\treturn max - Math.sqrt((1 - u) * d * (max - mode));\n\t}\n\n\tstatic isPowerOfTwo (value: number) {\n\t\treturn value && (value & (value - 1)) === 0;\n\t}\n}\n\nexport abstract class Interpolation {\n\tstatic readonly linear: Interpolation = new class extends Interpolation {\n\t\tprotected applyInternal (a: number): number {\n\t\t\treturn a;\n\t\t}\n\t}();\n\n\t/** Aka \"smoothstep\". */\n\tstatic readonly smooth: Interpolation = new class extends Interpolation {\n\t\tprotected applyInternal (a: number): number {\n\t\t\treturn a * a * (3 - 2 * a);\n\t\t}\n\t}();\n\n\t/** Slow, then fast. */\n\tstatic readonly slowFast: Interpolation = new class extends Interpolation {\n\t\tprotected applyInternal (a: number): number {\n\t\t\treturn a * a;\n\t\t}\n\t}();\n\n\t/** Fast, then slow. */\n\tstatic readonly fastSlow: Interpolation = new class extends Interpolation {\n\t\tprotected applyInternal (a: number): number {\n\t\t\treturn (a - 1) * (a - 1) * -1 + 1;\n\t\t}\n\t}();\n\n\tstatic readonly circle: Interpolation = new class extends Interpolation {\n\t\tprotected applyInternal (a: number): number {\n\t\t\tif (a <= 0.5) {\n\t\t\t\ta *= 2;\n\t\t\t\treturn (1 - Math.sqrt(1 - a * a)) / 2;\n\t\t\t}\n\t\t\ta--;\n\t\t\ta *= 2;\n\t\t\treturn (Math.sqrt(1 - a * a) + 1) / 2;\n\t\t}\n\t}();\n\n\tprotected abstract applyInternal (a: number): number;\n\n\tapply (a: number): number;\n\tapply (start: number, end: number, a: number): number;\n\tapply (start: number, end?: number, a?: number): number {\n\t\tif (end === undefined || a === undefined) return this.applyInternal(start);\n\t\treturn start + (end - start) * this.applyInternal(a);\n\t}\n}\n\nexport class Pow extends Interpolation {\n\tprotected power = 2;\n\n\tconstructor (power: number) {\n\t\tsuper();\n\t\tthis.power = power;\n\t}\n\n\tapplyInternal (a: number): number {\n\t\tif (a <= 0.5) return Math.pow(a * 2, this.power) / 2;\n\t\treturn Math.pow((a - 1) * 2, this.power) / (this.power % 2 === 0 ? -2 : 2) + 1;\n\t}\n}\n\nexport class PowOut extends Pow {\n\tconstructor (power: number) {\n\t\tsuper(power);\n\t}\n\n\tapplyInternal (a: number): number {\n\t\treturn Math.pow(a - 1, this.power) * (this.power % 2 === 0 ? -1 : 1) + 1;\n\t}\n}\n\nexport class Utils {\n\tstatic SUPPORTS_TYPED_ARRAYS = typeof (Float32Array) !== \"undefined\";\n\n\tstatic arrayCopy<T> (source: ArrayLike<T>, sourceStart: number, dest: ArrayLike<T>, destStart: number, numElements: number) {\n\t\tfor (let i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) {\n\t\t\tdest[j] = source[i];\n\t\t}\n\t}\n\n\tstatic arrayFill<T> (array: ArrayLike<T>, fromIndex: number, toIndex: number, value: T) {\n\t\tfor (let i = fromIndex; i < toIndex; i++)\n\t\t\tarray[i] = value;\n\t}\n\n\t// biome-ignore lint/suspicious/noExplicitAny: ok any in this case\n\tstatic setArraySize<T> (array: Array<T>, size: number, value: any = 0): Array<T> {\n\t\tconst oldSize = array.length;\n\t\tif (oldSize === size) return array;\n\t\tarray.length = size;\n\t\tif (oldSize < size) {\n\t\t\tfor (let i = oldSize; i < size; i++) array[i] = value;\n\t\t}\n\t\treturn array;\n\t}\n\n\t// biome-ignore lint/suspicious/noExplicitAny: ok any in this case\n\tstatic ensureArrayCapacity<T> (array: Array<T>, size: number, value: any = 0): Array<T> {\n\t\tif (array.length >= size) return array;\n\t\treturn Utils.setArraySize(array, size, value);\n\t}\n\n\tstatic newArray<T> (size: number, defaultValue: T): Array<T> {\n\t\tconst array: T[] = [];\n\t\tfor (let i = 0; i < size; i++) array[i] = defaultValue;\n\t\treturn array;\n\t}\n\n\tstatic newFloatArray (size: number): NumberArrayLike {\n\t\tif (Utils.SUPPORTS_TYPED_ARRAYS)\n\t\t\treturn new Float32Array(size)\n\t\telse {\n\t\t\tconst array: number[] = [];\n\t\t\tfor (let i = 0; i < array.length; i++) array[i] = 0;\n\t\t\treturn array;\n\t\t}\n\t}\n\n\tstatic newShortArray (size: number): IntArrayLike {\n\t\tif (Utils.SUPPORTS_TYPED_ARRAYS)\n\t\t\treturn new Int16Array(size)\n\t\telse {\n\t\t\tconst array: number[] = [];\n\t\t\tfor (let i = 0; i < array.length; i++) array[i] = 0;\n\t\t\treturn array;\n\t\t}\n\t}\n\n\tstatic toFloatArray (array: Array<number>): number[] | Float32Array {\n\t\treturn Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array;\n\t}\n\n\tstatic toSinglePrecision (value: number) {\n\t\treturn Utils.SUPPORTS_TYPED_ARRAYS ? Math.fround(value) : value;\n\t}\n\n\t// This function is used to fix WebKit 602 specific issue described at https://esotericsoftware.com/forum/d/10109-ios-10-disappearing-graphics\n\tstatic webkit602BugfixHelper (alpha: number) {\n\t}\n\n\tstatic contains<T> (array: Array<T>, element: T, identity = true) {\n\t\tfor (let i = 0; i < array.length; i++)\n\t\t\tif (array[i] === element) return true;\n\t\treturn false;\n\t}\n\n\t// biome-ignore lint/suspicious/noExplicitAny: ok any in this case\n\tstatic enumValue (type: any, name: string) {\n\t\treturn type[name[0].toUpperCase() + name.slice(1)];\n\t}\n}\n\nexport class DebugUtils {\n\tstatic logBones (skeleton: Skeleton) {\n\t\tfor (let i = 0; i < skeleton.bones.length; i++) {\n\t\t\tconst bone = skeleton.bones[i].appliedPose;\n\t\t\tconsole.log(`${bone.bone.data.name}, ${bone.a}, ${bone.b}, ${bone.c}, ${bone.d}, ${bone.worldX}, ${bone.worldY}`);\n\t\t}\n\t}\n}\n\nexport class Pool<T> {\n\tprivate items = [] as T[];\n\tprivate instantiator: () => T;\n\n\tconstructor (instantiator: () => T) {\n\t\tthis.instantiator = instantiator;\n\t}\n\n\tobtain () {\n\t\t// biome-ignore lint/style/noNonNullAssertion: length check\n\t\treturn this.items.length > 0 ? this.items.pop()! : this.instantiator();\n\t}\n\n\tfree (item: T) {\n\t\t// biome-ignore lint/suspicious/noExplicitAny: T can be anything\n\t\t(item as any).reset?.();\n\t\tthis.items.push(item);\n\t}\n\n\tfreeAll (items: ArrayLike<T>) {\n\t\tfor (let i = 0; i < items.length; i++)\n\t\t\tthis.free(items[i]);\n\t}\n\n\tclear () {\n\t\tthis.items.length = 0;\n\t}\n}\n\nexport class Vector2 {\n\tconstructor (public x = 0, public y = 0) {\n\t}\n\n\tset (x: number, y: number): Vector2 {\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\treturn this;\n\t}\n\n\tlength () {\n\t\tconst x = this.x;\n\t\tconst y = this.y;\n\t\treturn Math.sqrt(x * x + y * y);\n\t}\n\n\tnormalize () {\n\t\tconst len = this.length();\n\t\tif (len !== 0) {\n\t\t\tthis.x /= len;\n\t\t\tthis.y /= len;\n\t\t}\n\t\treturn this;\n\t}\n}\n\nexport class TimeKeeper {\n\tmaxDelta = 0.064;\n\tframesPerSecond = 0;\n\tdelta = 0;\n\ttotalTime = 0;\n\n\tprivate lastTime = Date.now() / 1000;\n\tprivate frameCount = 0;\n\tprivate frameTime = 0;\n\n\tupdate () {\n\t\tconst now = Date.now() / 1000;\n\t\tthis.delta = now - this.lastTime;\n\t\tthis.frameTime += this.delta;\n\t\tthis.totalTime += this.delta;\n\t\tif (this.delta > this.maxDelta) this.delta = this.maxDelta;\n\t\tthis.lastTime = now;\n\n\t\tthis.frameCount++;\n\t\tif (this.frameTime > 1) {\n\t\t\tthis.framesPerSecond = this.frameCount / this.frameTime;\n\t\t\tthis.frameTime = 0;\n\t\t\tthis.frameCount = 0;\n\t\t}\n\t}\n}\n\nexport interface ArrayLike<T> {\n\tlength: number;\n\t[n: number]: T;\n}\n\nexport class WindowedMean {\n\tvalues: Array<number>;\n\taddedValues = 0;\n\tlastValue = 0;\n\tmean = 0;\n\tdirty = true;\n\n\tconstructor (windowSize: number = 32) {\n\t\tthis.values = new Array<number>(windowSize);\n\t}\n\n\thasEnoughData () {\n\t\treturn this.addedValues >= this.values.length;\n\t}\n\n\taddValue (value: number) {\n\t\tif (this.addedValues < this.values.length) this.addedValues++;\n\t\tthis.values[this.lastValue++] = value;\n\t\tif (this.lastValue > this.values.length - 1) this.lastValue = 0;\n\t\tthis.dirty = true;\n\t}\n\n\tgetMean () {\n\t\tif (this.hasEnoughData()) {\n\t\t\tif (this.dirty) {\n\t\t\t\tlet mean = 0;\n\t\t\t\tfor (let i = 0; i < this.values.length; i++)\n\t\t\t\t\tmean += this.values[i];\n\t\t\t\tthis.mean = mean / this.values.length;\n\t\t\t\tthis.dirty = false;\n\t\t\t}\n\t\t\treturn this.mean;\n\t\t}\n\t\treturn 0;\n\t}\n}\n", "/******************************************************************************\n * Spine Runtimes License Agreement\n * Last updated April 5, 2025. Replaces all prior versions.\n *\n * Copyright (c) 2013-2025, Esoteric Software LLC\n *\n * Integration of the Spine Runtimes into software or otherwise creating\n * derivative works of the Spine Runtimes is permitted under the terms and\n * conditions of Section 2 of the Spine Editor License Agreement:\n * http://esotericsoftware.com/spine-editor-license\n *\n * Otherwise, it is permitted to integrate the Spine Runtimes into software\n * or otherwise create derivative works of the Spine Runtimes (collectively,\n * \"Products\"), provided that each user of the Products must obtain their own\n * Spine Editor license and redistribution of the Products in any form must\n * include this license and copyright notice.\n *\n * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,\n * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *****************************************************************************/\n\n/** biome-ignore-all lint/suspicious/noExplicitAny: textures can be various type */\n\nexport abstract class Texture {\n\tprotected _image: HTMLImageElement | ImageBitmap | any;\n\n\tconstructor (image: HTMLImageElement | ImageBitmap | any) {\n\t\tthis._image = image;\n\t}\n\n\tgetImage (): HTMLImageElement | ImageBitmap | any {\n\t\treturn this._image;\n\t}\n\n\tabstract setFilters (minFilter: TextureFilter, magFilter: TextureFilter): void;\n\tabstract setWraps (uWrap: TextureWrap, vWrap: TextureWrap): void;\n\tabstract dispose (): void;\n}\n\nexport enum TextureFilter {\n\tNearest = 9728, // WebGLRenderingContext.NEAREST\n\tLinear = 9729, // WebGLRenderingContext.LINEAR\n\tMipMap = 9987, // WebGLRenderingContext.LINEAR_MIPMAP_LINEAR\n\tMipMapNearestNearest = 9984, // WebGLRenderingContext.NEAREST_MIPMAP_NEAREST\n\tMipMapLinearNearest = 9985, // WebGLRenderingContext.LINEAR_MIPMAP_NEAREST\n\tMipMapNearestLinear = 9986, // WebGLRenderingContext.NEAREST_MIPMAP_LINEAR\n\tMipMapLinearLinear = 9987 // WebGLRenderingContext.LINEAR_MIPMAP_LINEAR\n}\n\nexport enum TextureWrap {\n\tMirroredRepeat = 33648, // WebGLRenderingContext.MIRRORED_REPEAT\n\tClampToEdge = 33071, // WebGLRenderingContext.CLAMP_TO_EDGE\n\tRepeat = 10497 // WebGLRenderingContext.REPEAT\n}\n\nexport class TextureRegion {\n\ttexture: any;\n\tu = 0; v = 0;\n\tu2 = 0; v2 = 0;\n\twidth = 0; height = 0;\n\tdegrees = 0;\n\toffsetX = 0; offsetY = 0;\n\toriginalWidth = 0; originalHeight = 0;\n}\n\nexport class FakeTexture extends Texture {\n\tsetFilters (minFilter: TextureFilter, magFilter: TextureFilter) { }\n\tsetWraps (uWrap: TextureWrap, vWrap: TextureWrap) { }\n\tdispose () { }\n}\n", "/******************************************************************************\n * Spine Runtimes License Agreement\n * Last updated April 5, 2025. Replaces all prior versions.\n *\n * Copyright (c) 2013-2025, Esoteric Software LLC\n *\n * Integration of the Spine Runtimes into software or otherwise creating\n * derivative works of the Spine Runtimes is permitted under the terms and\n * conditions of Section 2 of the Spine Editor License Agreement:\n * http://esotericsoftware.com/spine-editor-license\n *\n * Otherwise, it is permitted to integrate the Spine Runtimes into software\n * or otherwise create derivative works of the Spine Runtimes (collectively,\n * \"Products\"), provided that each user of the Products must obtain their own\n * Spine Editor license and redistribution of the Products in any form must\n * include this license and copyright notice.\n *\n * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,\n * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *****************************************************************************/\n\nimport type { AssetManagerBase } from \"./AssetManagerBase.js\";\nimport { type Texture, TextureFilter, TextureRegion, TextureWrap } from \"./Texture.js\";\nimport { type Disposable, type StringMap, Utils } from \"./Utils.js\";\n\nexport class TextureAtlas implements Disposable {\n\tpages = [] as TextureAtlasPage[];\n\tregions = [] as TextureAtlasRegion[];\n\n\tconstructor (atlasText: string) {\n\t\tconst reader = new TextureAtlasReader(atlasText);\n\t\tconst entry = new Array<string>(4);\n\n\t\tconst pageFields: StringMap<(page: TextureAtlasPage) => void> = {};\n\t\tpageFields.size = (page: TextureAtlasPage) => {\n\t\t\tpage.width = parseInt(entry[1]);\n\t\t\tpage.height = parseInt(entry[2]);\n\t\t};\n\t\tpageFields.format = () => {\n\t\t\t// page.format = Format[tuple[0]]; we don't need format in WebGL\n\t\t};\n\t\tpageFields.filter = (page: TextureAtlasPage) => {\n\t\t\tpage.minFilter = Utils.enumValue(TextureFilter, entry[1]);\n\t\t\tpage.magFilter = Utils.enumValue(TextureFilter, entry[2]);\n\t\t};\n\t\tpageFields.repeat = (page: TextureAtlasPage) => {\n\t\t\tif (entry[1].indexOf('x') !== -1) page.uWrap = TextureWrap.Repeat;\n\t\t\tif (entry[1].indexOf('y') !== -1) page.vWrap = TextureWrap.Repeat;\n\t\t};\n\t\tpageFields.pma = (page: TextureAtlasPage) => {\n\t\t\tpage.pma = entry[1] === \"true\";\n\t\t};\n\n\t\tvar regionFields: StringMap<(region: TextureAtlasRegion) => void> = {};\n\t\tregionFields.xy = (region: TextureAtlasRegion) => { // Deprecated, use bounds.\n\t\t\tregion.x = parseInt(entry[1]);\n\t\t\tregion.y = parseInt(entry[2]);\n\t\t};\n\t\tregionFields.size = (region: TextureAtlasRegion) => { // Deprecated, use bounds.\n\t\t\tregion.width = parseInt(entry[1]);\n\t\t\tregion.height = parseInt(entry[2]);\n\t\t};\n\t\tregionFields.bounds = (region: TextureAtlasRegion) => {\n\t\t\tregion.x = parseInt(entry[1]);\n\t\t\tregion.y = parseInt(entry[2]);\n\t\t\tregion.width = parseInt(entry[3]);\n\t\t\tregion.height = parseInt(entry[4]);\n\t\t};\n\t\tregionFields.offset = (region: TextureAtlasRegion) => { // Deprecated, use offsets.\n\t\t\tregion.offsetX = parseInt(entry[1]);\n\t\t\tregion.offsetY = parseInt(entry[2]);\n\t\t};\n\t\tregionFields.orig = (region: TextureAtlasRegion) => { // Deprecated, use offsets.\n\t\t\tregion.originalWidth = parseInt(entry[1]);\n\t\t\tregion.originalHeight = parseInt(entry[2]);\n\t\t};\n\t\tregionFields.offsets = (region: TextureAtlasRegion) => {\n\t\t\tregion.offsetX = parseInt(entry[1]);\n\t\t\tregion.offsetY = parseInt(entry[2]);\n\t\t\tregion.originalWidth = parseInt(entry[3]);\n\t\t\tregion.originalHeight = parseInt(entry[4]);\n\t\t};\n\t\tregionFields.rotate = (region: TextureAtlasRegion) => {\n\t\t\tconst value = entry[1];\n\t\t\tif (value === \"true\")\n\t\t\t\tregion.degrees = 90;\n\t\t\telse if (value !== \"false\")\n\t\t\t\tregion.degrees = parseInt(value);\n\t\t};\n\t\tregionFields.index = (region: TextureAtlasRegion) => {\n\t\t\tregion.index = parseInt(entry[1]);\n\t\t};\n\n\t\tlet line = reader.readLine();\n\t\t// Ignore empty lines before first entry.\n\t\twhile (line && line.trim().length === 0)\n\t\t\tline = reader.readLine();\n\t\t// Header entries.\n\t\twhile (true) {\n\t\t\tif (!line || line.trim().length === 0) break;\n\t\t\tif (reader.readEntry(entry, line) === 0) break; // Silently ignore all header fields.\n\t\t\tline = reader.readLine();\n\t\t}\n\n\t\t// Page and region entries.\n\t\tlet page: TextureAtlasPage | null = null;\n\t\tlet names: string[] | null = null;\n\t\tlet values: number[][] | null = null;\n\t\twhile (true) {\n\t\t\tif (line === null) break;\n\t\t\tif (line.trim().length === 0) {\n\t\t\t\tpage = null;\n\t\t\t\tline = reader.readLine();\n\t\t\t} else if (!page) {\n\t\t\t\tpage = new TextureAtlasPage(line.trim());\n\t\t\t\twhile (true) {\n\t\t\t\t\tif (reader.readEntry(entry, line = reader.readLine()) === 0) break;\n\t\t\t\t\tconst field = pageFields[entry[0]];\n\t\t\t\t\tif (field) field(page);\n\t\t\t\t}\n\t\t\t\tthis.pages.push(page);\n\t\t\t} else {\n\t\t\t\tconst region = new TextureAtlasRegion(page, line);\n\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst count = reader.readEntry(entry, line = reader.readLine());\n\t\t\t\t\tif (count === 0) break;\n\t\t\t\t\tconst field = regionFields[entry[0]];\n\t\t\t\t\tif (field)\n\t\t\t\t\t\tfield(region);\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (!names) names = [];\n\t\t\t\t\t\tif (!values) values = [];\n\t\t\t\t\t\tnames.push(entry[0]);\n\t\t\t\t\t\tconst entryValues: number[] = [];\n\t\t\t\t\t\tfor (let i = 0; i < count; i++)\n\t\t\t\t\t\t\tentryValues.push(parseInt(entry[i + 1]));\n\t\t\t\t\t\tvalues.push(entryValues);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (region.originalWidth === 0 && region.originalHeight === 0) {\n\t\t\t\t\tregion.originalWidth = region.width;\n\t\t\t\t\tregion.originalHeight = region.height;\n\t\t\t\t}\n\t\t\t\tif (names && names.length > 0 && values && values.length > 0) {\n\t\t\t\t\tregion.names = names;\n\t\t\t\t\tregion.values = values;\n\t\t\t\t\tnames = null;\n\t\t\t\t\tvalues = null;\n\t\t\t\t}\n\t\t\t\tregion.u = region.x / page.width;\n\t\t\t\tregion.v = region.y / page.height;\n\t\t\t\tif (region.degrees === 90) {\n\t\t\t\t\tregion.u2 = (region.x + region.height) / page.width;\n\t\t\t\t\tregion.v2 = (region.y + region.width) / page.height;\n\t\t\t\t} else {\n\t\t\t\t\tregion.u2 = (region.x + region.width) / page.width;\n\t\t\t\t\tregion.v2 = (region.y + region.height) / page.height;\n\t\t\t\t}\n\t\t\t\tthis.regions.push(region);\n\t\t\t}\n\t\t}\n\t}\n\n\tfindRegion (name: string): TextureAtlasRegion | null {\n\t\tfor (let i = 0; i < this.regions.length; i++) {\n\t\t\tif (this.regions[i].name === name) {\n\t\t\t\treturn this.regions[i];\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tsetTextures (assetManager: AssetManagerBase, pathPrefix: string = \"\") {\n\t\tfor (const page of this.pages)\n\t\t\tpage.setTexture(assetManager.get(pathPrefix + page.name) as Texture);\n\t}\n\n\tdispose () {\n\t\tfor (let i = 0; i < this.pages.length; i++) {\n\t\t\tthis.pages[i].texture?.dispose();\n\t\t}\n\t}\n}\n\nclass TextureAtlasReader {\n\tlines: Array<string>;\n\tindex: number = 0;\n\n\tconstructor (text: string) {\n\t\tthis.lines = text.split(/\\r\\n|\\r|\\n/);\n\t}\n\n\treadLine (): string | null {\n\t\tif (this.index >= this.lines.length)\n\t\t\treturn null;\n\t\treturn this.lines[this.index++];\n\t}\n\n\treadEntry (entry: string[], line: string | null): number {\n\t\tif (!line) return 0;\n\t\tline = line.trim();\n\t\tif (line.length === 0) return 0;\n\n\t\tconst colon = line.indexOf(':');\n\t\tif (colon === -1) return 0;\n\t\tentry[0] = line.substr(0, colon).trim();\n\t\tfor (let i = 1, lastMatch = colon + 1; ; i++) {\n\t\t\tconst comma = line.indexOf(',', lastMatch);\n\t\t\tif (comma === -1) {\n\t\t\t\tentry[i] = line.substr(lastMatch).trim();\n\t\t\t\treturn i;\n\t\t\t}\n\t\t\tentry[i] = line.substr(lastMatch, comma - lastMatch).trim();\n\t\t\tlastMatch = comma + 1;\n\t\t\tif (i === 4) return 4;\n\t\t}\n\t}\n}\n\nexport class TextureAtlasPage {\n\tname: string;\n\tminFilter: TextureFilter = TextureFilter.Nearest;\n\tmagFilter: TextureFilter = TextureFilter.Nearest;\n\tuWrap: TextureWrap = TextureWrap.ClampToEdge;\n\tvWrap: TextureWrap = TextureWrap.ClampToEdge;\n\ttexture: Texture | null = null;\n\twidth: number = 0;\n\theight: number = 0;\n\tpma: boolean = false;\n\tregions = [] as TextureAtlasRegion[];\n\n\tconstructor (name: string) {\n\t\tthis.name = name;\n\t}\n\n\tsetTexture (texture: Texture) {\n\t\tthis.texture = texture;\n\t\ttexture.setFilters(this.minFilter, this.magFilter);\n\t\ttexture.setWraps(this.uWrap, this.vWrap);\n\t\tfor (const region of this.regions)\n\t\t\tregion.texture = texture;\n\t}\n}\n\nexport class TextureAtlasRegion extends TextureRegion {\n\tpage: TextureAtlasPage;\n\tname: string;\n\tx: number = 0;\n\ty: number = 0;\n\toffsetX: number = 0;\n\toffsetY: number = 0;\n\toriginalWidth: number = 0;\n\toriginalHeight: number = 0;\n\tindex: number = 0;\n\tdegrees: number = 0;\n\tnames: string[] | null = null;\n\tvalues: number[][] | null = null;\n\n\tconstructor (page: TextureAtlasPage, name: string) {\n\t\tsuper();\n\t\tthis.page = page;\n\t\tthis.name = name;\n\t\tpage.regions.push(this);\n\t}\n}\n", "/******************************************************************************\n * Spine Runtimes License Agreement\n * Last updated April 5, 2025. Replaces all prior versions.\n *\n * Copyright (c) 2013-2025, Esoteric Software LLC\n *\n * Integration of the Spine Runtimes into software or otherwise creating\n * derivative works of the Spine Runtimes is permitted under the terms and\n * conditions of Section 2 of the Spine Editor License Agreement:\n * http://esotericsoftware.com/spine-editor-license\n *\n * Otherwise, it is permitted to integrate the Spine Runtimes into software\n * or otherwise create derivative works of the Spine Runtimes (collectively,\n * \"Products\"), provided that each user of the Products must obtain their own\n * Spine Editor license and redistribution of the Products in any form must\n * include this license and copyright notice.\n *\n * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,\n * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *****************************************************************************/\n\nimport type { Skeleton } from \"../Skeleton.js\";\nimport type { Slot } from \"../Slot.js\";\nimport type { SlotPose } from \"../SlotPose.js\";\nimport { type NumberArrayLike, Utils } from \"../Utils.js\";\n\n/** The base class for all attachments. Multiple {@link Skeleton} instances, slots, or skins can use the same attachments. */\nexport abstract class Attachment {\n\tprivate static readonly empty: number[] = [];\n\n\tname: string;\n\n\t/** Timelines for the timeline attachment are also applied to this attachment.\n\t * @return May be null if no attachment-specific timelines should be applied. */\n\ttimelineAttachment?: Attachment;\n\n\t/** Slots that can have attachments whose {@link timelineAttachment} is this attachment. */\n\ttimelineSlots: number[] = Attachment.empty;\n\n\tconstructor (name: string) {\n\t\tif (!name) throw new Error(\"name cannot be null.\");\n\t\tthis.name = name;\n\t\tthis.timelineAttachment = this;\n\t}\n\n\tabstract copy (): Attachment;\n\n\t/** Returns true if the {@code slotIndex} or any {@link timelineSlots} have an attachment whose {@link timelineAttachment} is\n\t * this attachment.\n\t * @param slots The {@link Skeleton.slots}.\n\t * @param slotIndex The timeline's primary slot index. */\n\tpublic isTimelineActive (slots: Slot[], slotIndex: number, appliedPose: boolean): boolean {\n\t\tlet slot = slots[slotIndex];\n\t\tif (slot.bone.isActive()) {\n\t\t\tconst other = (appliedPose ? slot.getAppliedPose() : slot.getPose()).getAttachment();\n\t\t\tif (other != null && other.timelineAttachment === this) return true;\n\t\t}\n\t\tfor (let i = 0, n = this.timelineSlots.length; i < n; i++) {\n\t\t\tslot = slots[this.timelineSlots[i]];\n\t\t\tif (!slot.bone.isActive()) continue;\n\t\t\tconst other = (appliedPose ? slot.getAppliedPose() : slot.getPose()).getAttachment();\n\t\t\tif (other != null && other.timelineAttachment === this) return true;\n\t\t}\n\t\treturn false;\n\t}\n}\n\n/** Base class for an attachment with vertices that are transformed by one or more bones and can be deformed by\n * {@link SlotPose.deform}. */\nexport abstract class VertexAttachment extends Attachment {\n\tprivate static nextID = 0;\n\n\t/** The unique ID for this attachment. */\n\tid = VertexAttachment.nextID++;\n\n\t/** The bones that affect the {@link vertices}. The entries are, for each vertex, the number of bones affecting the vertex\n\t * followed by that many bone indices, which is {@link Skeleton.getBones} index. Null if this attachment has no weights. */\n\tbones: Array<number> | null = null;\n\n\t/** The vertex positions in the bone's coordinate system. For a non-weighted attachment, the values are `x,y`\n\t * entries for each vertex. For a weighted attachment, the values are `x,y,weight` triplets for each bone affecting\n\t * each vertex. */\n\tvertices: NumberArrayLike = [];\n\n\t/** The maximum number of world vertex values that can be output by\n\t * {@link computeWorldVertices} using the `count` parameter. */\n\tworldVerticesLength = 0;\n\n\tconstructor (name: string) {\n\t\tsuper(name);\n\t}\n\n\t/** Transforms the attachment's local {@link vertices} to world coordinates. If {@link SlotPose.getDeform} is not empty, it\n\t * is used to deform the vertices.\n\t *\n\t * See <a href=\"https://esotericsoftware.com/spine-runtime-skeletons#World-transforms\">World transforms</a> in the Spine\n\t * Runtimes Guide.\n\t * @param start The index of the first {@link vertices} value to transform. Each vertex has 2 values, x and y.\n\t * @param count The number of world vertex values to output. Must be <= {@link worldVerticesLength} - `start`.\n\t * @param worldVertices The output world vertices. Must have a length >= `offset` + `count` *\n\t * `stride` / 2.\n\t * @param offset The `worldVertices` index to begin writing values.\n\t * @param stride The number of `worldVertices` entries between the value pairs written. */\n\tcomputeWorldVertices (skeleton: Skeleton, slot: Slot, start: number, count: number, worldVertices: NumberArrayLike, offset: number,\n\t\tstride: number) {\n\n\t\tcount = offset + (count >> 1) * stride;\n\t\tconst deformArray = slot.appliedPose.deform;\n\t\tlet vertices = this.vertices;\n\t\tconst bones = this.bones;\n\t\tif (!bones) {\n\t\t\tif (deformArray.length > 0) vertices = deformArray;\n\t\t\tconst bone = slot.bone.appliedPose;\n\t\t\tconst x = bone.worldX;\n\t\t\tconst y = bone.worldY;\n\t\t\tconst a = bone.a, b = bone.b, c = bone.c, d = bone.d;\n\t\t\tfor (let v = start, w = offset; w < count; v += 2, w += stride) {\n\t\t\t\tconst vx = vertices[v], vy = vertices[v + 1];\n\t\t\t\tworldVertices[w] = vx * a + vy * b + x;\n\t\t\t\tworldVertices[w + 1] = vx * c + vy * d + y;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tlet v = 0, skip = 0;\n\t\tfor (let i = 0; i < start; i += 2) {\n\t\t\tconst n = bones[v];\n\t\t\tv += n + 1;\n\t\t\tskip += n;\n\t\t}\n\t\tconst skeletonBones = skeleton.bones;\n\t\tif (deformArray.length === 0) {\n\t\t\tfor (let w = offset, b = skip * 3; w < count; w += stride) {\n\t\t\t\tlet wx = 0, wy = 0;\n\t\t\t\tlet n = bones[v++];\n\t\t\t\tn += v;\n\t\t\t\tfor (; v < n; v++, b += 3) {\n\t\t\t\t\tconst bone = skeletonBones[bones[v]].appliedPose;\n\t\t\t\t\tconst vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2];\n\t\t\t\t\twx += (vx * bone.a + vy * bone.b + bone.worldX) * weight;\n\t\t\t\t\twy += (vx * bone.c + vy * bone.d + bone.worldY) * weight;\n\t\t\t\t}\n\t\t\t\tworldVertices[w] = wx;\n\t\t\t\tworldVertices[w + 1] = wy;\n\t\t\t}\n\t\t} else {\n\t\t\tconst deform = deformArray;\n\t\t\tfor (let w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) {\n\t\t\t\tlet wx = 0, wy = 0;\n\t\t\t\tlet n = bones[v++];\n\t\t\t\tn += v;\n\t\t\t\tfor (; v < n; v++, b += 3, f += 2) {\n\t\t\t\t\tconst bone = skeletonBones[bones[v]].appliedPose;\n\t\t\t\t\tconst vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2];\n\t\t\t\t\twx += (vx * bone.a + vy * bone.b + bone.worldX) * weight;\n\t\t\t\t\twy += (vx * bone.c + vy * bone.d + bone.worldY) * weight;\n\t\t\t\t}\n\t\t\t\tworldVertices[w] = wx;\n\t\t\t\tworldVertices[w + 1] = wy;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Does not copy id (generated) or name (set on construction). **/\n\tcopyTo (attachment: VertexAttachment) {\n\t\tif (this.bones) {\n\t\t\tattachment.bones = [];\n\t\t\tUtils.arrayCopy(this.bones, 0, attachment.bones, 0, this.bones.length);\n\t\t} else\n\t\t\tattachment.bones = null;\n\n\t\tif (this.vertices) {\n\t\t\tattachment.vertices = Utils.newFloatArray(this.vertices.length);\n\t\t\tUtils.arrayCopy(this.vertices, 0, attachment.vertices, 0, this.vertices.length);\n\t\t}\n\n\t\tattachment.worldVerticesLength = this.worldVerticesLength;\n\t\tattachment.timelineAttachment = this.timelineAttachment;\n\t\tattachment.timelineSlots = this.timelineSlots;\n\t}\n}\n", "/******************************************************************************\n * Spine Runtimes License Agreement\n * Last updated April 5, 2025. Replaces all prior versions.\n *\n * Copyright (c) 2013-2025, Esoteric Software LLC\n *\n * Integration of the Spine Runtimes into software or otherwise creating\n * derivative works of the Spine Runtimes is permitted under the terms and\n * conditions of Section 2 of the Spine Editor License Agreement:\n * http://esotericsoftware.com/spine-editor-license\n *\n * Otherwise, it is permitted to integrate the Spine Runtimes into software\n * or otherwise create derivative works of the Spine Runtimes (collectively,\n * \"Products\"), provided that each user of the Products must obtain their own\n * Spine Editor license and redistribution of the Products in any form must\n * include this license and copyright notice.\n *\n * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,\n * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *****************************************************************************/\n\nimport type { TextureRegion } from \"../Texture.js\";\nimport { TextureAtlasRegion } from \"../TextureAtlas.js\";\nimport { Color, type NumberArrayLike, Utils } from \"../Utils.js\";\nimport { VertexAttachment } from \"./Attachment.js\";\nimport type { HasSequence } from \"./HasSequence.js\";\nimport type { Sequence } from \"./Sequence.js\";\n\n/** An attachment that displays a textured mesh. A mesh has hull vertices and internal vertices within the hull. Holes are not\n * supported. Each vertex has UVs (texture coordinates) and triangles that are used to map an image on to the mesh.\n *\n * See [Mesh attachments](http://esotericsoftware.com/spine-meshes) in the Spine User Guide. */\nexport class MeshAttachment extends VertexAttachment implements HasSequence {\n\treadonly sequence: Sequence;\n\n\t/** The UV pair for each vertex, normalized within the texture region. */\n\tregionUVs: NumberArrayLike = [];\n\n\t/** Triplets of vertex indices which describe the mesh's triangulation. */\n\ttriangles: Array<number> = [];\n\n\t/** The number of entries at the beginning of {@link vertices} that make up the mesh hull. */\n\thullLength: number = 0;\n\n\t/** The name of the texture region for this attachment. */\n\tpath?: string;\n\n\t/** The color to tint the mesh. */\n\tcolor = new Color(1, 1, 1, 1);\n\n\tprivate sourceMesh: MeshAttachment | null = null;\n\n\t/** Vertex index pairs describing edges for controlling triangulation, or null if nonessential data was not exported. Mesh\n\t * triangles do not never cross edges. Triangulation is not performed at runtime. */\n\tedges: Array<number> = [];\n\n\t/** The width of the mesh's image. Available only when nonessential data was exported. */\n\twidth: number = 0;\n\n\t/** The height of the mesh's image. Available only when nonessential data was exported. */\n\theight: number = 0;\n\n\ttempColor = new Color(0, 0, 0, 0);\n\n\tconstructor (name: string, sequence: Sequence) {\n\t\tsuper(name);\n\t\tthis.sequence = sequence;\n\t}\n\n\tcopy (): MeshAttachment {\n\t\tif (this.sourceMesh) return this.newLinkedMesh();\n\n\t\tconst copy = new MeshAttachment(this.name, this.sequence.copy());\n\t\tcopy.path = this.path;\n\t\tcopy.color.setFromColor(this.color);\n\n\t\tthis.copyTo(copy);\n\t\tcopy.regionUVs = [];\n\t\tUtils.arrayCopy(this.regionUVs, 0, copy.regionUVs, 0, this.regionUVs.length);\n\t\tcopy.triangles = [];\n\t\tUtils.arrayCopy(this.triangles, 0, copy.triangles, 0, this.triangles.length);\n\t\tcopy.hullLength = this.hullLength;\n\n\t\t// Nonessential.\n\t\tif (this.edges) {\n\t\t\tcopy.edges = [];\n\t\t\tUtils.arrayCopy(this.edges, 0, copy.edges, 0, this.edges.length);\n\t\t}\n\t\tcopy.width = this.width;\n\t\tcopy.height = this.height;\n\n\t\treturn copy;\n\t}\n\n\tupdateSequence () {\n\t\tthis.sequence.update(this);\n\t}\n\n\t/** The source mesh if this is a linked mesh, else null. A linked mesh shares the {@link bones}, {@link vertices},\n\t * {@link regionUVs}, {@link triangles}, {@link hullLength}, {@link edges}, {@link width}, and {@link height} with the\n\t * source mesh, but may have a different {@link name} or {@link path}, and therefore a different texture region. */\n\tgetSourceMesh () {\n\t\treturn this.sourceMesh;\n\t}\n\n\tsetSourceMesh (sourceMesh: MeshAttachment | null) {\n\t\tthis.sourceMesh = sourceMesh;\n\t\tif (sourceMesh) {\n\t\t\tthis.bones = sourceMesh.bones;\n\t\t\tthis.vertices = sourceMesh.vertices;\n\t\t\tthis.worldVerticesLength = sourceMesh.worldVerticesLength;\n\t\t\tthis.regionUVs = sourceMesh.regionUVs;\n\t\t\tthis.triangles = sourceMesh.triangles;\n\t\t\tthis.hullLength = sourceMesh.hullLength;\n\t\t\tthis.worldVerticesLength = sourceMesh.worldVerticesLength\n\t\t\tthis.edges = sourceMesh.edges;\n\t\t\tthis.width = sourceMesh.width;\n\t\t\tthis.height = sourceMesh.height;\n\t\t}\n\t}\n\n\t/** Returns a new mesh with the {@link sourceMesh} set to this mesh's source mesh, if any, else to this mesh. **/\n\tnewLinkedMesh (): MeshAttachment {\n\t\tconst copy = new MeshAttachment(this.name, this.sequence.copy());\n\t\tcopy.timelineAttachment = this.timelineAttachment;\n\t\tcopy.path = this.path;\n\t\tcopy.color.setFromColor(this.color);\n\t\tcopy.setSourceMesh(this.sourceMesh ? this.sourceMesh : this);\n\t\tcopy.updateSequence();\n\t\treturn copy;\n\t}\n\n\t/** Computes {@link Sequence.getUVs | UVs} for a mesh attachment.\n\t * @param uvs Output array for the computed UVs, same length as regionUVs. */\n\tstatic computeUVs (region: TextureRegion | null, regionUVs: NumberArrayLike, uvs: NumberArrayLike): void {\n\t\tif (!region) throw new Error(\"Region not set.\");\n\t\tconst n = uvs.length;\n\t\tlet u = region.u, v = region.v, width = 0, height = 0;\n\t\tif (region instanceof TextureAtlasRegion) {\n\t\t\tconst page = region.page;\n\t\t\tconst textureWidth = page.width, textureHeight = page.height;\n\t\t\tswitch (region.degrees) {\n\t\t\t\tcase 90:\n\t\t\t\t\tu -= (region.originalHeight - region.offsetY - region.height) / textureWidth;\n\t\t\t\t\tv -= (region.originalWidth - region.offsetX - region.width) / textureHeight;\n\t\t\t\t\twidth = region.originalHeight / textureWidth;\n\t\t\t\t\theight = region.originalWidth / textureHeight;\n\t\t\t\t\tfor (let i = 0; i < n; i += 2) {\n\t\t\t\t\t\tuvs[i] = u + regionUVs[i + 1] * width;\n\t\t\t\t\t\tuvs[i + 1] = v + (1 - regionUVs[i]) * height;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\tcase 180:\n\t\t\t\t\tu -= (region.originalWidth - region.offsetX - region.width) / textureWidth;\n\t\t\t\t\tv -= region.offsetY / textureHeight;\n\t\t\t\t\twidth = region.originalWidth / textureWidth;\n\t\t\t\t\theight = region.originalHeight / textureHeight;\n\t\t\t\t\tfor (let i = 0; i < n; i += 2) {\n\t\t\t\t\t\tuvs[i] = u + (1 - regionUVs[i]) * width;\n\t\t\t\t\t\tuvs[i + 1] = v + (1 - regionUVs[i + 1]) * height;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\tcase 270:\n\t\t\t\t\tu -= region.offsetY / textureWidth;\n\t\t\t\t\tv -= region.offsetX / textureHeight;\n\t\t\t\t\twidth = region.originalHeight / textureWidth;\n\t\t\t\t\theight = region.originalWidth / textureHeight;\n\t\t\t\t\tfor (let i = 0; i < n; i += 2) {\n\t\t\t\t\t\tuvs[i] = u + (1 - regionUVs[i + 1]) * width;\n\t\t\t\t\t\tuvs[i + 1] = v + regionUVs[i] * height;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\tdefault:\n\t\t\t\t\tu -= region.offsetX / textureWidth;\n\t\t\t\t\tv -= (region.originalHeight - region.offsetY - region.height) / textureHeight;\n\t\t\t\t\twidth = region.originalWidth / textureWidth;\n\t\t\t\t\theight = region.originalHeight / textureHeight;\n\t\t\t}\n\t\t} else if (!region) {\n\t\t\tu = v = 0;\n\t\t\twidth = height = 1;\n\t\t} else {\n\t\t\twidth = region.u2 - u;\n\t\t\theight = region.v2 - v;\n\t\t}\n\n\t\tfor (let i = 0; i < n; i += 2) {\n\t\t\tuvs[i] = u + regionUVs[i] * width;\n\t\t\tuvs[i + 1] = v + regionUVs[i + 1] * height;\n\t\t}\n\t}\n}\n", "/******************************************************************************\n * Spine Runtimes License Agreement\n * Last updated April 5, 2025. Replaces all prior versions.\n *\n * Copyright (c) 2013-2025, Esoteric Software LLC\n *\n * Integration of the Spine Runtimes into software or otherwise creating\n * derivative works of the Spine Runtimes is permitted under the terms and\n * conditions of Section 2 of the Spine Editor License Agreement:\n * http://esotericsoftware.com/spine-editor-license\n *\n * Otherwise, it is permitted to integrate the Spine Runtimes into software\n * or otherwise create derivative works of the Spine Runtimes (collectively,\n * \"Products\"), provided that each user of the Products must obtain their own\n * Spine Editor license and redistribution of the Products in any form must\n * include this license and copyright notice.\n *\n * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,\n * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *****************************************************************************/\n\nimport type { SlotPose } from \"../SlotPose.js\";\nimport type { Slot } from \"../Slot.js\";\nimport type { TextureRegion } from \"../Texture.js\";\nimport { Color, MathUtils, type NumberArrayLike } from \"../Utils.js\";\nimport { Attachment } from \"./Attachment.js\";\nimport type { HasSequence } from \"./HasSequence.js\";\nimport type { Sequence } from \"./Sequence.js\";\n\n/** An attachment that displays a textured quadrilateral.\n *\n * See [Region attachments](http://esotericsoftware.com/spine-regions) in the Spine User Guide. */\nexport class RegionAttachment extends Attachment implements HasSequence {\n\treadonly sequence: Sequence;\n\n\t/** The local x translation. */\n\tx = 0;\n\n\t/** The local y translation. */\n\ty = 0;\n\n\t/** The local scaleX. */\n\tscaleX = 1;\n\n\t/** The local scaleY. */\n\tscaleY = 1;\n\n\t/** The local rotation in degrees, counter clockwise. */\