spine-html 0.1.0 → 0.3.0

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/README.md CHANGED
@@ -1,4 +1,12 @@
1
- # spine-html
1
+ <p align="center">
2
+ <img src="assets/banner.svg" alt="spine-html - DOM-first Spine 2D runtime" width="100%" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/spine-html"><img src="https://img.shields.io/npm/v/spine-html.svg?style=flat-square&color=FF6B4A" alt="npm version" /></a>
7
+ <a href="https://www.npmjs.com/package/spine-html"><img src="https://img.shields.io/npm/dm/spine-html.svg?style=flat-square&color=EC4899" alt="npm downloads" /></a>
8
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-38BDF8.svg?style=flat-square" alt="license" /></a>
9
+ </p>
2
10
 
3
11
  Render [Spine](https://esotericsoftware.com/) skeletal animations as **plain DOM** — one
4
12
  absolutely-positioned `<img>` per slot, posed with a single CSS `matrix()` write per frame.
@@ -17,16 +25,43 @@ The idea has been floated on the official forum three times since 2014 and was n
17
25
  built — the blockers named were meshes, clipping, and DOM update overhead. This project
18
26
  is the experiment: how far does the DOM actually go, and how cheap is it?
19
27
 
20
- Measured so far (PoC, Chromium on Apple silicon):
21
-
22
- - Rigid only (spineboy-ess): 10 skeletons / 180 slot images at **~0.03 ms skeleton math
23
- + ~0.22 ms DOM writes per frame** about 1.5% of a 60 fps frame budget.
24
- - With meshes (spineboy-pro): 1 skeleton = **~0.05 ms + ~0.5 ms render** (8 mesh
25
- canvases, 323 triangles); 10 running skeletons = **~4.4 ms/frame** total.
28
+ Measured so far (PoC, Apple silicon — headless and on-device numbers are labeled,
29
+ they do **not** substitute for each other):
30
+
31
+ - Rigid only (spineboy-ess), headless Chromium: 10 skeletons / 180 slot images at
32
+ **~0.03 ms skeleton math + ~0.22 ms DOM writes per frame** about 1.5% of a
33
+ 60 fps frame budget. On-device Safari: 10 rigid skeletons hold **60 fps**.
34
+ - With meshes (spineboy-pro), headless Chromium: 1 skeleton = **~0.05 ms + ~0.5 ms
35
+ render** (8 mesh canvases, 323 triangles); 10 running skeletons = **~3.5 ms/frame**
36
+ total, smooth.
37
+ - Dirty-skip: 10 *static* skeletons (pose held) = **~0.4 ms/frame** headless and
38
+ **~0.6 ms** on-device Safari — unchanged meshes reuse their raster, so idle or
39
+ held parts cost nothing anywhere.
40
+ - Real Safari (on-device), canvas2d mesh backend: in-callback JS stays **~4–5
41
+ ms/frame** for 10 running meshed skeletons — but the rAF rate tells the real
42
+ story: **meshed ×1 = 37 fps, meshed ×10 = 3–4 fps** (rigid-only ×10 = 60 fps).
43
+ The cost lives outside the frame callback, in the compositor/GPU process:
44
+ Safari antialiases canvas2d **clip paths**, so every triangle pays for an AA
45
+ mask. Chromium doesn't antialias clips and stays smooth. This is what the
46
+ optional WebGL mesh backend (below) removes.
47
+ - Real Safari (on-device), **webgl mesh backend**: meshed ×1 holds **60 fps**
48
+ (vs 37 on canvas2d), and the meshed ×10 stress scene jumps **3–4 → 45 fps** —
49
+ 80 mesh canvases / 3230 triangles redrawn every frame (0 reused, the worst
50
+ case), in-callback JS ~5.8 ms at dpr=1. The per-triangle clip-AA tax is gone;
51
+ the remaining gap to 60 is the blit/compositing cost of a 10-skeleton stress
52
+ scene, not a per-triangle cost.
53
+ - Headless-WebKit numbers are a **software rasterizer** and measured up to 28×
54
+ off real Safari in both directions — useful for visual regression only, never
55
+ as Safari perf evidence.
26
56
 
27
57
  ## Status
28
58
 
29
- **Proof of concept.**
59
+ **Production.** The questions this started as a PoC to answer — how far does the
60
+ DOM actually go, and how cheap is it — are answered with on-device numbers: the
61
+ practical scenario (a character or two, mostly holding pose, a few parts
62
+ deforming) holds **60 fps on every engine measured**, and the 10-skeleton
63
+ stress scene holds 45 fps on the weakest one (Safari, webgl backend). Ships
64
+ with a self-contained test suite (backend visual parity + invariants) and CI.
30
65
 
31
66
  - ✅ Region attachments (rigid parts): exact affine mapping, draw-order via `z-index`,
32
67
  attachment swaps, alpha
@@ -40,12 +75,37 @@ Measured so far (PoC, Chromium on Apple silicon):
40
75
  clip polygon is expanded 0.5px from its centroid so neighbours overlap — the
41
76
  texture is continuous across shared edges, so the overlap is invisible
42
77
  (`?expand=0` shows the cracks for comparison)
78
+ - ✅ RGB tinting (skeleton × slot × attachment color) via an SVG `feColorMatrix`
79
+ reference filter per element — an exact channel multiply that works identically on
80
+ `<img>` and `<canvas>` without touching the raster (needs reference-filter support,
81
+ Safari 15+; verified pixel-level on Chromium and WebKit). Dark/two-color tint is
82
+ not expressible this way and stays out of scope
83
+ - ✅ DPR-aware mesh canvas backing store: `renderer.pixelRatio` (defaults to
84
+ `devicePixelRatio`; if you scale the root element, fold that scale in)
85
+ - ✅ Dirty-skip: a mesh whose canvas-space vertices didn't change reuses last frame's
86
+ raster — the CSS translate still tracks it, so parts that hold a pose (or move by
87
+ whole pixels) pay zero raster. 10 frozen spineboys: WebKit ~141 → ~0.5 ms/frame
43
88
  - ⬜ Clipping — deliberately unsupported (counted and skipped); layered transparent
44
89
  parts + `overflow: hidden` cover the practical cases
45
- - RGB tinting (alpha works); DPR-aware mesh canvas backing store
46
- - WebKit mesh-canvas cost: Safari rasterizes the per-triangle path noticeably
47
- slower than Chromium (measured ~7.6ms vs ~0.5ms per frame headless) dirty-check
48
- skipping and/or an optional WebGL blit backend are the candidates
90
+ - Safari mesh cost root-caused by on-device triangulation (two corrections deep):
91
+ the early "~15× slower per-triangle path" was a **headless-WebKit artifact**
92
+ (software rasterization), and the follow-up "on par with Chromium" held only for
93
+ in-callback JS time. Real-Safari rAF rates rigid ×10 = 60 fps, meshed ×1 =
94
+ 37 fps, meshed ×10 = 3–4 fps with JS flat at ~4–5 ms — put the real cost in the
95
+ GPU process: Safari antialiases canvas2d **clip paths**, so the per-triangle clip
96
+ mapping pays a per-triangle AA-mask tax (the same AA that caused the seam cracks)
97
+ - ✅ Optional WebGL blit backend for the mesh tier: `renderer.meshBackend =
98
+ 'webgl'` (default stays `'canvas2d'`). All dirty meshes are shelf-packed into
99
+ **one shared offscreen WebGL context** (module-level — browsers cap contexts at
100
+ ~16), drawn as textured triangles with premultiplied alpha, then rect-blitted
101
+ onto the same per-part canvases with an unclipped `drawImage` — cheap on Safari.
102
+ Everything element-level is unchanged: z-index interleave, tint filter,
103
+ `mix-blend-mode`, dirty-skip, grow-only backing. GL rasterizes shared triangle
104
+ edges seamlessly, so this path needs no crack overdraw. Falls back to canvas2d
105
+ when WebGL is unavailable or the context is lost. Backend parity verified by
106
+ headless Chromium+WebKit screenshot diffs (glow / clipping / tint scenes;
107
+ sub-pixel edge differences only). On-device Safari, meshed ×10 with every mesh
108
+ redrawn per frame: **3–4 fps (canvas2d) → 45 fps (webgl)**
49
109
 
50
110
  ## Install
51
111
 
@@ -75,6 +135,13 @@ const skeleton = new Skeleton(data);
75
135
  const state = new AnimationState(new AnimationStateData(data));
76
136
  state.setAnimation(0, 'walk', true);
77
137
  const renderer = new SpineHtmlRenderer(rootElement, regionImages);
138
+ // Mesh canvases raster at devicePixelRatio by default; if you scale the
139
+ // root element, fold that scale in so the raster matches the screen:
140
+ // renderer.pixelRatio = devicePixelRatio * rootScale;
141
+ // Mesh rasterizer: 'canvas2d' (default) or 'webgl' — same output, but on
142
+ // Safari heavy deforming scenes should use 'webgl' (see Measured above).
143
+ // Falls back to canvas2d automatically when WebGL is unavailable.
144
+ // renderer.meshBackend = 'webgl';
78
145
 
79
146
  function frame(delta: number) {
80
147
  state.update(delta);
@@ -99,6 +166,37 @@ The official spineboy example assets are downloaded automatically on first `dev`
99
166
  (they are owned by Esoteric Software and not redistributed in this repository — see
100
167
  [NOTICE.md](NOTICE.md)); `bun run fetch-assets` runs the same idempotent step manually.
101
168
 
169
+ Debug knobs (query string): `?skel=pro|ess` `?anim=walk` `?count=10` pick the scene,
170
+ `?tint=ff8080` tints the whole skeleton, `?dpr=2` overrides the mesh-canvas backing
171
+ ratio, `?timescale=0` freezes the pose (every mesh should report "reused"),
172
+ `?expand=0` disables the crack-closing clip overdraw, `?backend=webgl` rasterizes
173
+ meshes through the shared WebGL blitter (also a live header select; the stats line
174
+ names the active backend), and `?time=1.2` seeks every instance to the same pose
175
+ for deterministic captures.
176
+
177
+ ## Tests
178
+
179
+ ```bash
180
+ bun run test # builds + serves the demo, then runs chromium + webkit
181
+ ```
182
+
183
+ Playwright drives the demo (`tests/`, config in `playwright.config.ts`; CI
184
+ runs the same suite on ubuntu). The visual check is **A/B within one run**:
185
+ no golden snapshots are committed (they rot across platforms/GPUs) — instead
186
+ the same deterministic pose (`?time` + `?timescale=0`) is screenshotted with
187
+ `?backend=canvas2d` and `?backend=webgl` in the same engine and the buffers
188
+ are diffed directly with a shift-tolerant comparison, so missing parts,
189
+ wrong colors, and tint/blend divergence fail regardless of platform.
190
+ Hairline seams are guarded by a deterministic canary (`?expand=0` must
191
+ change the canvas2d raster), and counter tests pin the dirty-skip /
192
+ grow-only-backing / clip-skip invariants plus spine-core's region corner
193
+ order (BL, UL, UR, BR).
194
+
195
+ Standing rule: **headless numbers are never Safari performance evidence** —
196
+ nothing in the suite asserts timing, and headless-WebKit fps/ms readings do
197
+ not transfer (software rasterizer, measured up to 28× off real Safari). The
198
+ perf oracle is the demo's stats line on a real device.
199
+
102
200
  ## How it works
103
201
 
104
202
  1. `@esotericsoftware/spine-core` loads the skeleton and drives `AnimationState`,
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Shared offscreen WebGL rasterizer for the mesh (deform) tier.
3
+ *
4
+ * One module-level context serves every renderer instance: browsers cap live
5
+ * WebGL contexts (16 on Chrome/Safari) and a page can hold many renderers, so
6
+ * per-renderer contexts would evict each other. Per flush, every dirty mesh is
7
+ * shelf-packed into a rect of the offscreen canvas, its triangles are drawn
8
+ * textured (atlas page texture, premultiplied alpha), and each rect is blitted
9
+ * onto the mesh's per-part 2d canvas with an unclipped drawImage rect copy.
10
+ *
11
+ * Why this exists: Safari antialiases canvas2d clip paths, so the standard
12
+ * per-triangle clip+transform+drawImage mapping pays a per-triangle AA-mask
13
+ * cost in the GPU process — invisible to in-callback JS timing, but it
14
+ * rAF-limits heavy scenes. GL rasterizes shared triangle edges seamlessly
15
+ * (no clip, no crack overdraw needed), and the remaining canvas2d work is a
16
+ * plain rect blit.
17
+ *
18
+ * The offscreen buffer is scratch space: rects are scissor-cleared and
19
+ * redrawn every flush and read back in the same task, so neither
20
+ * preserveDrawingBuffer nor cross-frame content is relied on. The buffer
21
+ * grows quantized and never shrinks, mirroring the per-part backing policy
22
+ * (reallocating GPU surfaces per frame is a Safari killer).
23
+ */
24
+ export interface MeshBlitJob {
25
+ /** Destination per-part canvas; the blit clears its full backing first. */
26
+ canvas: HTMLCanvasElement;
27
+ /** Atlas page image the mesh samples (cached as a GL texture on first use). */
28
+ page: HTMLImageElement;
29
+ /** Bbox-relative vertices in CSS px, x/y interleaved (indexed via `triangles`). */
30
+ vertices: Float64Array;
31
+ /** Normalized page UVs aligned with `vertices`. */
32
+ uvs: ArrayLike<number>;
33
+ /** Triangle index list into vertex/UV pairs. */
34
+ triangles: ArrayLike<number>;
35
+ /** Backing-store pixels per CSS px. */
36
+ ratio: number;
37
+ /** Rasterized region in device px — the packed rect and the blit both use it. */
38
+ width: number;
39
+ height: number;
40
+ }
41
+ declare class MeshGlBlitter {
42
+ lost: boolean;
43
+ private readonly canvas;
44
+ private readonly gl;
45
+ private readonly uResolution;
46
+ private readonly textures;
47
+ private readonly maxSize;
48
+ private vertexData;
49
+ /** Per-job packed rect origins, filled by flush(). */
50
+ private packX;
51
+ private packY;
52
+ constructor();
53
+ /**
54
+ * Rasterize every job into the offscreen buffer, then blit each rect onto
55
+ * its per-part canvas. Returns false when the context is lost (or the jobs
56
+ * cannot fit) so the caller can rasterize the batch on the canvas2d path.
57
+ */
58
+ flush(jobs: MeshBlitJob[]): boolean;
59
+ private compile;
60
+ private textureFor;
61
+ }
62
+ /**
63
+ * The module-level blitter, created on first use. Returns null when WebGL is
64
+ * unavailable or the shared context has been lost — callers then stay on the
65
+ * canvas2d path.
66
+ */
67
+ export declare function getMeshGlBlitter(): MeshGlBlitter | null;
68
+ export {};
69
+ //# sourceMappingURL=MeshGlBlitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MeshGlBlitter.d.ts","sourceRoot":"","sources":["../src/MeshGlBlitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,MAAM,EAAE,iBAAiB,CAAC;IAC1B,+EAA+E;IAC/E,IAAI,EAAE,gBAAgB,CAAC;IACvB,mFAAmF;IACnF,QAAQ,EAAE,YAAY,CAAC;IACvB,mDAAmD;IACnD,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IACvB,gDAAgD;IAChD,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7B,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AA4BD,cAAM,aAAa;IACjB,IAAI,UAAS;IAEb,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAwB;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuB;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6C;IACtE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,UAAU,CAA0B;IAC5C,sDAAsD;IACtD,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,KAAK,CAAgB;;IAoD7B;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,OAAO;IAwGnC,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,UAAU;CAmBnB;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,IAAI,CASvD"}
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Shared offscreen WebGL rasterizer for the mesh (deform) tier.
3
+ *
4
+ * One module-level context serves every renderer instance: browsers cap live
5
+ * WebGL contexts (16 on Chrome/Safari) and a page can hold many renderers, so
6
+ * per-renderer contexts would evict each other. Per flush, every dirty mesh is
7
+ * shelf-packed into a rect of the offscreen canvas, its triangles are drawn
8
+ * textured (atlas page texture, premultiplied alpha), and each rect is blitted
9
+ * onto the mesh's per-part 2d canvas with an unclipped drawImage rect copy.
10
+ *
11
+ * Why this exists: Safari antialiases canvas2d clip paths, so the standard
12
+ * per-triangle clip+transform+drawImage mapping pays a per-triangle AA-mask
13
+ * cost in the GPU process — invisible to in-callback JS timing, but it
14
+ * rAF-limits heavy scenes. GL rasterizes shared triangle edges seamlessly
15
+ * (no clip, no crack overdraw needed), and the remaining canvas2d work is a
16
+ * plain rect blit.
17
+ *
18
+ * The offscreen buffer is scratch space: rects are scissor-cleared and
19
+ * redrawn every flush and read back in the same task, so neither
20
+ * preserveDrawingBuffer nor cross-frame content is relied on. The buffer
21
+ * grows quantized and never shrinks, mirroring the per-part backing policy
22
+ * (reallocating GPU surfaces per frame is a Safari killer).
23
+ */
24
+ const VERTEX_SHADER = `
25
+ attribute vec2 aPos;
26
+ attribute vec2 aUV;
27
+ uniform vec2 uResolution;
28
+ varying vec2 vUV;
29
+ void main() {
30
+ // aPos is in offscreen-canvas device px, top-left origin (matching the
31
+ // top-left-origin drawImage read of the same rect).
32
+ vec2 clip = aPos / uResolution * 2.0 - 1.0;
33
+ gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);
34
+ vUV = aUV;
35
+ }`;
36
+ const FRAGMENT_SHADER = `
37
+ precision mediump float;
38
+ uniform sampler2D uTex;
39
+ varying vec2 vUV;
40
+ void main() {
41
+ gl_FragColor = texture2D(uTex, vUV);
42
+ }`;
43
+ /** Gap between packed rects; blits are 1:1 unfiltered, so 1px is plenty. */
44
+ const GUTTER = 1;
45
+ /** Drawing-buffer growth quantum (device px). */
46
+ const GROW_STEP = 256;
47
+ class MeshGlBlitter {
48
+ lost = false;
49
+ canvas = document.createElement('canvas');
50
+ gl;
51
+ uResolution;
52
+ textures = new Map();
53
+ maxSize;
54
+ vertexData = new Float32Array(8192);
55
+ /** Per-job packed rect origins, filled by flush(). */
56
+ packX = [];
57
+ packY = [];
58
+ constructor() {
59
+ const gl = this.canvas.getContext('webgl', {
60
+ alpha: true,
61
+ premultipliedAlpha: true,
62
+ antialias: false,
63
+ depth: false,
64
+ stencil: false,
65
+ preserveDrawingBuffer: false,
66
+ });
67
+ if (!gl)
68
+ throw new Error('WebGL unavailable');
69
+ this.gl = gl;
70
+ // No restore attempt: on loss the renderer falls back to canvas2d and the
71
+ // backend signature re-dirties every mesh, so frames stay complete.
72
+ this.canvas.addEventListener('webglcontextlost', () => {
73
+ this.lost = true;
74
+ });
75
+ const program = gl.createProgram();
76
+ if (!program)
77
+ throw new Error('createProgram failed');
78
+ gl.attachShader(program, this.compile(gl.VERTEX_SHADER, VERTEX_SHADER));
79
+ gl.attachShader(program, this.compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER));
80
+ gl.linkProgram(program);
81
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
82
+ throw new Error(`program link failed: ${gl.getProgramInfoLog(program)}`);
83
+ }
84
+ gl.useProgram(program);
85
+ const uResolution = gl.getUniformLocation(program, 'uResolution');
86
+ if (!uResolution)
87
+ throw new Error('uResolution not found');
88
+ this.uResolution = uResolution;
89
+ gl.uniform1i(gl.getUniformLocation(program, 'uTex'), 0);
90
+ // Static state: this context does exactly one thing, set it up once.
91
+ // Interleaved [x, y, u, v] vertices in a single dynamic buffer.
92
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
93
+ const aPos = gl.getAttribLocation(program, 'aPos');
94
+ const aUV = gl.getAttribLocation(program, 'aUV');
95
+ gl.enableVertexAttribArray(aPos);
96
+ gl.enableVertexAttribArray(aUV);
97
+ gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
98
+ gl.vertexAttribPointer(aUV, 2, gl.FLOAT, false, 16, 8);
99
+ // Premultiplied source-over, matching canvas2d triangle compositing.
100
+ gl.enable(gl.BLEND);
101
+ gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
102
+ gl.enable(gl.SCISSOR_TEST);
103
+ gl.clearColor(0, 0, 0, 0);
104
+ gl.activeTexture(gl.TEXTURE0);
105
+ this.maxSize = Math.min(gl.getParameter(gl.MAX_RENDERBUFFER_SIZE) || 4096, 8192);
106
+ }
107
+ /**
108
+ * Rasterize every job into the offscreen buffer, then blit each rect onto
109
+ * its per-part canvas. Returns false when the context is lost (or the jobs
110
+ * cannot fit) so the caller can rasterize the batch on the canvas2d path.
111
+ */
112
+ flush(jobs) {
113
+ const gl = this.gl;
114
+ if (this.lost || gl.isContextLost())
115
+ return false;
116
+ // Shelf-pack, tallest first (indices keep job order for the draw pass).
117
+ let width = Math.max(512, this.canvas.width);
118
+ for (const job of jobs)
119
+ width = Math.max(width, job.width + GUTTER * 2);
120
+ if (width > this.maxSize)
121
+ return false;
122
+ const order = jobs.map((_, i) => i).sort((a, b) => jobs[b].height - jobs[a].height);
123
+ const packX = (this.packX = new Array(jobs.length));
124
+ const packY = (this.packY = new Array(jobs.length));
125
+ let shelfX = GUTTER;
126
+ let shelfY = GUTTER;
127
+ let shelfH = 0;
128
+ let height = GUTTER;
129
+ for (const i of order) {
130
+ const job = jobs[i];
131
+ if (shelfX + job.width + GUTTER > width) {
132
+ shelfY += shelfH + GUTTER;
133
+ shelfX = GUTTER;
134
+ shelfH = 0;
135
+ }
136
+ packX[i] = shelfX;
137
+ packY[i] = shelfY;
138
+ shelfX += job.width + GUTTER;
139
+ if (job.height > shelfH)
140
+ shelfH = job.height;
141
+ if (shelfY + job.height + GUTTER > height)
142
+ height = shelfY + job.height + GUTTER;
143
+ }
144
+ if (height > this.maxSize)
145
+ return false;
146
+ // Grow-only quantized drawing buffer. Resizing clears it, which is fine:
147
+ // every rect below is cleared and redrawn anyway.
148
+ if (width > this.canvas.width || height > this.canvas.height) {
149
+ this.canvas.width = Math.min(this.maxSize, Math.ceil(width / GROW_STEP) * GROW_STEP);
150
+ this.canvas.height = Math.min(this.maxSize, Math.ceil(Math.max(height, this.canvas.height) / GROW_STEP) * GROW_STEP);
151
+ }
152
+ const bufW = this.canvas.width;
153
+ const bufH = this.canvas.height;
154
+ gl.viewport(0, 0, bufW, bufH);
155
+ gl.uniform2f(this.uResolution, bufW, bufH);
156
+ // Build one interleaved vertex array for the whole batch (unindexed —
157
+ // meshes are a few hundred triangles, expansion is cheaper than managing
158
+ // index buffers).
159
+ let floats = 0;
160
+ for (const job of jobs)
161
+ floats += job.triangles.length * 4;
162
+ if (this.vertexData.length < floats) {
163
+ this.vertexData = new Float32Array(1 << Math.ceil(Math.log2(floats)));
164
+ }
165
+ const data = this.vertexData;
166
+ let f = 0;
167
+ for (let i = 0; i < jobs.length; i++) {
168
+ const { vertices, uvs, triangles, ratio } = jobs[i];
169
+ const ox = packX[i];
170
+ const oy = packY[i];
171
+ for (let t = 0; t < triangles.length; t++) {
172
+ const vi = triangles[t] * 2;
173
+ data[f++] = ox + vertices[vi] * ratio;
174
+ data[f++] = oy + vertices[vi + 1] * ratio;
175
+ data[f++] = uvs[vi];
176
+ data[f++] = uvs[vi + 1];
177
+ }
178
+ }
179
+ gl.bufferData(gl.ARRAY_BUFFER, data.subarray(0, floats), gl.DYNAMIC_DRAW);
180
+ let boundPage = null;
181
+ let first = 0;
182
+ for (let i = 0; i < jobs.length; i++) {
183
+ const job = jobs[i];
184
+ if (job.page !== boundPage) {
185
+ gl.bindTexture(gl.TEXTURE_2D, this.textureFor(job.page));
186
+ boundPage = job.page;
187
+ }
188
+ // Scissor is bottom-left origin; pack coords are top-left origin.
189
+ gl.scissor(packX[i], bufH - packY[i] - job.height, job.width, job.height);
190
+ gl.clear(gl.COLOR_BUFFER_BIT);
191
+ gl.drawArrays(gl.TRIANGLES, first, job.triangles.length);
192
+ first += job.triangles.length;
193
+ }
194
+ // If the context died mid-batch the draws above were no-ops; report it
195
+ // before blitting stale/blank rects onto the part canvases.
196
+ if (gl.isContextLost()) {
197
+ this.lost = true;
198
+ return false;
199
+ }
200
+ // Blit each rect onto its per-part canvas: same-task read (no
201
+ // preserveDrawingBuffer needed), 1:1 device px (no filtering).
202
+ for (let i = 0; i < jobs.length; i++) {
203
+ const job = jobs[i];
204
+ const ctx = job.canvas.getContext('2d');
205
+ if (!ctx)
206
+ continue;
207
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
208
+ // Clear the full backing: the previous raster may have been larger.
209
+ ctx.clearRect(0, 0, job.canvas.width, job.canvas.height);
210
+ ctx.drawImage(this.canvas, packX[i], packY[i], job.width, job.height, 0, 0, job.width, job.height);
211
+ }
212
+ return true;
213
+ }
214
+ compile(type, source) {
215
+ const gl = this.gl;
216
+ const shader = gl.createShader(type);
217
+ if (!shader)
218
+ throw new Error('createShader failed');
219
+ gl.shaderSource(shader, source);
220
+ gl.compileShader(shader);
221
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
222
+ throw new Error(`shader compile failed: ${gl.getShaderInfoLog(shader)}`);
223
+ }
224
+ return shader;
225
+ }
226
+ textureFor(page) {
227
+ let texture = this.textures.get(page);
228
+ if (texture)
229
+ return texture;
230
+ const gl = this.gl;
231
+ texture = gl.createTexture();
232
+ if (!texture)
233
+ throw new Error('createTexture failed');
234
+ gl.bindTexture(gl.TEXTURE_2D, texture);
235
+ // Premultiply at upload so blending and the premultiplied canvas agree.
236
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
237
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
238
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, page);
239
+ // Linear, no mips, clamped — NPOT-safe in WebGL1.
240
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
241
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
242
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
243
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
244
+ this.textures.set(page, texture);
245
+ return texture;
246
+ }
247
+ }
248
+ let shared;
249
+ /**
250
+ * The module-level blitter, created on first use. Returns null when WebGL is
251
+ * unavailable or the shared context has been lost — callers then stay on the
252
+ * canvas2d path.
253
+ */
254
+ export function getMeshGlBlitter() {
255
+ if (shared === undefined) {
256
+ try {
257
+ shared = new MeshGlBlitter();
258
+ }
259
+ catch {
260
+ shared = null;
261
+ }
262
+ }
263
+ return shared && !shared.lost ? shared : null;
264
+ }
265
+ //# sourceMappingURL=MeshGlBlitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MeshGlBlitter.js","sourceRoot":"","sources":["../src/MeshGlBlitter.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  import { type Skeleton } from '@esotericsoftware/spine-core';
2
2
  import type { RegionImage } from './DomTexture';
3
+ /** Rasterizer used for the mesh (deform) tier. */
4
+ export type MeshBackend = 'canvas2d' | 'webgl';
3
5
  /**
4
6
  * Renders a spine-core Skeleton as DOM, split by slot type:
5
7
  *
@@ -7,13 +9,20 @@ import type { RegionImage } from './DomTexture';
7
9
  * posed with a single CSS matrix() write per frame — exact, since bone
8
10
  * transforms are affine.
9
11
  * - Mesh attachments (deform parts) each get a small per-part <canvas> sized
10
- * to the mesh's world bounding box, redrawn per frame with the standard
11
- * per-triangle clip+transform+drawImage mapping.
12
+ * to the mesh's world bounding box, redrawn per frame — either with the
13
+ * standard per-triangle clip+transform+drawImage mapping (default), or via
14
+ * a shared offscreen WebGL canvas that rect-blits into the same per-part
15
+ * canvases (meshBackend = 'webgl'). Frames where the canvas-space vertices
16
+ * are unchanged reuse the previous raster on both backends.
12
17
  *
13
18
  * Both element kinds share one stacking context, so draw order interleaves
14
19
  * freely via z-index (rear hair canvas < torso img < front hair canvas).
15
- * Clipping attachments are deliberately unsupported (transparent layered
16
- * parts make them unnecessary); they are counted in clipSkipCount.
20
+ * RGB tint (skeleton × slot × attachment color) is applied per element with
21
+ * an SVG feColorMatrix reference filter exact channel multiply, works the
22
+ * same on <img> and <canvas>. Dark (two-color) tint is not expressible that
23
+ * way and is unsupported. Clipping attachments are deliberately unsupported
24
+ * (transparent layered parts make them unnecessary); they are counted in
25
+ * clipSkipCount.
17
26
  *
18
27
  * Coordinate mapping: Spine is Y-up, CSS is Y-down — world Y is negated.
19
28
  * spine-core computes everything (bones, constraints, physics, deformed
@@ -24,8 +33,16 @@ export declare class SpineHtmlRenderer {
24
33
  private readonly regionImages;
25
34
  /** Clipping attachments encountered (visible but unsupported). */
26
35
  clipSkipCount: number;
27
- /** Mesh canvases drawn last frame. */
36
+ /** Mesh canvases rasterized last frame. */
28
37
  meshCount: number;
38
+ /** Mesh canvases that reused their previous raster last frame. */
39
+ meshReuseCount: number;
40
+ /**
41
+ * Mesh canvas backing stores (re)allocated last frame. Should drop to zero
42
+ * once an animation reaches its steady state; a persistent nonzero value
43
+ * means GPU surfaces are being recreated per frame (a Safari killer).
44
+ */
45
+ canvasReallocCount: number;
29
46
  /** Triangles rasterized last frame. */
30
47
  triangleCount: number;
31
48
  /**
@@ -34,8 +51,35 @@ export declare class SpineHtmlRenderer {
34
51
  * set to 0 to see them.
35
52
  */
36
53
  triangleExpand: number;
54
+ /**
55
+ * Mesh-canvas backing-store pixels per CSS pixel. Defaults to the device
56
+ * pixel ratio. If the caller scales the root element, fold that scale in
57
+ * (e.g. devicePixelRatio * rootScale) so the raster matches the on-screen
58
+ * resolution instead of over- or under-sampling.
59
+ */
60
+ pixelRatio: number;
61
+ /**
62
+ * Rasterizer for the mesh (deform) tier. 'canvas2d' (default) maps each
63
+ * triangle with clip+transform+drawImage directly on the per-part canvas.
64
+ * 'webgl' rasterizes every dirty mesh into one shared offscreen WebGL
65
+ * canvas and rect-blits each mesh back onto its per-part canvas — the DOM
66
+ * structure and all element-level behavior (z-index interleave, tint
67
+ * filter, mix-blend-mode, dirty-skip) are identical, only the raster step
68
+ * changes. Motivation: Safari antialiases canvas2d clip paths, so the
69
+ * per-triangle clip mapping pays a per-triangle AA-mask cost in the GPU
70
+ * process that rAF-limits heavy scenes; GL rasterizes shared edges
71
+ * seamlessly (no clip, no crack overdraw) and the blit is an unclipped
72
+ * rect copy. Falls back to 'canvas2d' when WebGL is unavailable or the
73
+ * shared context is lost — see meshBackendActive.
74
+ */
75
+ meshBackend: MeshBackend;
76
+ /** Backend that actually rasterized the mesh tier during the last render(). */
77
+ meshBackendActive: MeshBackend;
37
78
  private readonly views;
38
- private meshVertices;
79
+ private readonly pendingJobs;
80
+ private readonly pendingViews;
81
+ private scratchVertices;
82
+ private tintDefs;
39
83
  /**
40
84
  * @param root Positioned element (e.g. position:absolute) that becomes the
41
85
  * skeleton origin. The renderer only appends slot elements to it — layout
@@ -47,6 +91,8 @@ export declare class SpineHtmlRenderer {
47
91
  dispose(): void;
48
92
  private renderRegion;
49
93
  private renderMesh;
94
+ /** The canvas2d raster path: clear the backing, map each triangle. */
95
+ private rasterizeMesh2d;
50
96
  /**
51
97
  * Standard canvas triangle texture mapping (same math as the official
52
98
  * spine-canvas renderer): derive the affine that sends the triangle's
@@ -60,7 +106,9 @@ export declare class SpineHtmlRenderer {
60
106
  * with no visible cost. The texture-mapping affine itself stays exact.
61
107
  */
62
108
  private drawTriangle;
109
+ private setTransform;
63
110
  private applyCommon;
111
+ private tintMatrixFor;
64
112
  private view;
65
113
  private hide;
66
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SpineHtmlRenderer.d.ts","sourceRoot":"","sources":["../src/SpineHtmlRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,QAAQ,EAId,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAqChD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,iBAAiB;IAwB1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAxB/B,kEAAkE;IAClE,aAAa,SAAK;IAClB,sCAAsC;IACtC,SAAS,SAAK;IACd,uCAAuC;IACvC,aAAa,SAAK;IAClB;;;;OAIG;IACH,cAAc,SAAO;IAErB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,YAAY,CAAyB;IAE7C;;;;;OAKG;gBAEgB,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC;IAGzD,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IA2BhC,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,YAAY;IA8CpB,OAAO,CAAC,UAAU;IAiFlB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,YAAY;IAwCpB,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,IAAI;IAiCZ,OAAO,CAAC,IAAI;CAOb"}
1
+ {"version":3,"file":"SpineHtmlRenderer.d.ts","sourceRoot":"","sources":["../src/SpineHtmlRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,QAAQ,EAId,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC;AAiE/C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,iBAAiB;IA2D1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,YAAY;IA3D/B,kEAAkE;IAClE,aAAa,SAAK;IAClB,2CAA2C;IAC3C,SAAS,SAAK;IACd,kEAAkE;IAClE,cAAc,SAAK;IACnB;;;;OAIG;IACH,kBAAkB,SAAK;IACvB,uCAAuC;IACvC,aAAa,SAAK;IAClB;;;;OAIG;IACH,cAAc,SAAO;IACrB;;;;;OAKG;IACH,UAAU,SAA+D;IACzE;;;;;;;;;;;;;OAaG;IACH,WAAW,EAAE,WAAW,CAAc;IACtC,+EAA+E;IAC/E,iBAAiB,EAAE,WAAW,CAAc;IAE5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkB;IAC/C,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAA8B;IAE9C;;;;;OAKG;gBAEgB,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC;IAGzD,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IA4ChC,OAAO,IAAI,IAAI;IASf,OAAO,CAAC,YAAY;IA8CpB,OAAO,CAAC,UAAU;IAsIlB,sEAAsE;IACtE,OAAO,CAAC,eAAe;IA+BvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,YAAY;IAwCpB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,WAAW;IAmDnB,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,IAAI;IA+CZ,OAAO,CAAC,IAAI;CAOb"}
@@ -1,5 +1,9 @@
1
1
  import { BlendMode, ClippingAttachment, MeshAttachment, RegionAttachment, } from '@esotericsoftware/spine-core';
2
+ import { getMeshGlBlitter } from './MeshGlBlitter';
2
3
  const regionVertices = new Float32Array(8);
4
+ const SVG_NS = 'http://www.w3.org/2000/svg';
5
+ /** Unique tint-filter ids across renderer instances (ids are document-global). */
6
+ let tintFilterSeq = 0;
3
7
  /** Push a point away from (cx, cy) by `amount` pixels. */
4
8
  function expandPoint(x, y, cx, cy, amount) {
5
9
  const dx = x - cx;
@@ -23,13 +27,20 @@ const BLEND_CSS = {
23
27
  * posed with a single CSS matrix() write per frame — exact, since bone
24
28
  * transforms are affine.
25
29
  * - Mesh attachments (deform parts) each get a small per-part <canvas> sized
26
- * to the mesh's world bounding box, redrawn per frame with the standard
27
- * per-triangle clip+transform+drawImage mapping.
30
+ * to the mesh's world bounding box, redrawn per frame — either with the
31
+ * standard per-triangle clip+transform+drawImage mapping (default), or via
32
+ * a shared offscreen WebGL canvas that rect-blits into the same per-part
33
+ * canvases (meshBackend = 'webgl'). Frames where the canvas-space vertices
34
+ * are unchanged reuse the previous raster on both backends.
28
35
  *
29
36
  * Both element kinds share one stacking context, so draw order interleaves
30
37
  * freely via z-index (rear hair canvas < torso img < front hair canvas).
31
- * Clipping attachments are deliberately unsupported (transparent layered
32
- * parts make them unnecessary); they are counted in clipSkipCount.
38
+ * RGB tint (skeleton × slot × attachment color) is applied per element with
39
+ * an SVG feColorMatrix reference filter exact channel multiply, works the
40
+ * same on <img> and <canvas>. Dark (two-color) tint is not expressible that
41
+ * way and is unsupported. Clipping attachments are deliberately unsupported
42
+ * (transparent layered parts make them unnecessary); they are counted in
43
+ * clipSkipCount.
33
44
  *
34
45
  * Coordinate mapping: Spine is Y-up, CSS is Y-down — world Y is negated.
35
46
  * spine-core computes everything (bones, constraints, physics, deformed
@@ -40,8 +51,16 @@ export class SpineHtmlRenderer {
40
51
  regionImages;
41
52
  /** Clipping attachments encountered (visible but unsupported). */
42
53
  clipSkipCount = 0;
43
- /** Mesh canvases drawn last frame. */
54
+ /** Mesh canvases rasterized last frame. */
44
55
  meshCount = 0;
56
+ /** Mesh canvases that reused their previous raster last frame. */
57
+ meshReuseCount = 0;
58
+ /**
59
+ * Mesh canvas backing stores (re)allocated last frame. Should drop to zero
60
+ * once an animation reaches its steady state; a persistent nonzero value
61
+ * means GPU surfaces are being recreated per frame (a Safari killer).
62
+ */
63
+ canvasReallocCount = 0;
45
64
  /** Triangles rasterized last frame. */
46
65
  triangleCount = 0;
47
66
  /**
@@ -50,8 +69,35 @@ export class SpineHtmlRenderer {
50
69
  * set to 0 to see them.
51
70
  */
52
71
  triangleExpand = 0.5;
72
+ /**
73
+ * Mesh-canvas backing-store pixels per CSS pixel. Defaults to the device
74
+ * pixel ratio. If the caller scales the root element, fold that scale in
75
+ * (e.g. devicePixelRatio * rootScale) so the raster matches the on-screen
76
+ * resolution instead of over- or under-sampling.
77
+ */
78
+ pixelRatio = typeof devicePixelRatio === 'number' ? devicePixelRatio : 1;
79
+ /**
80
+ * Rasterizer for the mesh (deform) tier. 'canvas2d' (default) maps each
81
+ * triangle with clip+transform+drawImage directly on the per-part canvas.
82
+ * 'webgl' rasterizes every dirty mesh into one shared offscreen WebGL
83
+ * canvas and rect-blits each mesh back onto its per-part canvas — the DOM
84
+ * structure and all element-level behavior (z-index interleave, tint
85
+ * filter, mix-blend-mode, dirty-skip) are identical, only the raster step
86
+ * changes. Motivation: Safari antialiases canvas2d clip paths, so the
87
+ * per-triangle clip mapping pays a per-triangle AA-mask cost in the GPU
88
+ * process that rAF-limits heavy scenes; GL rasterizes shared edges
89
+ * seamlessly (no clip, no crack overdraw) and the blit is an unclipped
90
+ * rect copy. Falls back to 'canvas2d' when WebGL is unavailable or the
91
+ * shared context is lost — see meshBackendActive.
92
+ */
93
+ meshBackend = 'canvas2d';
94
+ /** Backend that actually rasterized the mesh tier during the last render(). */
95
+ meshBackendActive = 'canvas2d';
53
96
  views = new Map();
54
- meshVertices = new Float32Array(256);
97
+ pendingJobs = [];
98
+ pendingViews = [];
99
+ scratchVertices = new Float32Array(256);
100
+ tintDefs = null;
55
101
  /**
56
102
  * @param root Positioned element (e.g. position:absolute) that becomes the
57
103
  * skeleton origin. The renderer only appends slot elements to it — layout
@@ -65,9 +111,12 @@ export class SpineHtmlRenderer {
65
111
  render(skeleton) {
66
112
  this.clipSkipCount = 0;
67
113
  this.meshCount = 0;
114
+ this.meshReuseCount = 0;
115
+ this.canvasReallocCount = 0;
68
116
  this.triangleCount = 0;
117
+ const blitter = this.meshBackend === 'webgl' ? getMeshGlBlitter() : null;
118
+ this.meshBackendActive = blitter ? 'webgl' : 'canvas2d';
69
119
  const drawOrder = skeleton.drawOrder.appliedPose;
70
- const skeletonAlpha = skeleton.color.a;
71
120
  for (let i = 0, n = drawOrder.length; i < n; i++) {
72
121
  const slot = drawOrder[i];
73
122
  const pose = slot.appliedPose;
@@ -77,10 +126,10 @@ export class SpineHtmlRenderer {
77
126
  continue;
78
127
  }
79
128
  if (attachment instanceof RegionAttachment) {
80
- this.renderRegion(slot, pose, attachment, i, skeletonAlpha);
129
+ this.renderRegion(skeleton, slot, pose, attachment, i);
81
130
  }
82
131
  else if (attachment instanceof MeshAttachment) {
83
- this.renderMesh(skeleton, slot, pose, attachment, i, skeletonAlpha);
132
+ this.renderMesh(skeleton, slot, pose, attachment, i);
84
133
  }
85
134
  else {
86
135
  if (attachment instanceof ClippingAttachment)
@@ -88,14 +137,29 @@ export class SpineHtmlRenderer {
88
137
  this.hide(slot);
89
138
  }
90
139
  }
140
+ if (this.pendingJobs.length) {
141
+ if (!blitter || !blitter.flush(this.pendingJobs)) {
142
+ // Context lost mid-frame: rasterize this batch on the 2d path so the
143
+ // frame stays complete; the next render() re-selects the backend.
144
+ for (let i = 0; i < this.pendingJobs.length; i++) {
145
+ const job = this.pendingJobs[i];
146
+ this.pendingViews[i].meshBackendDrawn = 'canvas2d';
147
+ this.rasterizeMesh2d(job.canvas, job.page, job.vertices, job.uvs, job.triangles, job.ratio);
148
+ }
149
+ }
150
+ this.pendingJobs.length = 0;
151
+ this.pendingViews.length = 0;
152
+ }
91
153
  }
92
154
  dispose() {
93
155
  for (const view of this.views.values())
94
156
  view.el.remove();
95
157
  this.views.clear();
158
+ this.tintDefs?.remove();
159
+ this.tintDefs = null;
96
160
  }
97
161
  // --- rigid tier -----------------------------------------------------------
98
- renderRegion(slot, pose, attachment, zIndex, skeletonAlpha) {
162
+ renderRegion(skeleton, slot, pose, attachment, zIndex) {
99
163
  const sequence = attachment.sequence;
100
164
  const region = sequence.regions[sequence.resolveIndex(pose)];
101
165
  const regionImage = region && this.regionImages.get(region.name);
@@ -125,11 +189,11 @@ export class SpineHtmlRenderer {
125
189
  const b = (ury - uly) / w;
126
190
  const c = (blx - ulx) / h;
127
191
  const d = (bly - uly) / h;
128
- img.style.transform = `matrix(${a},${b},${c},${d},${ulx},${uly})`;
129
- this.applyCommon(view, slot, zIndex, skeletonAlpha * pose.color.a * attachment.color.a);
192
+ this.setTransform(view, `matrix(${a},${b},${c},${d},${ulx},${uly})`);
193
+ this.applyCommon(view, slot, pose, attachment.color, skeleton, zIndex);
130
194
  }
131
195
  // --- deform tier ----------------------------------------------------------
132
- renderMesh(skeleton, slot, pose, attachment, zIndex, skeletonAlpha) {
196
+ renderMesh(skeleton, slot, pose, attachment, zIndex) {
133
197
  const sequence = attachment.sequence;
134
198
  const sequenceIndex = sequence.resolveIndex(pose);
135
199
  const region = sequence.regions[sequenceIndex];
@@ -139,9 +203,9 @@ export class SpineHtmlRenderer {
139
203
  return;
140
204
  }
141
205
  const count = attachment.worldVerticesLength;
142
- if (this.meshVertices.length < count)
143
- this.meshVertices = new Float32Array(count);
144
- const vertices = this.meshVertices;
206
+ if (this.scratchVertices.length < count)
207
+ this.scratchVertices = new Float32Array(count);
208
+ const vertices = this.scratchVertices;
145
209
  attachment.computeWorldVertices(skeleton, slot, 0, count, vertices, 0, 2);
146
210
  // World bounds (in CSS coords: Y negated).
147
211
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
@@ -169,32 +233,110 @@ export class SpineHtmlRenderer {
169
233
  }
170
234
  const view = this.view(slot, 'canvas');
171
235
  const canvas = view.el;
172
- // NOTE: 1x backing store for the PoC; the example atlas is 0.5-scale
173
- // anyway. DPR-aware backing is a follow-up.
174
- if (view.canvasW !== w || view.canvasH !== h) {
175
- view.canvasW = w;
176
- view.canvasH = h;
177
- canvas.width = w;
178
- canvas.height = h;
236
+ const ratio = this.pixelRatio;
237
+ let dirty = view.meshAttachment !== attachment ||
238
+ view.meshSequenceIndex !== sequenceIndex ||
239
+ view.meshExpand !== this.triangleExpand ||
240
+ view.meshVertexCount !== count ||
241
+ view.meshBackendDrawn !== this.meshBackendActive;
242
+ // The backing store only grows, in 32-device-px steps. Setting
243
+ // canvas.width recreates the GPU surface, and a deforming mesh changes
244
+ // its bbox every frame — reallocating every mesh canvas per frame
245
+ // stalled real Safari to ~3 fps while the JS split showed ~4 ms (the
246
+ // cost lives in the compositor, invisible to in-callback timing). With
247
+ // grow-only quantized backing, steady-state animation reallocates
248
+ // nothing. The CSS size mirrors the whole backing so the pixel mapping
249
+ // stays 1:1; the mesh draws into the top-left w×h logical region and
250
+ // the rest stays transparent.
251
+ const needW = Math.max(1, Math.round(w * ratio));
252
+ const needH = Math.max(1, Math.round(h * ratio));
253
+ if (needW > view.canvasW || needH > view.canvasH || view.meshRatio !== ratio) {
254
+ // 25% slack: at low fps the animation is sampled sparsely, so new bbox
255
+ // maxima keep being discovered for many seconds — allocate ahead of the
256
+ // curve instead of chasing it.
257
+ const step = 32;
258
+ view.canvasW = Math.ceil(Math.max(needW * 1.25, view.canvasW) / step) * step;
259
+ view.canvasH = Math.ceil(Math.max(needH * 1.25, view.canvasH) / step) * step;
260
+ view.meshRatio = ratio;
261
+ canvas.width = view.canvasW;
262
+ canvas.height = view.canvasH;
263
+ canvas.style.width = `${view.canvasW / ratio}px`;
264
+ canvas.style.height = `${view.canvasH / ratio}px`;
265
+ this.canvasReallocCount++;
266
+ dirty = true;
267
+ }
268
+ // Canvas-space vertices: identical values mean last frame's raster is
269
+ // still exact (static pose, or the part moved by whole pixels), so the
270
+ // per-triangle redraw can be skipped — the CSS translate below keeps
271
+ // tracking the part. This is the main WebKit cost lever: idle skeletons
272
+ // stop paying the raster entirely.
273
+ if (view.meshVertices.length < count) {
274
+ view.meshVertices = new Float64Array(count);
275
+ dirty = true;
276
+ }
277
+ const rel = view.meshVertices;
278
+ for (let v = 0; v < count; v += 2) {
279
+ const x = vertices[v] - minX;
280
+ const y = vertices[v + 1] - minY;
281
+ if (rel[v] !== x || rel[v + 1] !== y)
282
+ dirty = true;
283
+ rel[v] = x;
284
+ rel[v + 1] = y;
285
+ }
286
+ this.setTransform(view, `translate(${minX}px,${minY}px)`);
287
+ if (!dirty) {
288
+ this.meshReuseCount++;
179
289
  }
180
- canvas.style.transform = `translate(${minX}px,${minY}px)`;
290
+ else {
291
+ view.meshAttachment = attachment;
292
+ view.meshSequenceIndex = sequenceIndex;
293
+ view.meshExpand = this.triangleExpand;
294
+ view.meshVertexCount = count;
295
+ view.meshBackendDrawn = this.meshBackendActive;
296
+ const uvs = sequence.getUVs(sequenceIndex);
297
+ const triangles = attachment.triangles;
298
+ if (this.meshBackendActive === 'webgl') {
299
+ // Queued, not drawn: render() flushes the whole batch through the
300
+ // shared GL context once the slot loop is done. `rel` is this view's
301
+ // own signature array — nothing mutates it before the flush.
302
+ this.pendingJobs.push({
303
+ canvas,
304
+ page,
305
+ vertices: rel,
306
+ uvs,
307
+ triangles,
308
+ ratio,
309
+ width: Math.min(view.canvasW, Math.ceil(w * ratio)),
310
+ height: Math.min(view.canvasH, Math.ceil(h * ratio)),
311
+ });
312
+ this.pendingViews.push(view);
313
+ }
314
+ else {
315
+ this.rasterizeMesh2d(canvas, page, rel, uvs, triangles, ratio);
316
+ }
317
+ this.meshCount++;
318
+ this.triangleCount += triangles.length / 3;
319
+ }
320
+ this.applyCommon(view, slot, pose, attachment.color, skeleton, zIndex);
321
+ }
322
+ /** The canvas2d raster path: clear the backing, map each triangle. */
323
+ rasterizeMesh2d(canvas, page, vertices, uvs, triangles, ratio) {
181
324
  const ctx = canvas.getContext('2d');
182
325
  if (!ctx)
183
326
  return;
184
- ctx.clearRect(0, 0, w, h);
185
- const uvs = sequence.getUVs(sequenceIndex);
186
- const triangles = attachment.triangles;
327
+ // Clear the full backing: the previous frame's bbox (and so its drawn
328
+ // region) may have been larger than today's.
329
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
330
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
331
+ ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
187
332
  const uw = page.width - 1;
188
333
  const uh = page.height - 1;
189
334
  for (let t = 0; t < triangles.length; t += 3) {
190
335
  const i0 = triangles[t] * 2;
191
336
  const i1 = triangles[t + 1] * 2;
192
337
  const i2 = triangles[t + 2] * 2;
193
- this.drawTriangle(ctx, page, vertices[i0] - minX, vertices[i0 + 1] - minY, uvs[i0] * uw, uvs[i0 + 1] * uh, vertices[i1] - minX, vertices[i1 + 1] - minY, uvs[i1] * uw, uvs[i1 + 1] * uh, vertices[i2] - minX, vertices[i2 + 1] - minY, uvs[i2] * uw, uvs[i2 + 1] * uh);
338
+ this.drawTriangle(ctx, page, vertices[i0], vertices[i0 + 1], uvs[i0] * uw, uvs[i0 + 1] * uh, vertices[i1], vertices[i1 + 1], uvs[i1] * uw, uvs[i1 + 1] * uh, vertices[i2], vertices[i2 + 1], uvs[i2] * uw, uvs[i2 + 1] * uh);
194
339
  }
195
- this.meshCount++;
196
- this.triangleCount += triangles.length / 3;
197
- this.applyCommon(view, slot, zIndex, skeletonAlpha * pose.color.a * attachment.color.a);
198
340
  }
199
341
  /**
200
342
  * Standard canvas triangle texture mapping (same math as the official
@@ -242,16 +384,43 @@ export class SpineHtmlRenderer {
242
384
  ctx.restore();
243
385
  }
244
386
  // --- shared plumbing -------------------------------------------------------
245
- applyCommon(view, slot, zIndex, alpha) {
387
+ setTransform(view, transform) {
388
+ if (view.transform !== transform) {
389
+ view.transform = transform;
390
+ view.el.style.transform = transform;
391
+ }
392
+ }
393
+ applyCommon(view, slot, pose, attachmentColor, skeleton, zIndex) {
394
+ const sc = skeleton.color;
395
+ const pc = pose.color;
246
396
  if (view.zIndex !== zIndex) {
247
397
  view.zIndex = zIndex;
248
398
  view.el.style.zIndex = String(zIndex);
249
399
  }
250
- // Alpha only; RGB tinting has no cheap DOM equivalent (out of scope).
400
+ const alpha = sc.a * pc.a * attachmentColor.a;
251
401
  if (view.opacity !== alpha) {
252
402
  view.opacity = alpha;
253
403
  view.el.style.opacity = alpha === 1 ? '' : String(alpha);
254
404
  }
405
+ // RGB tint (uniform per slot) rides an feColorMatrix reference filter:
406
+ // scaling the channels is an exact multiply, applies to <img> and
407
+ // <canvas> alike, and never touches the raster. Needs reference-filter
408
+ // support (Safari 15+).
409
+ const r = sc.r * pc.r * attachmentColor.r;
410
+ const g = sc.g * pc.g * attachmentColor.g;
411
+ const b = sc.b * pc.b * attachmentColor.b;
412
+ if (view.tintR !== r || view.tintG !== g || view.tintB !== b) {
413
+ view.tintR = r;
414
+ view.tintG = g;
415
+ view.tintB = b;
416
+ if (r === 1 && g === 1 && b === 1) {
417
+ view.el.style.filter = '';
418
+ }
419
+ else {
420
+ this.tintMatrixFor(view).setAttribute('values', `${r} 0 0 0 0 0 ${g} 0 0 0 0 0 ${b} 0 0 0 0 0 1 0`);
421
+ view.el.style.filter = `url(#${view.tintId})`;
422
+ }
423
+ }
255
424
  const blendMode = slot.data.blendMode;
256
425
  if (view.blendMode !== blendMode) {
257
426
  view.blendMode = blendMode;
@@ -262,10 +431,36 @@ export class SpineHtmlRenderer {
262
431
  view.el.style.display = '';
263
432
  }
264
433
  }
434
+ tintMatrixFor(view) {
435
+ if (view.tintMatrix)
436
+ return view.tintMatrix;
437
+ if (!this.tintDefs) {
438
+ const svg = document.createElementNS(SVG_NS, 'svg');
439
+ svg.setAttribute('width', '0');
440
+ svg.setAttribute('height', '0');
441
+ svg.style.position = 'absolute';
442
+ this.root.appendChild(svg);
443
+ this.tintDefs = svg;
444
+ }
445
+ const filter = document.createElementNS(SVG_NS, 'filter');
446
+ view.tintId = `spine-html-tint-${tintFilterSeq++}`;
447
+ filter.setAttribute('id', view.tintId);
448
+ // Filter math must happen in sRGB to match Spine's color multiply
449
+ // (SVG filters default to linearRGB).
450
+ filter.setAttribute('color-interpolation-filters', 'sRGB');
451
+ const matrix = document.createElementNS(SVG_NS, 'feColorMatrix');
452
+ matrix.setAttribute('in', 'SourceGraphic');
453
+ matrix.setAttribute('type', 'matrix');
454
+ filter.appendChild(matrix);
455
+ this.tintDefs.appendChild(filter);
456
+ view.tintMatrix = matrix;
457
+ return matrix;
458
+ }
265
459
  view(slot, kind) {
266
460
  let view = this.views.get(slot);
267
461
  if (view && view.kind !== kind) {
268
462
  view.el.remove();
463
+ view.tintMatrix?.parentElement?.remove();
269
464
  view = undefined;
270
465
  }
271
466
  if (!view) {
@@ -287,8 +482,21 @@ export class SpineHtmlRenderer {
287
482
  zIndex: -1,
288
483
  opacity: 1,
289
484
  blendMode: BlendMode.Normal,
485
+ transform: '',
486
+ tintR: 1,
487
+ tintG: 1,
488
+ tintB: 1,
489
+ tintId: '',
490
+ tintMatrix: null,
290
491
  canvasW: 0,
291
492
  canvasH: 0,
493
+ meshRatio: -1,
494
+ meshAttachment: null,
495
+ meshSequenceIndex: -1,
496
+ meshExpand: -1,
497
+ meshVertexCount: -1,
498
+ meshBackendDrawn: '',
499
+ meshVertices: new Float64Array(0),
292
500
  };
293
501
  this.views.set(slot, view);
294
502
  this.root.appendChild(el);
@@ -1 +1 @@
1
- {"version":3,"file":"SpineHtmlRenderer.js","sourceRoot":"","sources":["../src/SpineHtmlRenderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SpineHtmlRenderer.js","sourceRoot":"","sources":["../src/SpineHtmlRenderer.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { SpineHtmlRenderer } from './SpineHtmlRenderer';
1
+ export { SpineHtmlRenderer, type MeshBackend } from './SpineHtmlRenderer';
2
2
  export { DomTexture, unpackRegions, type RegionImage } from './DomTexture';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAoB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAoB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAoB,MAAM,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-html",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Render Spine skeletal animations as plain DOM — rigid slots as <img> posed by CSS matrix, deform meshes on small per-part canvases, interleaved in one stacking context.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -44,6 +44,7 @@
44
44
  "build:lib": "rm -rf dist && tsc -p tsconfig.build.json",
45
45
  "prepublishOnly": "npm run build:lib",
46
46
  "preview": "vite preview",
47
+ "test": "playwright test",
47
48
  "fetch-assets": "bash scripts/fetch-assets.sh"
48
49
  },
49
50
  "peerDependencies": {
@@ -51,6 +52,8 @@
51
52
  },
52
53
  "devDependencies": {
53
54
  "@esotericsoftware/spine-core": "^4.3.13",
55
+ "@playwright/test": "1.62.1",
56
+ "@types/node": "^22",
54
57
  "typescript": "^5.6.0",
55
58
  "vite": "^6.0.0"
56
59
  }