Skip to content

Migrate spine-plugin into monorepo with custom SpineBatcher#1331

Merged
obiot merged 4 commits intomasterfrom
chore/add-spine-plugin
Mar 29, 2026
Merged

Migrate spine-plugin into monorepo with custom SpineBatcher#1331
obiot merged 4 commits intomasterfrom
chore/add-spine-plugin

Conversation

@obiot
Copy link
Copy Markdown
Member

@obiot obiot commented Mar 28, 2026

Summary

Brings the @melonjs/spine-plugin from its standalone repo into the monorepo, fully revamped with proper melonJS batcher integration.

melonJS Batcher improvements

  • Batcher: configurable maxVertices, optional indexed drawing (settings.indexed), configurable projectionUniform
  • IndexBuffer: refactored for both static quad patterns and dynamic stream drawing
  • VertexArrayBuffer: new pushFloats() for variable-length all-float vertex data

Spine plugin revamp

  • SpineBatcher: custom melonJS Batcher using Spine's official two-color shader, indexed drawElements, blend modes via renderer.setBlendMode()
  • Canvas SkeletonRenderer: refactored with drawRegion/drawMesh/drawTriangle, auto-detect mesh attachments for fast path, degenerate triangle guard, UV edge bleeding fix
  • New API: setCombinedSkin, setEmptyAnimation, findBone, findSlot, addAnimationListener, getAnimationNames, getSkinNames
  • Physics: gravity inversion for Y-down, skeleton.update() for Spine 4.2+
  • Fixed: rotate/scale chaining, dispose guard, error handling, JSDoc
  • Cleaned up: source reorganized (index.js entry point), AssetManager refactored, all lint passing

Examples

  • 17 official Spine characters (spineboy, raptor, owl, dragon, tank, hero, etc.)
  • Character selector dropdown with debug plugin

Test plan

  • All 1848 tests pass
  • WebGL rendering works with custom SpineBatcher
  • Canvas rendering works with SkeletonRenderer
  • Physics (cloud-pot rain) falls correctly
  • All 17 characters render and animate
  • Debug panel with hitbox rendering works alongside Spine

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings March 28, 2026 06:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates @melonjs/spine-plugin into the monorepo and aligns its build/tooling with the existing plugin packages (esbuild + shared tsconfig), while bringing over the plugin source and demo assets.

Changes:

  • Add packages/spine-plugin package with esbuild-based build + clean scripts and TS configs for declaration generation.
  • Import Spine plugin source (src/) and demo/test harness (test/) including sample Spine assets.
  • Update pnpm-lock.yaml to include the new workspace package and Spine runtime dependencies.

Reviewed changes

Copilot reviewed 38 out of 61 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds spine-plugin workspace importer entries and Spine runtime package resolutions.
packages/spine-plugin/tsconfig.json Package TS config extending shared base; noEmit for local typechecking.
packages/spine-plugin/tsconfig.build.json TS build config for emitting declarations into build/.
packages/spine-plugin/scripts/clean.ts Build artifact cleanup (removes build/).
packages/spine-plugin/scripts/build.ts esbuild bundling entrypoint for the plugin.
packages/spine-plugin/package.json Defines package metadata, exports/types paths, deps, and build scripts.
packages/spine-plugin/src/index.js Main Spine renderable implementation + WebGL/Canvas rendering paths.
packages/spine-plugin/src/SpinePlugin.js Plugin registration entry (asset manager + startup logging).
packages/spine-plugin/src/SkeletonRenderer.js Canvas renderer implementation for Spine skeletons (with clipping/mesh support).
packages/spine-plugin/src/AssetManager.js Integrates Spine asset loading into melonJS loader via a custom parser.
packages/spine-plugin/test/index.css Styles for the demo pages.
packages/spine-plugin/test/js/index.js Demo bootstrap (video init, plugin registration, preload, scene setup).
packages/spine-plugin/test/js/manifest.js Demo asset manifest for loader preload.
packages/spine-plugin/test/js/renderables/spine.js Demo renderable that wraps Spine and adds basic input/body behavior.
packages/spine-plugin/test/alien.html Demo page for alien skeleton.
packages/spine-plugin/test/coin.html Demo page for coin skeleton.
packages/spine-plugin/test/dragon.html Demo page for dragon skeleton.
packages/spine-plugin/test/mix-and-match.html Demo page for mix-and-match skeleton.
packages/spine-plugin/test/owl.html Demo page for owl skeleton.
packages/spine-plugin/test/spineboy.html Demo page for spineboy skeleton.
packages/spine-plugin/test/stretchyman.html Demo page for stretchyman skeleton.
packages/spine-plugin/test/data/spine/alien.atlas Demo Spine atlas data.
packages/spine-plugin/test/data/spine/coin-pma.atlas Demo Spine atlas data (PMA).
packages/spine-plugin/test/data/spine/coin-pro.json Demo Spine skeleton JSON.
packages/spine-plugin/test/data/spine/coin-pro.skel Demo Spine skeleton binary.
packages/spine-plugin/test/data/spine/dragon-ess.json Demo Spine skeleton JSON.
packages/spine-plugin/test/data/spine/dragon-ess.skel Demo Spine skeleton binary.
packages/spine-plugin/test/data/spine/dragon-pma.atlas Demo Spine atlas data (PMA, multi-page).
packages/spine-plugin/test/data/spine/dragon-pma_2.png Demo texture image.
packages/spine-plugin/test/data/spine/mix-and-match-pma.atlas Demo Spine atlas data (PMA).
packages/spine-plugin/test/data/spine/owl-pma.atlas Demo Spine atlas data (PMA).
packages/spine-plugin/test/data/spine/owl-pro.skel Demo Spine skeleton binary.
packages/spine-plugin/test/data/spine/owl.atlas Demo Spine atlas data.
packages/spine-plugin/test/data/spine/spineboy-pma.atlas Demo Spine atlas data (PMA).
packages/spine-plugin/test/data/spine/stretchyman-pma.atlas Demo Spine atlas data (PMA).
packages/spine-plugin/test/data/spine/stretchyman.atlas Demo Spine atlas data.
packages/spine-plugin/README.md Package README brought into monorepo.
packages/spine-plugin/LICENSE Package license file.
packages/spine-plugin/CHANGELOG.md Package changelog brought into monorepo.
packages/spine-plugin/.gitignore Ignores build/ and other package-local artifacts.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +16 to +19
"melonjs": "https://cdn.jsdelivr.net/npm/melonjs@15.12/+esm",
"debugPlugin" : "https://cdn.jsdelivr.net/npm/@melonjs/debug-plugin/dist/@melonjs/debug-plugin.js",
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test HTML files import the spine plugin from ./../dist/@melonjs/spine-plugin.js, but this package’s build output is now configured to emit into build/ (and dist/ is not present). Update the import map to reference the correct built file (e.g. ../build/index.js) or a published CDN path that matches the new output layout.

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +19
"melonjs": "https://cdn.jsdelivr.net/npm/melonjs@15.12/+esm",
"debugPlugin" : "https://cdn.jsdelivr.net/npm/@melonjs/debug-plugin/dist/@melonjs/debug-plugin.js",
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test HTML files import the spine plugin from ./../dist/@melonjs/spine-plugin.js, but this package’s build output is now configured to emit into build/ (and dist/ is not present). Update the import map to reference the correct built file (e.g. ../build/index.js) or a published CDN path that matches the new output layout.

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +19
"melonjs": "https://cdn.jsdelivr.net/npm/melonjs@15.12/+esm",
"debugPlugin" : "https://cdn.jsdelivr.net/npm/@melonjs/debug-plugin/dist/@melonjs/debug-plugin.js",
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test HTML files import the spine plugin from ./../dist/@melonjs/spine-plugin.js, but this package’s build output is now configured to emit into build/ (and dist/ is not present). Update the import map to reference the correct built file (e.g. ../build/index.js) or a published CDN path that matches the new output layout.

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +19
"melonjs": "https://cdn.jsdelivr.net/npm/melonjs@15.12/+esm",
"debugPlugin" : "https://cdn.jsdelivr.net/npm/@melonjs/debug-plugin/dist/@melonjs/debug-plugin.js",
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test HTML files import the spine plugin from ./../dist/@melonjs/spine-plugin.js, but this package’s build output is now configured to emit into build/ (and dist/ is not present). Update the import map to reference the correct built file (e.g. ../build/index.js) or a published CDN path that matches the new output layout.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,101 @@
// a melonJS data manifest
// note : this is note a webpack manifest
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: "this is note a webpack manifest" should be "this is not a webpack manifest".

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +59
* @param {number} [settings.atlasFile] - the name of the atlasFile to be used to create this spine animation
* @param {number} [settings.jsonFile] - the name of the atlasFile to be used to create this spine animation
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSDoc types for settings.atlasFile and settings.jsonFile are listed as number, but they are used as filenames/keys (strings) throughout the implementation. Please correct the types in the docstring to avoid misleading IDE hints and generated docs.

Suggested change
* @param {number} [settings.atlasFile] - the name of the atlasFile to be used to create this spine animation
* @param {number} [settings.jsonFile] - the name of the atlasFile to be used to create this spine animation
* @param {string} [settings.atlasFile] - the name of the atlasFile to be used to create this spine animation
* @param {string} [settings.jsonFile] - the name of the atlasFile to be used to create this spine animation

Copilot uses AI. Check for mistakes.
"imports": {
"melonjs": "https://cdn.jsdelivr.net/npm/melonjs@15.12/+esm",
"debugPlugin" : "https://cdn.jsdelivr.net/npm/@melonjs/debug-plugin/dist/@melonjs/debug-plugin.js",
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test HTML files import the spine plugin from ./../dist/@melonjs/spine-plugin.js, but this package’s build output is now configured to emit into build/ (and dist/ is not present). Update the import map to reference the correct built file (e.g. ../build/index.js) or a published CDN path that matches the new output layout.

Suggested change
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
"spinePlugin" : "../build/index.js"

Copilot uses AI. Check for mistakes.
"imports": {
"melonjs": "https://cdn.jsdelivr.net/npm/melonjs@15.12/+esm",
"debugPlugin" : "https://cdn.jsdelivr.net/npm/@melonjs/debug-plugin/dist/@melonjs/debug-plugin.js",
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test HTML files import the spine plugin from ./../dist/@melonjs/spine-plugin.js, but this package’s build output is now configured to emit into build/ (and dist/ is not present). Update the import map to reference the correct built file (e.g. ../build/index.js) or a published CDN path that matches the new output layout.

Suggested change
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
"spinePlugin" : "../build/index.js"

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +19
"melonjs": "https://cdn.jsdelivr.net/npm/melonjs@15.12/+esm",
"debugPlugin" : "https://cdn.jsdelivr.net/npm/@melonjs/debug-plugin/dist/@melonjs/debug-plugin.js",
"spinePlugin" : "./../dist/@melonjs/spine-plugin.js"
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test HTML files import the spine plugin from ./../dist/@melonjs/spine-plugin.js, but this package’s build output is now configured to emit into build/ (and dist/ is not present). Update the import map to reference the correct built file (e.g. ../build/index.js) or a published CDN path that matches the new output layout.

Copilot uses AI. Check for mistakes.
// ensure plugin was properly registered
this.plugin = plugin.get(SpinePlugin);
if (typeof this.plugin === "undefined") {
throw "Spine plugin: plugin needs to be registered first using plugin.register";
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing a string makes stack traces and error handling harder (e.g., instanceof Error checks). Please throw an Error (or a project-standard error type) with this message instead.

Suggested change
throw "Spine plugin: plugin needs to be registered first using plugin.register";
throw new Error("Spine plugin: plugin needs to be registered first using plugin.register");

Copilot uses AI. Check for mistakes.
obiot and others added 2 commits March 29, 2026 15:43
- Support optional indexed drawing via settings.indexed with own VBO
  and dynamic IndexBuffer (addIndices, flush with drawElements)
- Support configurable maxVertices via settings.maxVertices (default 4096)
- Support configurable projection uniform name via settings.projectionUniform
  (default "uProjectionMatrix") for third-party shaders
- IndexBuffer: refactored to support both static quad patterns (fillQuadPattern)
  and dynamic stream drawing (add/upload/clear)
- VertexArrayBuffer: new pushFloats() for variable-length all-float vertex data
- QuadBatcher: updated to use refactored IndexBuffer API

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SpineBatcher:
- Custom melonJS Batcher using Spine's official two-color shader
- Indexed drawing via melonJS Batcher's new indexed mode
- Blend modes delegated to melonJS renderer.setBlendMode() with PMA
- No manual GL state management — integrates via setBatcher("spine")

Spine renderable:
- skeleton.update() for Spine 4.2+ physics support
- Physics gravity inversion for Y-down coordinate system
- Auto-detect mesh attachments for canvas triangleRendering optimization
- New API: setCombinedSkin, setEmptyAnimation, findBone, findSlot,
  addAnimationListener, getAnimationNames, getSkinNames
- Fixed rotate/scale/dispose, removed redundant methods

Canvas SkeletonRenderer:
- Extracted drawRegion/drawMesh/drawTriangle from monolithic draw()
- Degenerate triangle guard, UV edge bleeding fix
- triangleRendering auto-detection (fast path for region-only skeletons)

AssetManager:
- Cleaned up naming, added dispose(), fixed JSDoc

Examples:
- 17 official Spine characters with character selector dropdown
- Debug plugin visible by default

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 29, 2026 07:45
@obiot obiot force-pushed the chore/add-spine-plugin branch from 1eea087 to dd83678 Compare March 29, 2026 07:45
@obiot obiot changed the title Migrate spine-plugin into monorepo Migrate spine-plugin into monorepo with custom SpineBatcher Mar 29, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 56 out of 107 changed files in this pull request and generated 5 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +203 to +205
esbuild:
specifier: 0.27.4
version: 0.27.4
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this lockfile importer entry, the esbuild specifier is 0.27.4, but packages/spine-plugin/package.json declares esbuild as ^0.27.3. The lockfile should reflect the package.json specifier; please update the dependency specifier (or regenerate the lockfile) so they stay consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +51
"peerDependencies": {
"melonjs": ">=18.1.0"
},
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

peerDependencies.melonjs is set to >=18.1.0, but the README and CHANGELOG in this package state the minimum melonJS version is 18.2.0. This should be aligned so consumers get the correct install-time signal (and so SpinePlugin.version reports the correct minimum).

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +49
default:
throw new Error(
`Spine plugin: unknown extension "${ext}" when preloading spine assets`,
);
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The custom loader parser throws an Error for unknown extensions. loader.preload expects parsers to report failures via the provided onerror callback (see loader.setParser docs); throwing here bypasses the loader's failure bookkeeping and can break preload flow. Prefer calling onerror (and returning 0/1 as appropriate) instead of throwing.

Copilot uses AI. Check for mistakes.
Comment on lines +415 to +425
/**
* Disposes of all rendering-related resources to free GPU memory.
* Should be called when this Spine object is no longer needed.
*/
dispose() {
if (this.renderer.WebGLVersion >= 1) {
this.shapes.dispose();
this.shapesShader.dispose();
this.skeletonDebugRenderer.dispose();
}
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spine allocates WebGL resources (shapes, shapesShader, skeletonDebugRenderer) but dispose() is never called automatically when the renderable is removed from the world. Renderable.destroy() calls onDestroyEvent, not dispose(), so removing a Spine instance will leak GPU resources unless users remember to call dispose() manually. Consider moving the cleanup into onDestroyEvent() (or overriding destroy()) and keeping dispose() as an alias if you want a public API.

Copilot uses AI. Check for mistakes.
Comment on lines 9 to 13
* @param {WebGL2RenderingContext} gl - the WebGL context
* @param {number} maxQuads - maximum number of quads this buffer can index
* @param {number} maxIndices - maximum number of indices this buffer can hold
* @param {boolean} [useUint32=false] - use Uint32 indices (WebGL2) instead of Uint16 (WebGL1)
* @param {boolean} [dynamic=false] - if true, use STREAM_DRAW for frequent updates; if false, use STATIC_DRAW
*/
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IndexBuffer constructor JSDoc types gl as WebGL2RenderingContext, but this class is also instantiated with WebGL1 contexts (e.g. QuadBatcher). Updating the type to WebGLRenderingContext|WebGL2RenderingContext would keep the documentation accurate.

Copilot uses AI. Check for mistakes.
obiot and others added 2 commits March 29, 2026 15:50
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Align peerDependencies melonjs to >=18.2.0 (matches README/CHANGELOG)
- AssetManager: use onerror callback instead of throw for unknown extensions
- Spine: add onDestroyEvent() for automatic GPU resource cleanup on removal
- IndexBuffer: fix JSDoc gl type to include WebGLRenderingContext

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 29, 2026 07:58
@obiot obiot merged commit 2b03c75 into master Mar 29, 2026
10 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 56 out of 107 changed files in this pull request and generated 8 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +336 to +346
if (worldVertices.length < mesh.worldVerticesLength) {
worldVertices = new Float32Array(mesh.worldVerticesLength);
}
mesh.computeWorldVertices(
slot,
0,
mesh.worldVerticesLength,
worldVertices,
0,
vertexSize,
);
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worldVertices is grown to mesh.worldVerticesLength, but when calling mesh.computeWorldVertices(..., stride=vertexSize) the destination array needs capacity for vertexCount * vertexSize floats (not vertexCount * 2). With VERTEX_SIZE = 8, the current allocation can be too small and typed-array writes past the end will be dropped, producing corrupted meshes. Allocate based on (mesh.worldVerticesLength / 2) * vertexSize (or similar) and keep it in sync with the stride used.

Copilot uses AI. Check for mistakes.
Comment on lines +168 to +173
if (this.useIndexBuffer) {
const gl = this.gl;
this.glVertexBuffer = gl.createBuffer();
// max indices: worst case is 3 indices per vertex (all triangles, no sharing)
this.indexBuffer = new IndexBuffer(gl, maxVertices * 3, false, true);
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indexed batchers allocate the dynamic index buffer as maxVertices * 3 with a comment claiming this is the “worst case”. For triangle meshes, index count can legitimately exceed 3 * vertexCount (e.g. shared vertices across many triangles), and there’s no guard if a single indices array exceeds the buffer capacity, which can cause silent out-of-bounds drops in IndexBuffer.add(). Consider (1) making max indices configurable (e.g. settings.maxIndices), (2) using a more conservative default (often maxVertices * 6), and/or (3) adding an explicit capacity check that flushes and/or throws when a single submission can’t fit.

Copilot uses AI. Check for mistakes.
Comment on lines +70 to +75
add(indices, vertexOffset) {
for (let i = 0; i < indices.length; i++) {
this.data[this.length + i] = indices[i] + vertexOffset;
}
this.length += indices.length;
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IndexBuffer.add() appends without checking remaining capacity (this.length + indices.length vs this.data.length). When it overflows, typed-array writes past the end are silently ignored, leading to incorrect drawElements output with no obvious error. Add a bounds check and either flush/return false or throw a clear error so callers can recover safely.

Copilot uses AI. Check for mistakes.
Comment on lines +203 to +217
esbuild:
specifier: 0.27.4
version: 0.27.4
melonjs:
specifier: workspace:*
version: link:../melonjs
tsconfig:
specifier: workspace:*
version: link:../tsconfig
tsx:
specifier: ^4.21.0
version: 4.21.0
typescript:
specifier: ^5.9.3
version: 5.9.3
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lockfile records packages/spine-plugin devDependency esbuild with specifier 0.27.4, but packages/spine-plugin/package.json declares ^0.27.3. This indicates the lockfile is out of sync with the manifests (or vice versa) and will cause a diff on the next pnpm install. Please regenerate the lockfile or align the specifier in package.json.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +27
console.log(
`${name} ${version} - spine runtime ${dependencies["@esotericsoftware/spine-core"]} | ${homepage}`,
);
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plugin log format is inconsistent with the other melonJS plugins in this repo (e.g. debug-plugin uses ${name} ${version} | ${homepage}). Consider matching that convention (and optionally including the spine runtime version after, but keep the same separators) so logs are uniform across plugins.

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +92
constructor(x, y, settings) {
super(x, y, settings.width, settings.height);

// ensure plugin was properly registered
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spine calls super(x, y, settings.width, settings.height) but settings is optional in your own JSDoc examples (and in the monorepo example you don’t provide width/height). With settings undefined or missing width/height, Rect/Renderable will end up with invalid dimensions (or throw when accessing settings.width). Consider defaulting settings = {} and passing safe numeric dimensions (e.g. 0/0 or 1/1) until the skeleton is loaded, then let updateBounds() size it from skeleton.getBounds().

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +20
// create new spine renderable
const spineObj = new Spine(char.x, char.y, {
atlasFile: char.atlas,
jsonFile: char.json,
});
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example constructs new Spine(char.x, char.y, { atlasFile, jsonFile }) without width/height, but Spine currently forwards settings.width/height into Renderable/Rect. As written, this will produce invalid bounds (or crash) unless Spine defaults width/height internally.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +104
const clippedVertexSize = clipper.isClipping() ? 2 : VERTEX_SIZE;
const slot = drawOrder[i];
const bone = slot.bone;
let image;
let region;
let triangles;

if (!bone.active) {
clipper.clipEndWithSlot(slot);
renderer.clearMask();
continue;
}

const attachment = slot.getAttachment();

if (attachment instanceof RegionAttachment) {
region = attachment.region;
image = region.texture.getImage();
} else if (
this.triangleRendering &&
attachment instanceof MeshAttachment
) {
this.computeMeshVertices(slot, attachment, clippedVertexSize);
triangles = attachment.triangles;
region = attachment.region;
image = region.texture.getImage();
} else if (attachment instanceof ClippingAttachment) {
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clippedVertexSize becomes 2 while clipping is active, but mesh rendering still calls drawMesh() which indexes worldVertices assuming the full VERTEX_SIZE layout (e.g. t1 + 6 for UVs). If a mesh attachment is drawn while clipping is active, computeMeshVertices(..., 2) will generate an incompatible buffer layout. Meshes should always be computed with the full vertex stride (and clipping should be applied separately via masking/clipper).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants