@melonjs/spine-plugin 1.5.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.1
4
+
5
+ ### Changed
6
+ - minimum melonJS version is now 18.2.1 (loading screen race condition fix)
7
+
8
+ ## 2.0.0
9
+
10
+ ### Changed
11
+ - migrated into the melonJS monorepo
12
+ - replaced rollup build with esbuild (aligned with debug-plugin)
13
+ - bumped Spine runtime dependencies to ^4.2.108
14
+ - minimum melonJS version is now 18.2.0
15
+ - WebGL rendering now uses a custom `SpineBatcher` extending melonJS `Batcher` with indexed drawing, instead of Spine's own `PolygonBatcher` — integrates through melonJS's batcher system (`setBatcher("spine")`)
16
+ - SpineBatcher uses Spine's official two-color tinting shader (`Shader.newTwoColoredTextured`) and attribute names
17
+ - blend modes now delegate to melonJS `renderer.setBlendMode()` with premultiplied alpha support
18
+ - canvas `SkeletonRenderer` refactored: extracted `drawRegion()`, `drawMesh()`, `drawTriangle()` methods from monolithic `draw()`
19
+ - `AssetManager` cleaned up: renamed `asset_manager` to `spineAssetManager`, added `dispose()`, fixed JSDoc
20
+ - source reorganized: `index.js` is the proper entry point, `Spine.js` is the renderable, `SpinePlugin.js` is the plugin registration
21
+ - `SpinePlugin.js` renamed from `index.js` for clarity
22
+
23
+ ### Fixed
24
+ - use `setBatcher`/`currentBatcher` instead of deprecated `setCompositor`/`currentCompositor`
25
+ - replace removed `utils.file.getPath()` with inline path extraction
26
+ - `rotate()` now always calls `super.rotate()` and returns `this` for chaining (WebGL path was missing both)
27
+ - `scale()` now applies scale to the Spine root bone as well as the melonJS transform
28
+ - `dispose()` now guards against calling WebGL-only methods on canvas renderer
29
+ - `throw "string"` replaced with `throw new Error()` for proper stack traces
30
+ - `setAnimationByIndex`/`addAnimationByIndex` now use `console.warn` instead of `console.log` for errors
31
+ - canvas `drawTriangle()` now guards against degenerate triangles (zero-area UV)
32
+ - canvas mesh drawing now subtracts 1 pixel from UV dimensions to prevent edge bleeding (matches official spine-canvas)
33
+
34
+ ### Added
35
+ - `SpineBatcher`: custom melonJS `Batcher` for two-color tinted Spine rendering via indexed `drawElements`
36
+ - `addAnimation(trackIndex, name, loop, delay)` method for adding queued animations by name
37
+ - `setCombinedSkin(combinedName, ...skinNames)` for mix-and-match skin combining
38
+ - `setEmptyAnimation(trackIndex, mixDuration)` for clearing animation tracks
39
+ - `findBone(boneName)` and `findSlot(slotName)` for direct skeleton access
40
+ - `addAnimationListener(listener)` and `removeAnimationListener(listener)` for animation state events (start, end, complete, event, etc.)
41
+ - `getAnimationNames()` and `getSkinNames()` for skeleton introspection
42
+ - `skeleton.update(delta)` call before `updateWorldTransform()` as required by Spine 4.2+
43
+ - canvas `SkeletonRenderer` auto-detects mesh attachments and enables `triangleRendering` only when needed
44
+ - spine example added to the monorepo examples app with character selector dropdown and debug plugin
45
+
46
+ ### Removed
47
+ - redundant `getSpinePosition()`, `setSpineSize()`, `getSpineSize()` methods (use inherited `pos`, `width`, `height`)
48
+ - redundant `addAnimationByName()` (replaced by `addAnimation()`)
49
+ - old melonJS version check hack in constructor (no longer needed with >=18.2.0)
50
+ - old test/examples folder (replaced by monorepo examples)
51
+ - custom GLSL shaders (now uses Spine's official `Shader.newTwoColoredTextured`)
52
+ - manual GL state management in `resetRenderer()`/`enableRenderer()`/`end()` (replaced by melonJS batcher system)
53
+
3
54
  ## 1.5.0 - 2023-09-23
4
55
 
5
56
  - fix the `addAnimation()` method not returning the corresponding set TrackEntry
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (C) 2011 - 2023 Olivier Biot (AltByte Pte Ltd)
3
+ Copyright (C) 2011 - 2026 Olivier Biot (AltByte Pte Ltd)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,28 +1,44 @@
1
1
  # melonJS Spine Plugin
2
2
 
3
- a [Spine](http://en.esotericsoftware.com/spine-in-depth) 4.x plugin implementation for [melonJS 2](http://www.melonjs.org)
3
+ A [Spine](http://en.esotericsoftware.com/spine-in-depth) 4.2 runtime integration for the [melonJS](http://www.melonjs.org) game engine, using the official [@esotericsoftware/spine-webgl](https://www.npmjs.com/package/@esotericsoftware/spine-webgl) and [@esotericsoftware/spine-canvas](https://www.npmjs.com/package/@esotericsoftware/spine-canvas) runtimes.
4
4
 
5
5
  ![melonjs-spine-gif](https://github.com/melonjs/spine-plugin/assets/4033090/dc259c8e-def6-419e-83a9-cda374715686)
6
6
 
7
- >Note: although functional, this plugin is still a work in progress. Feedback and especially contributions are welcome!
8
-
9
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/melonjs/es6-boilerplate/blob/master/LICENSE)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/melonjs/melonJS/blob/master/packages/spine-plugin/LICENSE)
10
8
  [![NPM Package](https://img.shields.io/npm/v/@melonjs/spine-plugin)](https://www.npmjs.com/package/@melonjs/spine-plugin)
11
- [![jsDeliver](https://data.jsdelivr.com/v1/package/npm/@melonjs/spine-plugin/badge?style=rounded)](https://www.jsdelivr.com/package/npm/@melonjs/spine-plugin)
9
+ [![Spine Runtime](https://img.shields.io/badge/spine--runtime-4.2-orange)](http://esotericsoftware.com/spine-runtimes)
10
+
11
+ [Live Example](https://melonjs.github.io/melonJS/examples/#/spine) — 17 official Spine characters including spineboy, raptor, owl, dragon, and more
12
12
 
13
+ ## Features
14
+ -------------------------------------------------------------------------------
15
+ - **WebGL rendering** via custom `SpineBatcher` extending melonJS `Batcher` with two-color tinting and indexed drawing
16
+ - **Canvas rendering** with full mesh, clipping, tinting, and blend mode support
17
+ - **Spine 4.2 physics** support with automatic gravity correction for Y-down coordinate system
18
+ - **Two-color tinting** (dark/light color) using Spine's official shader
19
+ - **Blend modes** (Normal, Additive, Multiply, Screen) with premultiplied alpha support
20
+ - **Clipping attachments** via melonJS masking (canvas) and Spine's SkeletonClipping (WebGL)
21
+ - **Skin support** including mix-and-match skin combining via `setCombinedSkin()`
22
+ - **Animation state events** (start, end, complete, event, interrupt, dispose)
23
+ - **Skeleton introspection** — `findBone()`, `findSlot()`, `getAnimationNames()`, `getSkinNames()`
24
+ - **Animation queuing** — `setAnimation()`, `addAnimation()`, `setEmptyAnimation()`
25
+ - **Debug rendering** for bones, regions, meshes, and clipping areas
26
+ - **Auto-detection** of mesh attachments for optimized canvas rendering (fast path for region-only skeletons)
27
+ - **Binary skeleton** (.skel) and JSON skeleton loading via melonJS preloader
28
+ - **Integrated** with melonJS batcher system — no manual GL state management
13
29
 
14
30
  ## Installation
15
31
  -------------------------------------------------------------------------------
16
- this plugin is already bundled with the required Spine [4.x runtime](package.json#dependencies), so there is no need to install it separately.
17
- >Note: this plugin requires melonJS version 15.12 or higher.
32
+ This plugin is already bundled with the required Spine [4.x runtime](package.json#dependencies), so there is no need to install it separately.
33
+ >Note: this plugin requires melonJS version 18.2.1 or higher.
18
34
 
19
- To install the plugin using npm :
35
+ To install the plugin using npm:
20
36
 
21
- `$ [sudo] npm install @melonjs/spine-plugin`
37
+ `$ npm install @melonjs/spine-plugin`
22
38
 
23
39
  Then import and use the plugin in your project. For example:
24
40
  ```JavaScript
25
- import { SpinePlugin } from '@melonjs/spine-plugin';
41
+ import Spine, { SpinePlugin } from '@melonjs/spine-plugin';
26
42
  import * as me from 'melonjs';
27
43
 
28
44
  // register the plugin
@@ -42,9 +58,6 @@ const DataManifest = [
42
58
  },
43
59
  ];
44
60
 
45
- // import default Spine class
46
- import Spine from '@melonjs/spine-plugin';
47
-
48
61
  // preload assets
49
62
  me.loader.preload(DataManifest, async function() {
50
63
 
@@ -59,24 +72,59 @@ me.loader.preload(DataManifest, async function() {
59
72
 
60
73
  }
61
74
  ```
62
- >Note: use "spine" as a value for the `type` property to indicate which assets and are actual Spine assets and to be loaded using the plugin (requires version 1.4.0 or higher of the Spine plugin)
75
+ >Note: use "spine" as a value for the `type` property to indicate which assets are actual Spine assets and to be loaded using the plugin
63
76
 
64
- for more details, see a complete usage example in the [test](test) folder
77
+ ## API
78
+ -------------------------------------------------------------------------------
79
+
80
+ ### Animation
81
+ | Method | Description |
82
+ |---|---|
83
+ | `setAnimation(trackIndex, name, loop)` | Set the current animation for a track |
84
+ | `setAnimationByIndex(trackIndex, index, loop)` | Set animation by index |
85
+ | `addAnimation(trackIndex, name, loop, delay)` | Queue an animation after the current one |
86
+ | `setEmptyAnimation(trackIndex, mixDuration)` | Clear a track with optional mix out |
87
+ | `isCurrentAnimation(name)` | Check if a specific animation is playing |
88
+ | `setDefaultMixTime(mixTime)` | Set default mix duration between animations |
89
+ | `setTransitionMixTime(from, to, mixTime)` | Set mix duration between two specific animations |
90
+ | `addAnimationListener(listener)` | Register animation event callbacks |
91
+ | `removeAnimationListener(listener)` | Remove a registered listener |
92
+ | `getAnimationNames()` | Get list of available animation names |
93
+
94
+ ### Skins
95
+ | Method | Description |
96
+ |---|---|
97
+ | `setSkinByName(skinName)` | Set a skin by name |
98
+ | `setCombinedSkin(name, ...skinNames)` | Combine multiple skins (mix-and-match) |
99
+ | `getSkinNames()` | Get list of available skin names |
100
+
101
+ ### Skeleton
102
+ | Method | Description |
103
+ |---|---|
104
+ | `findBone(boneName)` | Find a bone by name |
105
+ | `findSlot(slotName)` | Find a slot by name |
106
+ | `setToSetupPose()` | Reset skeleton to setup pose |
107
+ | `setSkeleton(atlasFile, jsonFile)` | Load a skeleton (if not set via constructor) |
108
+
109
+ ### Transform
110
+ | Method | Description |
111
+ |---|---|
112
+ | `flipX(flip)` | Flip horizontally |
113
+ | `flipY(flip)` | Flip vertically |
114
+ | `scale(x, y)` | Scale the skeleton |
115
+ | `rotate(angle)` | Rotate the skeleton |
65
116
 
66
117
  ## Compatibility
67
118
  -------------------------------------------------------------------------------
68
119
 
69
- below is the compatibility version matrix :
70
-
71
- | melonJS | @melonjs/spine-plugin | spine-runtime |
120
+ | @melonjs/spine-plugin | melonJS | spine-runtime |
72
121
  |---|---|---|
73
- | v15.12.x (or higher) | v1.x | v4.1, v4.2-beta |
74
-
75
- >Note: the current version of the spine-plugin is bundled with the 4.2.x beta version of the Spine runtime, which is for now backward compatible with the Spine 4.1 runtime (from a player/rendering point of view).
122
+ | v2.0.1+ | v18.2.1 (or higher) | v4.2.x |
123
+ | v2.0.0 | v18.2.0 | v4.2.x |
124
+ | v1.5.x | v15.12.x v18.0.x | v4.1, v4.2-beta |
76
125
 
77
126
  ## Questions, need help ?
78
127
  -------------------------------------------------------------------------------
79
- If you need technical support, you can contact us through the following channels :
80
- * Forums: with melonJS 2 we moved to a new discourse [forum](https://melonjs.discourse.group), but we can still also find the previous one [here](http://www.html5gamedevs.com/forum/32-melonjs/)
81
- * Chat: come and chat with us on [discord](https://discord.gg/aur7JMk), or [gitter](https://gitter.im/melonjs/public)
82
- * we tried to keep our [wikipage](https://github.com/melonjs/melonJS/wiki) up-to-date with useful links, tutorials, and anything related melonJS.
128
+ If you need technical support, you can contact us through the following channels:
129
+ * Chat: come and chat with us on [discord](https://discord.gg/aur7JMk)
130
+ * We tried to keep our [wiki](https://github.com/melonjs/melonJS/wiki) up-to-date with useful links, tutorials, and anything related to melonJS.
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @classdesc
3
+ * An Asset Manager class that integrates Spine's asset loading with
4
+ * melonJS's preloader via a custom "spine" parser.
5
+ * Handles loading of atlas, JSON skeleton, and binary skeleton (.skel) files.
6
+ */
7
+ export default class AssetManager {
8
+ /**
9
+ * @param {CanvasRenderer|WebGLRenderer} renderer - a melonJS renderer instance
10
+ * @param {string} [pathPrefix=""] - a default path prefix for assets location
11
+ */
12
+ constructor(renderer: CanvasRenderer | WebGLRenderer, pathPrefix?: string);
13
+ /**
14
+ * the underlying Spine asset manager
15
+ * @ignore
16
+ */
17
+ spineAssetManager: spineWebGL.AssetManager | spineCanvas.AssetManager;
18
+ /**
19
+ * Set a default path prefix for assets location.
20
+ * @param {string} pathPrefix
21
+ */
22
+ setPrefix(pathPrefix: string): void;
23
+ /**
24
+ * Load a spine atlas and skeleton file pair.
25
+ * @param {string} atlas - atlas filename (e.g. "alien.atlas")
26
+ * @param {string} skel - skeleton filename (.json or .skel)
27
+ * @example
28
+ * // manually load spine assets
29
+ * plugin.assetManager.setPrefix("data/spine/");
30
+ * plugin.assetManager.loadAsset("alien.atlas", "alien-ess.json");
31
+ * await plugin.assetManager.loadAll();
32
+ */
33
+ loadAsset(atlas: string, skel: string): void;
34
+ /**
35
+ * Load a texture atlas file.
36
+ * @param {string} atlas - atlas filename
37
+ * @param {Function} [onload] - callback on successful load
38
+ * @param {Function} [onerror] - callback on error
39
+ */
40
+ loadTextureAtlas(atlas: string, onload?: Function, onerror?: Function): void;
41
+ /**
42
+ * Load a binary skeleton (.skel) file.
43
+ * @param {string} skel - skeleton binary filename
44
+ * @param {Function} [onload] - callback on successful load
45
+ * @param {Function} [onerror] - callback on error
46
+ */
47
+ loadBinary(skel: string, onload?: Function, onerror?: Function): void;
48
+ /**
49
+ * Load a JSON skeleton file.
50
+ * @param {string} skel - skeleton JSON filename
51
+ * @param {Function} [onload] - callback on successful load
52
+ * @param {Function} [onerror] - callback on error
53
+ */
54
+ loadText(skel: string, onload?: Function, onerror?: Function): void;
55
+ /**
56
+ * Load all queued spine assets.
57
+ * @returns {Promise} resolves when all assets are loaded
58
+ * @see loadAsset
59
+ */
60
+ loadAll(): Promise<any>;
61
+ /**
62
+ * Get a loaded asset by path.
63
+ * @param {string} path - the asset path/name
64
+ * @returns {*} the loaded asset (TextureAtlas, skeleton data, etc.)
65
+ */
66
+ require(path: string): any;
67
+ /**
68
+ * Dispose all loaded assets and release GPU resources.
69
+ */
70
+ dispose(): void;
71
+ }
72
+ import * as spineWebGL from "@esotericsoftware/spine-webgl";
73
+ import * as spineCanvas from "@esotericsoftware/spine-canvas";
74
+ //# sourceMappingURL=AssetManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetManager.d.ts","sourceRoot":"","sources":["../src/AssetManager.js"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH;IACC;;;OAGG;IACH,sBAHW,cAAc,GAAC,aAAa,eAC5B,MAAM,EA0ChB;IAvCA;;;OAGG;IACH,sEAG4C;IAkC7C;;;OAGG;IACH,sBAFW,MAAM,QAIhB;IAED;;;;;;;;;OASG;IACH,iBARW,MAAM,QACN,MAAM,QAgBhB;IAED;;;;;OAKG;IACH,wBAJW,MAAM,+CAMhB;IAED;;;;;OAKG;IACH,iBAJW,MAAM,+CAMhB;IAED;;;;;OAKG;IACH,eAJW,MAAM,+CAMhB;IAED;;;;OAIG;IACH,wBAEC;IAED;;;;OAIG;IACH,cAHW,MAAM,GACJ,GAAC,CAIb;IAED;;OAEG;IACH,gBAEC;CACD;4BA3I2B,+BAA+B;6BAD9B,gCAAgC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @classdesc
3
+ * A Canvas-based Spine skeleton renderer that draws through melonJS's
4
+ * canvas renderer API (drawImage, transform, setTint, setMask, etc.).
5
+ * This provides proper integration with melonJS's canvas rendering pipeline
6
+ * including tinting, blend modes, and clipping support.
7
+ */
8
+ export default class SkeletonRenderer {
9
+ /**
10
+ * Whether to enable triangle rendering for mesh attachments.
11
+ * When false, only region (image) attachments are rendered using the
12
+ * fast bone-transform path. Automatically enabled by Spine when the
13
+ * skeleton contains mesh attachments.
14
+ * @type {boolean}
15
+ * @default false
16
+ */
17
+ triangleRendering: boolean;
18
+ /**
19
+ * Whether to render debug outlines for regions, meshes, and clips
20
+ * @type {boolean}
21
+ * @default false
22
+ */
23
+ debugRendering: boolean;
24
+ tintColor: MColor;
25
+ tempColor: MColor;
26
+ clipper: SkeletonClipping;
27
+ clippingVertices: any[];
28
+ clippingMask: Polygon;
29
+ /**
30
+ * Draw the given skeleton using the melonJS canvas renderer.
31
+ * @param {CanvasRenderer} renderer - the melonJS canvas renderer
32
+ * @param {Skeleton} skeleton - the Spine skeleton to draw
33
+ */
34
+ draw(renderer: CanvasRenderer, skeleton: Skeleton): void;
35
+ /**
36
+ * Draw a region attachment (single quad image).
37
+ * @param {CanvasRenderer} renderer
38
+ * @param {HTMLImageElement} image
39
+ * @param {Bone} bone
40
+ * @param {RegionAttachment} attachment
41
+ * @param {TextureRegion} region
42
+ * @param {Polygon|null} mask - clipping mask if active
43
+ * @param {boolean} debug - whether to draw debug outline
44
+ * @ignore
45
+ */
46
+ drawRegion(renderer: CanvasRenderer, image: HTMLImageElement, bone: Bone, attachment: RegionAttachment, region: TextureRegion, mask: Polygon | null, debug: boolean): void;
47
+ /**
48
+ * Draw a mesh attachment as a series of textured triangles.
49
+ * @param {CanvasRenderer} renderer
50
+ * @param {HTMLImageElement} image
51
+ * @param {Float32Array} vertices - world vertices
52
+ * @param {number[]} triangles - triangle indices
53
+ * @ignore
54
+ */
55
+ drawMesh(renderer: CanvasRenderer, image: HTMLImageElement, vertices: Float32Array, triangles: number[]): void;
56
+ /**
57
+ * Draw a single textured triangle using affine transform.
58
+ * @ignore
59
+ */
60
+ drawTriangle(renderer: any, img: any, x0: any, y0: any, u0: any, v0: any, x1: any, y1: any, u1: any, v1: any, x2: any, y2: any, u2: any, v2: any): void;
61
+ /**
62
+ * Compute world vertices for a mesh attachment with color and UV data.
63
+ * @param {Slot} slot
64
+ * @param {MeshAttachment} mesh
65
+ * @param {number} vertexSize - floats per vertex
66
+ * @ignore
67
+ */
68
+ computeMeshVertices(slot: Slot, mesh: MeshAttachment, vertexSize: number): void;
69
+ }
70
+ import { Color as MColor } from "melonjs";
71
+ import { SkeletonClipping } from "@esotericsoftware/spine-core";
72
+ import { Polygon } from "melonjs";
73
+ import { RegionAttachment } from "@esotericsoftware/spine-core";
74
+ import { MeshAttachment } from "@esotericsoftware/spine-core";
75
+ //# sourceMappingURL=SkeletonRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkeletonRenderer.d.ts","sourceRoot":"","sources":["../src/SkeletonRenderer.js"],"names":[],"mappings":"AA0BA;;;;;;GAMG;AACH;IACC;;;;;;;OAOG;IACH,mBAHU,OAAO,CAGS;IAE1B;;;;OAIG;IACH,gBAHU,OAAO,CAGM;IAGvB,kBAAyB;IACzB,kBAAyB;IAGzB,0BAAiC;IACjC,wBAAsB;IACtB,sBAIG;IAEH;;;;OAIG;IACH,eAHW,cAAc,YACd,QAAQ,QAiGlB;IAED;;;;;;;;;;OAUG;IACH,qBATW,cAAc,SACd,gBAAgB,QAChB,IAAI,cACJ,gBAAgB,UAChB,aAAa,QACb,OAAO,GAAC,IAAI,SACZ,OAAO,QAqDjB;IAED;;;;;;;OAOG;IACH,mBANW,cAAc,SACd,gBAAgB,YAChB,YAAY,aACZ,MAAM,EAAE,QA8BlB;IAED;;;OAGG;IACH,wJA2CC;IAED;;;;;;OAMG;IACH,0BALW,IAAI,QACJ,cAAc,cACd,MAAM,QAwChB;CACD;gCAlWuD,SAAS;iCAD1D,8BAA8B;wBACmB,SAAS;iCAD1D,8BAA8B;+BAA9B,8BAA8B"}