rig-play 1.8.0 → 1.8.2

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/NOTICE.md CHANGED
@@ -3,8 +3,8 @@
3
3
  ## Spine Runtimes
4
4
 
5
5
  **The published package links nothing from Esoteric Software.** An install of
6
- `rig-play` (or of `spine-html`, the same files under the name the package first
7
- shipped as) carries one JavaScript module, `dist/index.js`, plus type
6
+ `@rig-c/play` (or of `rig-play` or `spine-html`, the same files under the names the
7
+ package shipped as before) carries one JavaScript module, `dist/index.js`, plus type
8
8
  declarations, and that module bundles two things: the renderer, and
9
9
  `rig-c/core` (MIT), rigc's own posing core, which poses the compiled model
10
10
  document `rigc build` writes. No part of the
@@ -28,7 +28,7 @@ it, and it is neither committed nor published.
28
28
 
29
29
  ### What that means, as a chain of facts
30
30
 
31
- rig-play's own code is MIT (see `LICENSE`). The following is a restatement of
31
+ @rig-c/play's own code is MIT (see `LICENSE`). The following is a restatement of
32
32
  Esoteric Software's terms, not a licence term of this project:
33
33
 
34
34
  1. rigc writes two things side by side: the model document this package plays,
@@ -46,7 +46,7 @@ Esoteric Software's terms, not a licence term of this project:
46
46
  because the package links none.
47
47
 
48
48
  > **What a consumer does with rigc's Spine-format output is governed by
49
- > Esoteric Software's terms**, not by this package — rig-play neither adds those
49
+ > Esoteric Software's terms**, not by this package — @rig-c/play neither adds those
50
50
  > terms nor removes them.
51
51
 
52
52
  ## Example assets
package/README.md CHANGED
@@ -1,18 +1,21 @@
1
1
  <p align="center">
2
- <img src="assets/banner.svg" alt="rig-play - plays rigc's compiled model as DOM elements or one canvas" width="100%" />
2
+ <img src="assets/banner.svg" alt="@rig-c/play - plays rigc's compiled model as DOM elements or one canvas" width="100%" />
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <a href="https://www.npmjs.com/package/rig-play"><img src="https://img.shields.io/npm/v/rig-play.svg?style=flat-square&color=FF6B4A" alt="npm version" /></a>
7
- <a href="https://www.npmjs.com/package/rig-play"><img src="https://img.shields.io/npm/dm/rig-play.svg?style=flat-square&color=EC4899" alt="npm downloads" /></a>
6
+ <a href="https://www.npmjs.com/package/@rig-c/play"><img src="https://img.shields.io/npm/v/@rig-c/play.svg?style=flat-square&color=FF6B4A" alt="npm version" /></a>
7
+ <a href="https://www.npmjs.com/package/@rig-c/play"><img src="https://img.shields.io/npm/dm/@rig-c/play.svg?style=flat-square&color=EC4899" alt="npm downloads" /></a>
8
8
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-38BDF8.svg?style=flat-square" alt="license" /></a>
9
9
  </p>
10
10
 
11
- Plays the rigs [rigc](https://github.com/firejune/rigc) builds — the compiled model
11
+ Plays the rigs [rigc](https://github.com/rig-c/core) builds — the compiled model
12
12
  document `rigc build` writes, `skeleton.model.json` — as **plain DOM**: one
13
13
  absolutely-positioned `<img>` per rigid slot, posed with a single CSS `matrix()` write
14
14
  per frame, deforming meshes on small per-part canvases; or as **one canvas** per player.
15
- `spine-html` is the same package under the name it first shipped as.
15
+ `rig-play` and `spine-html` are the same package under the names it shipped as before.
16
+ The toolchain lives under one organisation: the compiler [rig-c/core](https://github.com/rig-c/core)
17
+ (npm `rig-c`), the part generator [rig-c/parts](https://github.com/rig-c/parts)
18
+ (npm `@rig-c/parts`), and this player, [rig-c/play](https://github.com/rig-c/play).
16
19
 
17
20
  ## Why
18
21
 
@@ -29,8 +32,9 @@ At 1.0 it stopped being a Spine runtime. It plays the model document `rigc build
29
32
  poses it through `rig-c/core` — rigc's own posing core, bundled into the package — and
30
33
  links nothing from Esoteric Software; a Spine export is refused by name. It gained a
31
34
  second render mode that draws the whole frame into one canvas. And it took the name
32
- `rig-play`, which says what it is; `spine-html` keeps being published with the same
33
- files, so links to the old name keep working.
35
+ `rig-play`, which says what it is; after 1.8 it moved with the rest of the toolchain to
36
+ `@rig-c/play`. `rig-play` and `spine-html` keep being published with the same files, so
37
+ links to either earlier name keep working.
34
38
 
35
39
  ### Measured
36
40
 
@@ -99,9 +103,12 @@ default stays `dom`.
99
103
  bounds, interleaved with the rigid `<img>` slots in one stacking context — the DOM
100
104
  handles the bones, a rasterizer handles the warps
101
105
  - ✅ Blend modes via `mix-blend-mode` (additive = `plus-lighter`)
102
- - ✅ Crack-free mesh seams on clip-antialiasing browsers (Safari): each triangle's
103
- clip polygon is expanded 0.5px from its centroid so neighbours overlap — the
104
- texture is continuous across shared edges, so the overlap is invisible
106
+ - ✅ Crack-free mesh seams on the canvas2d backend: canvas2d antialiases each
107
+ triangle's clip edge, so two triangles sharing an edge each leave it partly
108
+ transparent and the background shows through as a hairline — plainest over a
109
+ light background behind light art (#104). Each edge of a triangle's clip
110
+ polygon is moved 0.5px outward along its own normal so neighbours overlap —
111
+ the texture is continuous across shared edges, so the overlap is invisible
105
112
  (`?expand=0` shows the cracks for comparison)
106
113
  - ✅ RGB tinting (skeleton × slot × attachment color) via an SVG `feColorMatrix`
107
114
  reference filter per element — an exact channel multiply that works identically on
@@ -159,11 +166,11 @@ default stays `dom`.
159
166
  ## Install
160
167
 
161
168
  ```bash
162
- npm i rig-play
163
- npm i -D rig-c # the build tool: `rigc build` writes the model rig-play loads
169
+ npm i @rig-c/play
170
+ npm i -D rig-c # the build tool: `rigc build` writes the model the player loads
164
171
  ```
165
172
 
166
- The package plays rigs built by [rigc](https://github.com/firejune/rigc):
173
+ The package plays rigs built by [rigc](https://github.com/rig-c/core):
167
174
  `rigc build` writes a compiled model document, `skeleton.model.json` (spec
168
175
  `rigc-compiled/3`), next to the Spine pair and the atlas pages. That document
169
176
  is what the player loads, and it states everything posing and drawing need —
@@ -173,7 +180,7 @@ the skeleton, the animations, and where every region sits on its page — so the
173
180
  is nothing else to install.
174
181
 
175
182
  ```ts
176
- import { loadModel, RigPlayer } from 'rig-play';
183
+ import { loadModel, RigPlayer } from '@rig-c/play';
177
184
 
178
185
  const assets = await loadModel({ modelUrl: '/rigs/walk/skeleton.model.json' });
179
186
 
@@ -212,7 +219,7 @@ else. A document whose `spec` is not one `rig-c/core` reads is refused with the
212
219
  core's own sentence plus "build it with `rigc build`", and so is a
213
220
  `rigc-compiled/1` document, which predates the `pages` section.
214
221
 
215
- `rig-play` is a third-party renderer and is not affiliated with or endorsed by
222
+ `@rig-c/play` is a third-party renderer and is not affiliated with or endorsed by
216
223
  Esoteric Software.
217
224
 
218
225
  ### Drawing your own frames
@@ -221,7 +228,7 @@ Esoteric Software.
221
228
  record, so anything that can produce one can draw through it:
222
229
 
223
230
  ```ts
224
- import { DomRenderer, type PosedFrame } from 'rig-play';
231
+ import { DomRenderer, type PosedFrame } from '@rig-c/play';
225
232
 
226
233
  const renderer = new DomRenderer(rootElement, assets.regionImages, assets.pageImages);
227
234
  renderer.render(frame); // frame: PosedFrame
@@ -583,8 +590,8 @@ onto shared pages instead. Both play here, unchanged:
583
590
  heavy deforming scenes on Safari want `'webgl'` (see Measured above). Falls back
584
591
  to canvas2d automatically when WebGL is unavailable. Switching re-rasters every
585
592
  mesh once (no reallocation), so it is fine to expose as a user setting.
586
- - `renderer.triangleExpand` — clip overdraw in px that closes antialiased mesh
587
- seams (default 0.5). Also re-rasters every mesh once when changed.
593
+ - `renderer.triangleExpand` — how far (canvas px) each triangle edge's clip is
594
+ moved outward to close antialiased mesh seams (default 0.5). Also re-rasters every mesh once when changed.
588
595
  - `renderer.clipping` — apply the clips the frame carries (default `true`).
589
596
  Which slots a clip covers is decided where the frame is made — the player's
590
597
  adapter walks the draw order the way the runtime's draw loop does (one clip in
@@ -653,9 +660,9 @@ name, and unloading is still elements first, bitmaps second.
653
660
 
654
661
  ### 0.8 → 1.0
655
662
 
656
- | 0.8.0 (`spine-html`) | 1.0.0 (`rig-play`) | Note |
663
+ | 0.8.0 (`spine-html`) | 1.x (`@rig-c/play`, formerly `rig-play`) | Note |
657
664
  | --- | --- | --- |
658
- | `npm i spine-html @esotericsoftware/spine-core` | `npm i rig-play`, and `npm i -D rig-c` for the build tool | 0.8 declared spine-core as a peer dependency (`>=4.0.0 <4.4.0`). 1.0.0 declares no dependencies and no peer dependencies. |
665
+ | `npm i spine-html @esotericsoftware/spine-core` | `npm i @rig-c/play`, and `npm i -D rig-c` for the build tool | 0.8 declared spine-core as a peer dependency (`>=4.0.0 <4.4.0`). 1.0.0 declares no dependencies and no peer dependencies. |
659
666
  | `loadSkeletonAssets(options)` | `loadModel(options)` | One URL instead of two. The `.atlas` and `skeleton.json` a build writes beside the document are not fetched. |
660
667
  | `LoadSkeletonAssetsOptions.atlasUrl`, `skeletonUrl` | `LoadModelOptions.modelUrl` | |
661
668
  | `resolvePage(pageName, atlasUrl)` | `resolvePage(pageName, modelUrl)` | The default now resolves a page name against the model URL's directory. |
@@ -761,7 +768,7 @@ renderer.dispose(); assets.dispose(); // on unload
761
768
  1.0.0:
762
769
 
763
770
  ```ts
764
- import { loadModel, RigPlayer } from 'rig-play';
771
+ import { loadModel, RigPlayer } from '@rig-c/play';
765
772
  const assets = await loadModel({ modelUrl: '/rigs/walk/skeleton.model.json' });
766
773
  const player = new RigPlayer(rootElement, assets);
767
774
  player.play('walk', { loop: true });
@@ -934,10 +941,10 @@ perf oracle is the demo's stats line on a real device.
934
941
 
935
942
  ## License
936
943
 
937
- rig-play's own code is MIT (see [LICENSE](LICENSE)). That says nothing about Spine,
944
+ @rig-c/play's own code is MIT (see [LICENSE](LICENSE)). That says nothing about Spine,
938
945
  so here is what is true of this package and this repository, stated plainly:
939
946
 
940
- 1. The published package — `rig-play`, and `spine-html`, the same files — **links
947
+ 1. The published package — `@rig-c/play`, and `rig-play` and `spine-html`, the same files — **links
941
948
  nothing from Esoteric Software**. Its one module bundles the renderer and
942
949
  `rig-c/core` (MIT), which poses rigc's model document; no part of the
943
950
  [Spine Runtimes](https://github.com/EsotericSoftware/spine-runtimes) is in it or
@@ -956,7 +963,7 @@ so here is what is true of this package and this repository, stated plainly:
956
963
  this project.
957
964
 
958
965
  > **What a consumer does with rigc's Spine-format output is governed by Esoteric
959
- > Software's terms**, not by this package — rig-play neither adds those terms nor
966
+ > Software's terms**, not by this package — @rig-c/play neither adds those terms nor
960
967
  > removes them.
961
968
 
962
969
  No example assets of Esoteric Software's are fetched or redistributed. See
@@ -82,9 +82,10 @@ export declare class DomRenderer {
82
82
  /** Triangles rasterized last frame. */
83
83
  triangleCount: number;
84
84
  /**
85
- * How far (px) each triangle's clip polygon is expanded from its centroid.
86
- * Closes antialiased-clip cracks between adjacent triangles (Safari);
87
- * set to 0 to see them.
85
+ * How far (canvas px) each edge of a triangle's clip polygon is moved
86
+ * outward along its normal. Closes the antialiased-clip cracks between
87
+ * adjacent triangles, through which the background shows (#104); set to 0
88
+ * to see them.
88
89
  */
89
90
  triangleExpand: number;
90
91
  /**
@@ -294,9 +295,10 @@ export declare class DomRenderer {
294
295
  * texel of bilinear support is added, and the result is floor/ceil'd to texel
295
296
  * boundaries (so the sub-rect itself resamples nothing) and clamped to the
296
297
  * page. A fixed pad would not do: the texture-space reach of the expansion is
297
- * `triangleExpand` times the local texels-per-canvas-unit, which on the
298
- * demo's own meshes ranges from ~0.26 texels on a typical triangle to ~8.6 on
299
- * a foreshortened one. Under-padding lets the rim of the overdraw sample
298
+ * `triangleExpand` times the local texels-per-canvas-unit (up to
299
+ * `MITRE_LIMIT` times that at a sharp corner), which on the demo's own meshes
300
+ * ranged from ~0.26 texels on a typical triangle to ~8.6 on a foreshortened
301
+ * one. Under-padding lets the rim of the overdraw sample
300
302
  * nothing, which brings back the very seams the overdraw exists to close.
301
303
  *
302
304
  * No half-texel offset is applied to the incoming u/v: the `(i + 0.5) / size`
@@ -1 +1 @@
1
- {"version":3,"file":"DomRenderer.d.ts","sourceRoot":"","sources":["../src/DomRenderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DomRenderer.d.ts","sourceRoot":"","sources":["../src/DomRenderer.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6845,13 +6845,41 @@ function getMeshGlBlitter() {
6845
6845
  const regionVertices = new Float32Array(8);
6846
6846
  const SVG_NS = "http://www.w3.org/2000/svg";
6847
6847
  let tintFilterSeq = 0;
6848
- function expandPoint(x, y, cx, cy, amount) {
6849
- const dx = x - cx;
6850
- const dy = y - cy;
6851
- const len = Math.sqrt(dx * dx + dy * dy);
6852
- if (len < 1e-6) return [x, y];
6853
- const s = amount / len;
6854
- return [x + dx * s, y + dy * s];
6848
+ const MITRE_LIMIT = 4;
6849
+ const offsetCorners = new Float64Array(6);
6850
+ function offsetTriangle(x0, y0, x1, y1, x2, y2, amount) {
6851
+ const out = offsetCorners;
6852
+ out[0] = x0;
6853
+ out[1] = y0;
6854
+ out[2] = x1;
6855
+ out[3] = y1;
6856
+ out[4] = x2;
6857
+ out[5] = y2;
6858
+ const area = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0);
6859
+ if (amount === 0 || area === 0) return out;
6860
+ const sign = area > 0 ? 1 : -1;
6861
+ let len = Math.hypot(x1 - x0, y1 - y0);
6862
+ const n0x = (y1 - y0) / len * sign, n0y = -(x1 - x0) / len * sign;
6863
+ len = Math.hypot(x2 - x1, y2 - y1);
6864
+ const n1x = (y2 - y1) / len * sign, n1y = -(x2 - x1) / len * sign;
6865
+ len = Math.hypot(x0 - x2, y0 - y2);
6866
+ const n2x = (y0 - y2) / len * sign, n2y = -(x0 - x2) / len * sign;
6867
+ offsetCorner(out, 0, n2x, n2y, n0x, n0y, amount);
6868
+ offsetCorner(out, 2, n0x, n0y, n1x, n1y, amount);
6869
+ offsetCorner(out, 4, n1x, n1y, n2x, n2y, amount);
6870
+ return out;
6871
+ }
6872
+ function offsetCorner(out, i, ax, ay, bx, by, amount) {
6873
+ const k = amount / (1 + ax * bx + ay * by);
6874
+ let dx = (ax + bx) * k, dy = (ay + by) * k;
6875
+ const reach = Math.hypot(dx, dy);
6876
+ const limit = MITRE_LIMIT * amount;
6877
+ if (reach > limit) {
6878
+ dx *= limit / reach;
6879
+ dy *= limit / reach;
6880
+ }
6881
+ out[i] += dx;
6882
+ out[i + 1] += dy;
6855
6883
  }
6856
6884
  function clipCoord(v) {
6857
6885
  return `${clipNum(v)}px`;
@@ -6931,9 +6959,10 @@ class DomRenderer {
6931
6959
  /** Triangles rasterized last frame. */
6932
6960
  triangleCount = 0;
6933
6961
  /**
6934
- * How far (px) each triangle's clip polygon is expanded from its centroid.
6935
- * Closes antialiased-clip cracks between adjacent triangles (Safari);
6936
- * set to 0 to see them.
6962
+ * How far (canvas px) each edge of a triangle's clip polygon is moved
6963
+ * outward along its normal. Closes the antialiased-clip cracks between
6964
+ * adjacent triangles, through which the background shows (#104); set to 0
6965
+ * to see them.
6937
6966
  */
6938
6967
  triangleExpand = 0.5;
6939
6968
  /**
@@ -7365,9 +7394,10 @@ class DomRenderer {
7365
7394
  * texel of bilinear support is added, and the result is floor/ceil'd to texel
7366
7395
  * boundaries (so the sub-rect itself resamples nothing) and clamped to the
7367
7396
  * page. A fixed pad would not do: the texture-space reach of the expansion is
7368
- * `triangleExpand` times the local texels-per-canvas-unit, which on the
7369
- * demo's own meshes ranges from ~0.26 texels on a typical triangle to ~8.6 on
7370
- * a foreshortened one. Under-padding lets the rim of the overdraw sample
7397
+ * `triangleExpand` times the local texels-per-canvas-unit (up to
7398
+ * `MITRE_LIMIT` times that at a sharp corner), which on the demo's own meshes
7399
+ * ranged from ~0.26 texels on a typical triangle to ~8.6 on a foreshortened
7400
+ * one. Under-padding lets the rim of the overdraw sample
7371
7401
  * nothing, which brings back the very seams the overdraw exists to close.
7372
7402
  *
7373
7403
  * No half-texel offset is applied to the incoming u/v: the `(i + 0.5) / size`
@@ -7624,11 +7654,10 @@ class DomRenderer {
7624
7654
  }
7625
7655
  }
7626
7656
  function drawTexturedTriangle(ctx, img, expand, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) {
7627
- const cx = (x0 + x1 + x2) / 3;
7628
- const cy = (y0 + y1 + y2) / 3;
7629
- const [px0, py0] = expandPoint(x0, y0, cx, cy, expand);
7630
- const [px1, py1] = expandPoint(x1, y1, cx, cy, expand);
7631
- const [px2, py2] = expandPoint(x2, y2, cx, cy, expand);
7657
+ const corners = offsetTriangle(x0, y0, x1, y1, x2, y2, expand);
7658
+ const px0 = corners[0], py0 = corners[1];
7659
+ const px1 = corners[2], py1 = corners[3];
7660
+ const px2 = corners[4], py2 = corners[5];
7632
7661
  ctx.beginPath();
7633
7662
  ctx.moveTo(px0, py0);
7634
7663
  ctx.lineTo(px1, py1);