rig-play 1.10.1 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/NOTICE.md CHANGED
@@ -11,20 +11,24 @@ document `rigc build` writes. No part of the
11
11
  [Spine Runtimes](https://github.com/EsotericSoftware/spine-runtimes) is in it,
12
12
  imported by it, or required beside it.
13
13
 
14
- **This repository links no Spine runtime either**, since #63.
15
- `@esotericsoftware/spine-core` and `@esotericsoftware/spine-webgl` are not
16
- dependencies of any kind — not `dependencies`, not `peerDependencies`, not
17
- `devDependencies` — and no lockfile entry names them. The test suite and the
18
- benchmark compare the package's two render modes with each other; the poses
19
- are rig-c's, held to the Spine runtime by rig-c's own CI, not here.
20
- `tests/package.spec.ts` asserts all of that, and that nothing the published
21
- package contains names an `@esotericsoftware/` package.
14
+ **Development tooling uses the official Spine WebGL runtime.** Issue #39
15
+ reintroduces `@esotericsoftware/spine-webgl` 4.3.13 as a pinned devDependency,
16
+ with its matching `@esotericsoftware/spine-core` dependency, for the independent
17
+ pixel oracle and comparison/benchmark tooling. These are licensed under the
18
+ [Spine Runtimes License Agreement](https://esotericsoftware.com/spine-runtimes-license),
19
+ updated April 5, 2025, copyright 2013–2025 Esoteric Software LLC; they are not
20
+ covered by this project's MIT licence. Their licence and copyright notices
21
+ apply to use and redistribution of that tooling. The earlier removal in #63
22
+ remains the history of the production player: no runtime is added back to its
23
+ public API or published library. `tests/package.spec.ts` checks the exact
24
+ development exception and the runtime-free shipped code and declarations.
22
25
 
23
26
  One thing in this repository is Spine data, and it is worth stating where it
24
27
  sits. `rigc build`, which `scripts/fetch-assets.sh` runs to make the fixtures,
25
28
  writes **Spine skeleton data** (`skeleton.json` and `skeleton.atlas`) beside
26
- each model document, into the gitignored `public/rigs/`. Nothing here reads
27
- it, and it is neither committed nor published.
29
+ each model document, into the gitignored `public/rigs/`. The development oracle
30
+ and comparison tooling read that paired export independently of the model
31
+ reader. These generated files are neither committed nor published in the package.
28
32
 
29
33
  ### What that means, as a chain of facts
30
34
 
package/README.md CHANGED
@@ -38,6 +38,81 @@ links to either earlier name keep working.
38
38
 
39
39
  ### Measured
40
40
 
41
+ **Standing comparison against `@esotericsoftware/spine-webgl 4.3.13` (`npm run bench`, #39)** —
42
+ measured on 2026-10-17 in **headed** Chromium `151.0.7922.34` on an Apple M4 GPU
43
+ (`ANGLE (Apple, ANGLE Metal Renderer: Apple M4, Unspecified Version)`, macOS `Darwin 25.6.0`,
44
+ 10 cores, 32 GiB RAM, `1280×720` viewport, `devicePixelRatio: 1`, 100 warm-up frames +
45
+ 600 measured frames per row, `loadPerCoreBefore: 0.33`, `loadPerCoreAfter: 0.33` under the
46
+ `1.0` load guard; each row is its own page load with only that runtime animating, and grid
47
+ scenes batch the official skeletons through one shared WebGL canvas while `small players`
48
+ mounts independent player instances):
49
+
50
+ | scene | runtime | rig | clipped to | fps | pose ms | render ms | drawn players | triangles | draw calls | origin Δpx | live contexts |
51
+ | --- | --- | --- | --- | --: | --: | --: | --: | --: | --: | --: | --: |
52
+ | 1 meshed rig animating | dom | `portrait-packed` `turn` | pane | 59.99 | 0.17 | 0.16 | —/1 | 48 | — | 0.007 | —/1 |
53
+ | 1 meshed rig animating | canvas | `portrait-packed` `turn` | pane | 59.99 | 0.23 | 0.18 | —/1 | 0 | 0 | 0.007 | —/1 |
54
+ | 1 meshed rig animating | official | `portrait-packed` `turn` | pane | 60.00 | 0.05 | 0.13 | 1/1 | 88 | 1 | 0.000 | 1/1 |
55
+ | 4 meshed rigs animating | dom | `portrait-packed` `turn` | pane | 60.01 | 0.46 | 0.48 | —/4 | 96 | — | 0.009 | —/1 |
56
+ | 4 meshed rigs animating | canvas | `portrait-packed` `turn` | pane | 60.00 | 0.60 | 0.49 | —/4 | 176 | 2 | 0.009 | —/1 |
57
+ | 4 meshed rigs animating | official | `portrait-packed` `turn` | pane | 59.99 | 0.13 | 0.17 | 4/4 | 352 | 1 | 0.000 | 1/1 |
58
+ | 16 meshed rigs animating | dom | `portrait-packed` `turn` | pane | 60.00 | 0.66 | 0.74 | —/16 | 384 | — | 0.010 | —/1 |
59
+ | 16 meshed rigs animating | canvas | `portrait-packed` `turn` | pane | 59.87 | 0.84 | 0.50 | —/16 | 704 | 8 | 0.010 | —/1 |
60
+ | 16 meshed rigs animating | official | `portrait-packed` `turn` | pane | 60.00 | 0.21 | 0.30 | 16/16 | 1408 | 1 | 0.000 | 1/1 |
61
+ | 36 meshed rigs animating | dom | `portrait-packed` `turn` | pane | 48.28 | 1.24 | 1.42 | —/36 | 1104 | — | 0.010 | —/1 |
62
+ | 36 meshed rigs animating | canvas | `portrait-packed` `turn` | pane | 60.11 | 1.15 | 0.85 | —/36 | 1760 | 20 | 0.010 | —/1 |
63
+ | 36 meshed rigs animating | official | `portrait-packed` `turn` | pane | 60.00 | 0.43 | 0.49 | 36/36 | 3168 | 1 | 0.000 | 1/1 |
64
+ | 64 meshed rigs animating | dom | `portrait-packed` `turn` | pane | 29.07 | 2.13 | 2.69 | —/64 | 1824 | — | 0.010 | —/1 |
65
+ | 64 meshed rigs animating | canvas | `portrait-packed` `turn` | pane | 53.99 | 1.62 | 1.17 | —/64 | 3168 | 36 | 0.010 | —/1 |
66
+ | 64 meshed rigs animating | official | `portrait-packed` `turn` | pane | 59.99 | 0.42 | 0.54 | 64/64 | 5632 | 1 | 0.000 | 1/1 |
67
+ | 1 meshed rig animating (canvas2d) | dom | `portrait-packed` `turn` | pane | 60.00 | 0.18 | 0.28 | —/1 | 48 | — | 0.007 | —/0 |
68
+ | 1 meshed rig animating (canvas2d) | canvas | `portrait-packed` `turn` | pane | 60.00 | 0.20 | 0.18 | —/1 | 88 | 1 | 0.007 | —/1 |
69
+ | 1 meshed rig animating (canvas2d) | official | `portrait-packed` `turn` | pane | 59.99 | 0.06 | 0.14 | 1/1 | 88 | 1 | 0.000 | 1/1 |
70
+ | 16 meshed rigs animating (canvas2d) | dom | `portrait-packed` `turn` | pane | 59.89 | 0.65 | 0.99 | —/16 | 384 | — | 0.010 | —/0 |
71
+ | 16 meshed rigs animating (canvas2d) | canvas | `portrait-packed` `turn` | pane | 60.00 | 0.93 | 0.59 | —/16 | 792 | 9 | 0.010 | —/1 |
72
+ | 16 meshed rigs animating (canvas2d) | official | `portrait-packed` `turn` | pane | 60.00 | 0.18 | 0.31 | 16/16 | 1408 | 1 | 0.000 | 1/1 |
73
+ | 1 held pose | dom | `portrait-packed` `turn` | pane | 60.11 | 0.00 | 0.15 | —/1 | 0 | — | 0.007 | —/1 |
74
+ | 1 held pose | canvas | `portrait-packed` `turn` | pane | 60.02 | 0.01 | 0.11 | —/1 | 0 | 0 | 0.007 | —/1 |
75
+ | 1 held pose | official | `portrait-packed` `turn` | pane | 60.00 | 0.00 | 0.13 | 1/1 | 88 | 1 | 0.000 | 1/1 |
76
+ | 16 held poses | dom | `portrait-packed` `turn` | pane | 60.09 | 0.00 | 0.43 | —/16 | 0 | — | 0.010 | —/1 |
77
+ | 16 held poses | canvas | `portrait-packed` `turn` | pane | 59.99 | 0.01 | 0.55 | —/16 | 0 | 0 | 0.010 | —/1 |
78
+ | 16 held poses | official | `portrait-packed` `turn` | pane | 60.08 | 0.00 | 0.35 | 16/16 | 1408 | 1 | 0.000 | 1/1 |
79
+ | 64 held poses | dom | `portrait-packed` `turn` | pane | 59.99 | 0.02 | 2.43 | —/64 | 0 | — | 0.010 | —/1 |
80
+ | 64 held poses | canvas | `portrait-packed` `turn` | pane | 60.10 | 0.02 | 2.56 | —/64 | 0 | 0 | 0.010 | —/1 |
81
+ | 64 held poses | official | `portrait-packed` `turn` | pane | 60.10 | 0.00 | 0.90 | 64/64 | 5632 | 1 | 0.000 | 1/1 |
82
+ | 1 rigid rig animating | dom | `walk-packed` `walk` | pane | 59.99 | 0.30 | 0.15 | —/1 | 0 | — | 0.007 | —/1 |
83
+ | 1 rigid rig animating | canvas | `walk-packed` `walk` | pane | 59.99 | 0.33 | 0.21 | —/1 | 30 | 1 | 0.007 | —/1 |
84
+ | 1 rigid rig animating | official | `walk-packed` `walk` | pane | 60.00 | 0.04 | 0.16 | 1/1 | 30 | 1 | 0.000 | 1/1 |
85
+ | 16 rigid rigs animating | dom | `walk-packed` `walk` | pane | 60.00 | 0.77 | 0.65 | —/16 | 0 | — | 0.010 | —/1 |
86
+ | 16 rigid rigs animating | canvas | `walk-packed` `walk` | pane | 60.00 | 0.62 | 0.47 | —/16 | 480 | 16 | 0.010 | —/1 |
87
+ | 16 rigid rigs animating | official | `walk-packed` `walk` | pane | 60.00 | 0.15 | 0.22 | 16/16 | 480 | 1 | 0.000 | 1/1 |
88
+ | 64 rigid rigs animating | dom | `walk-packed` `walk` | pane | 59.89 | 1.58 | 1.63 | —/64 | 0 | — | 0.010 | —/1 |
89
+ | 64 rigid rigs animating | canvas | `walk-packed` `walk` | pane | 42.00 | 1.50 | 1.21 | —/64 | 1920 | 64 | 0.010 | —/1 |
90
+ | 64 rigid rigs animating | official | `walk-packed` `walk` | pane | 60.00 | 0.14 | 0.13 | 64/64 | 1920 | 1 | 0.000 | 1/1 |
91
+ | 8 small players | dom | `walk-packed` `walk` | cell | 60.00 | 0.24 | 0.18 | —/8 | 0 | — | 0.012 | —/1 |
92
+ | 8 small players | canvas | `walk-packed` `walk` | cell | 60.00 | 0.33 | 0.30 | —/8 | 240 | 8 | 0.012 | —/1 |
93
+ | 8 small players | official | `walk-packed` `walk` | cell | 60.00 | 0.09 | 0.24 | 8/8 | 240 | 8 | 0.007 | 8/8 |
94
+ | 20 small players | dom | `walk-packed` `walk` | cell | 60.00 | 1.03 | 0.84 | —/20 | 0 | — | 0.015 | —/1 |
95
+ | 20 small players | canvas | `walk-packed` `walk` | cell | 59.99 | 0.69 | 0.54 | —/20 | 600 | 20 | 0.015 | —/1 |
96
+ | 20 small players | official | `walk-packed` `walk` | cell | 60.00 | 0.13 | 0.24 | 16/20 | 480 | 16 | 0.006 | 16/20 |
97
+
98
+ Where each side wins and loses on that table:
99
+
100
+ - **High-count meshed grids (`36` and `64 meshed rigs animating`) — `official` wins**: batching
101
+ all 64 skeletons into one WebGL canvas holds `59.99 fps` (`5,632 triangles` in `1 draw call`),
102
+ while `canvas` mode drops to `53.99 fps` (per-player `drawImage` blits from the shared WebGL
103
+ context) and `dom` mode drops to `48.28 fps` at 36 rigs and `29.07 fps` at 64 rigs (per-part
104
+ mesh canvas blits + DOM compositing). Up to 16 animating meshed rigs all three hold `60 fps`.
105
+ - **Held poses (`1`, `16`, `64 held poses`) — `dom` and `canvas` skip rasterization**: both
106
+ modes reuse their rasters (`0 triangles`, `0 draw calls`), while `official` redraws
107
+ `88` / `1,408` / `5,632 triangles` every frame.
108
+ - **Rigid-heavy grids (`64 rigid rigs animating`) — `dom` and batched `official` hold `60 fps`**:
109
+ `dom` updates `<img>` CSS transforms (`0 triangles`, `59.89 fps`), whereas `canvas` pays 64
110
+ per-player `drawImage` blits (`42.00 fps`).
111
+ - **Many independent players on one page (`20 small players`) — `dom` and `canvas` draw all 20;
112
+ `official` loses 4 to the browser's 16-context WebGL cap**: both `@rig-c/play` modes share at
113
+ most one WebGL context across the page, while mounting 20 independent `spine-webgl` players
114
+ evicts 4 contexts (`16/20 drawn players`, `16/20 live contexts`).
115
+
41
116
  **The element mode's mesh backend is `'webgl'` by default since 1.9 (#109)**, read off
42
117
  macOS Safari on 2026-10-13 (1.8.2, gallery rig `look-packed`: 4 meshes, 464
43
118
  triangles, `sweep`; the demo's stats line after a 30 s settle; the Mac was also
@@ -399,6 +474,52 @@ const front = new DomRenderer(frontRoot, assets.regionImages, assets.pageImages)
399
474
  front.render(player.posedFrame(['hand_f', 'arm_f_lo']));
400
475
  ```
401
476
 
477
+ ### Attachment sets (`sets.json`)
478
+
479
+ A build from `@rig-c/parts` (or authored alongside a rig) may ship a `sets.json`
480
+ sidecar beside `skeleton.model.json` declaring named attachment sets — an
481
+ expression, a viseme, a side view — under spec `"rig-parts-sets/1"` or
482
+ `"spine-parts-sets/1"`:
483
+
484
+ ```json
485
+ {
486
+ "spec": "rig-parts-sets/1",
487
+ "sets": {
488
+ "smile": {
489
+ "slots": { "face": "face_smile", "prop": "prop_star" },
490
+ "hides": []
491
+ },
492
+ "wink": {
493
+ "slots": { "face": "face_wink" },
494
+ "hides": ["prop"]
495
+ }
496
+ }
497
+ }
498
+ ```
499
+
500
+ `loadModel` probes `sets.json` in the model document's directory by default
501
+ (treating a 404 as "no sets"; pass `setsUrl: null` to skip the probe, or a URL
502
+ string to require one at another path) and validates every slot and attachment
503
+ name against the model document. `player.sets()` (and `assets.sets`) returns the
504
+ declared `readonly RigSet[]` (`{ name, slots, hides }`), and `player.setSet(name)`
505
+ switches the active set at runtime (#134):
506
+
507
+ ```ts
508
+ player.sets(); // [{ name: 'smile', slots: { ... }, hides: [] }, ...]
509
+ player.setSet('smile'); // covered slots take the set's attachments; <slot>_still and hides are hidden
510
+ player.set; // 'smile'
511
+ player.setSet(null); // restore base / track attachments
512
+ ```
513
+
514
+ The active set is applied immediately to the held pose (including the setup pose
515
+ before `play`) and after track evaluation on every subsequent `advance`, so a
516
+ track key on a covered slot is overridden while the set is active and restored
517
+ on the next frame when cleared with `setSet(null)`. Uncovered slots keep their
518
+ track attachments, mesh deforms and sequence frames untouched; when no set is
519
+ active (`null`), track evaluation runs with zero extra work and produces
520
+ byte-identical poses. An unknown set name throws by name; on a build without
521
+ `sets.json`, `sets()` is empty (`[]`) and `setSet` throws.
522
+
402
523
  ### Several tracks
403
524
 
404
525
  A base on track 0, a layer over it, a one-shot played once and mixed back out —
@@ -944,23 +1065,17 @@ deterministic captures.
944
1065
  bun run test # builds + serves the demo, then runs chromium + webkit
945
1066
  ```
946
1067
 
947
- Playwright drives the demo (`tests/`, config in `playwright.config.ts`; CI
948
- runs the same suite on ubuntu, one job). Every scene is a rig built by
949
- `rigc build` and posed by `rig-c/core` through `RigPlayer` — rigc's gallery rigs,
950
- and three test rigs authored in this repository (`tests/rigs/`) for what the
951
- gallery does not carry: `figure` (clipping attachments in rigc's format —
952
- convex, inverse, nested, whole-skeleton — rigid parts on turned bones, two grid
953
- meshes), `glow` (additive slots with slot colours over two weighted meshes) and
954
- `turned` (a region packed turned 90° on a hand-packed page). No Spine runtime
955
- is installed or compared against: the pose is rig-c's, held to spine-core at
956
- tolerance 0 by rig-c's own CI, and a pose doubt is a rigc issue. The visual
957
- checks are **A/B within one run**: no golden snapshots are committed (they rot
958
- across platforms/GPUs) — instead the same deterministic pose (`?time` +
959
- `?timescale=0`) is screenshotted twice in the same engine and the buffers are
960
- diffed directly with a shift-tolerant comparison, so missing parts, wrong
961
- colors, and tint/blend/clip divergence fail regardless of platform.
962
-
963
- **The picture gate** is the two render modes drawing the same picture: every
1068
+ Playwright drives rigc-built gallery and procedural test rigs through the
1069
+ production `RigPlayer`; its pose comes from `rig-c/core`. CI runs the same
1070
+ suite on Ubuntu with Chromium and WebKit. Internal parity captures the same
1071
+ deterministic pose in two modes/backends within one engine. An independent
1072
+ development oracle also reads the paired Spine export through the official
1073
+ WebGL runtime. No snapshot goldens are committed. Residue limits are measured
1074
+ per engine, case and renderer; an A/B design alone does not make a measured
1075
+ budget portable to another platform. Pose discrepancies remain rigc issues;
1076
+ the independent oracle checks the resulting raster.
1077
+
1078
+ **Internal picture parity** checks the two render modes drawing the same picture: every
964
1079
  scene captured in the DOM mode and in the canvas mode and diffed — bad pixels at
965
1080
  most 1.5% of drawn content on the test-rig scenes (measured floors 0.007–0.524%,
966
1081
  macOS Chromium; each scene's own feature dropped from the canvas mode — tint,
@@ -996,16 +1111,58 @@ resolving, so blob ownership — every unpacked URL freed, nothing the caller
996
1111
  owns touched, nothing stranded by a failed load — is asserted rather than
997
1112
  assumed.
998
1113
 
999
- ## Benchmark: DOM mode vs canvas mode
1114
+ ### Independent official raster oracle
1115
+
1116
+ `tests/oracle.spec.ts` compares real DOM WebGL, DOM canvas2d and whole-canvas
1117
+ output with `@esotericsoftware/spine-webgl` 4.3.13. The official reader parses
1118
+ the same build's Spine JSON, atlas and original PNGs independently; it never
1119
+ receives a `PosedFrame` or the player's alpha-corrected textures. JSON SHA-256
1120
+ binds the export to the compiled model, and generation/page dimensions fail
1121
+ closed. Both posers receive the same fixed-step history, crop, origin, scale
1122
+ and DPR 1; world geometry must agree exactly before raster acceptance.
1123
+
1124
+ Captures include the actual images, element canvases, CSS transforms, tint
1125
+ and clipping. Transparent RGB remains diagnostic, except for additional narrow
1126
+ raw checks on the whole-canvas PMA case. Acceptance compares those
1127
+ same captured bytes on black and white backgrounds with the shared pixel
1128
+ differ, and separately constrains alpha coverage, sum, unequal-pixel count
1129
+ and maximum. `tests/oracleLimits.ts` stores measured engine/case/mode floors:
1130
+ zero stays exact; nonzero counts receive 10% plus two units, and nonzero byte
1131
+ maxima one byte. macOS and Linux have separately measured tables; other
1132
+ platforms are refused as uncalibrated. Tests never regenerate limits from the
1133
+ image under test.
1134
+
1135
+ Cases cover geometry, tint, clipping, draw order with multiply/screen,
1136
+ rotated/named regions, additive glow and an original-PMA twin. Named UV and
1137
+ rotation coverage uses native scale: measured half-scale checker sampling
1138
+ has additional residue, so arbitrary-scale pixel identity is not claimed.
1139
+ The shared #37 negative control serves false PMA flags only in the player's
1140
+ model response, leaving original files and the official reader unchanged.
1141
+ Each renderer must first pass its healthy capture, then exceed the same
1142
+ healthy black-composite budget with the altered response. This runs on both
1143
+ CI browser projects. Original PMA PNG bytes are encoded before either reader
1144
+ sees them.
1145
+
1146
+ The reference uses `antialias:false`, `preserveDrawingBuffer:true` and the
1147
+ official `pmaAdditiveBatching:false` option to retain additive coverage in
1148
+ transparent captures. Initialization finishes model/region extraction before
1149
+ official page uploads, avoiding a measured concurrent WebKit initialization
1150
+ artifact. Use the required nova-run guard and a unique `TEST_PORT` for a
1151
+ focused `bun run test tests/oracle.spec.ts --workers=1`; full-suite acceptance
1152
+ remains CI. Headless results are raster evidence, never device performance.
1153
+
1154
+ ## Benchmark: DOM, canvas and official WebGL
1000
1155
 
1001
1156
  ```bash
1002
1157
  bun run bench:dev # the page, for a person to watch (and for Safari)
1003
1158
  bun run bench # drives it in a headed Chromium and writes a report
1159
+ bun run bench --headless # counters only; all timing fields are null
1004
1160
  ```
1005
1161
 
1006
1162
  `bench/` is a separate vite project — not part of the library, and not part of
1007
- what `bun run build` emits — that plays the same rigc gallery build in both
1008
- render modes side by side, each with its own stats line in the demo's style.
1163
+ what `bun run build` emits — that compares DOM, whole-canvas and the independent
1164
+ official WebGL reader, each with its own stats line. The paired JSON hash must
1165
+ match the model before an official comparison can publish readings.
1009
1166
  Scenes by query string: `?scene=mesh` (`portrait-packed` turning its head, the
1010
1167
  deform tier working every frame), `?scene=held` (the same pose frozen, where
1011
1168
  unchanged meshes reuse their raster and an unchanged frame is reused),
@@ -1016,7 +1173,7 @@ something you can see), laid out on one grid whose per-rig scale shrinks with
1016
1173
  the column count, so a step up in count adds rigs rather than cropping the ones
1017
1174
  already there.
1018
1175
 
1019
- **The two sides draw the same picture.** Both place rigs with one derivation and
1176
+ **The comparison uses the same framing.** All paths place rigs with one derivation and
1020
1177
  clip each to the same rect — the pane for a grid, the rig's own cell for `many`
1021
1178
  — with `overflow: hidden` on a box, the way a page embeds a player, and then
1022
1179
  *check* it: each side reports `origin Δpx`, the largest gap between where the
@@ -1024,9 +1181,12 @@ grid puts a rig and where that side drew it, and the report table carries it per
1024
1181
  row. (`contain: layout paint` is deliberately not used: paint containment clips
1025
1182
  to the same edge `overflow: hidden` does, and what it adds past the clip — a
1026
1183
  stacking context, a containing block, an independent formatting context —
1027
- changes how one side is composited and buys the comparison nothing.) Both modes
1028
- share the package's single WebGL context however many players there are; the
1029
- canvas side's stats line says how many contexts the page holds.
1184
+ changes how one side is composited and buys the comparison nothing.) Production
1185
+ modes retain the package's shared WebGL context. Official grid scenes batch
1186
+ all skeletons through one context; only `many` uses independent contexts.
1187
+ Official surviving contexts and drawn players are counted separately from
1188
+ requested players. Production survival counters are null where its public
1189
+ API cannot measure them, rather than treating requested counts as survivors.
1030
1190
 
1031
1191
  `scripts/bench.mjs` walks `bench/scenes.json`, opens each scene in a **headed**
1032
1192
  Chromium (a hidden page throttles `requestAnimationFrame`, so a headless
@@ -1034,15 +1194,20 @@ reading would be the browser's power policy rather than either mode's cost),
1034
1194
  runs a fixed number of frames per mode — one at a time, because rAF has a single
1035
1195
  cadence per document — and writes JSON plus a markdown table with the
1036
1196
  conditions attached: browser version, device pixel ratio, window size, GPU
1037
- string, and the load average before and after. Over a threshold it stamps the
1197
+ string, and the load average before and after. A software or unidentified GPU
1198
+ invalidates a headed timing report. Over a load threshold it stamps the
1038
1199
  whole report `INVALID: load average too high` and exits non-zero, because a
1039
1200
  benchmark on a busy machine measures the machine. `--corpus <dir>` points it at
1040
- local rigc builds that never enter this repository.
1201
+ local rigc builds that never enter this repository. `--headless` instead steps
1202
+ fixed frames and records counters only: FPS, pose/render timing and GPU fields
1203
+ are null, with “측정 불가: 헤드리스” in JSON and the table. The official
1204
+ additive-batching and drawing-buffer settings are recorded as conditions.
1041
1205
 
1042
- > **Numbers pending.** No comparison table is published yet. A reading taken on
1206
+ > **Performance numbers pending.** Counter reports establish the instrument,
1207
+ > not a performance comparison. A timing reading taken on
1043
1208
  > a loaded machine, a CI runner or a headless browser would not be worth
1044
1209
  > printing. The table will be taken the way every other number in this README
1045
- > was: the two stats lines read on a real device, on a quiet machine, per scene
1210
+ > was: the stats lines read on a real device, on a quiet machine, per scene
1046
1211
  > and per engine — including Safari, which stays manual because no automation
1047
1212
  > preserves what is being measured there. Until then the instrument exists and
1048
1213
  > the measurement does not.
@@ -1086,12 +1251,16 @@ so here is what is true of this package and this repository, stated plainly:
1086
1251
  `rig-c/core` (MIT), which poses rigc's model document; no part of the
1087
1252
  [Spine Runtimes](https://github.com/EsotericSoftware/spine-runtimes) is in it or
1088
1253
  required beside it.
1089
- 2. This repository links no Spine runtime either, since #63: no package of Esoteric
1090
- Software's npm scope is a dependency of any kind, and the lockfile names none.
1091
- `tests/package.spec.ts` asserts both.
1254
+ 2. Development tooling pins `@esotericsoftware/spine-webgl` 4.3.13 and its matching
1255
+ spine-core dependency for the independent oracle and comparison/benchmark.
1256
+ The [Spine Runtimes License Agreement](https://esotericsoftware.com/spine-runtimes-license)
1257
+ covers those runtimes, not this project's MIT license. They remain outside
1258
+ production source, the public API and the library package; package guards
1259
+ and the library-only pack allowlist hold that boundary.
1092
1260
  3. `rigc build`, which this repository runs to make its fixtures, also writes Spine
1093
1261
  skeleton data (`skeleton.json` and `skeleton.atlas`) beside each model document.
1094
- Nothing here reads it, and it is neither committed nor published.
1262
+ Development tooling reads this paired export independently. Generated fixtures
1263
+ remain gitignored and excluded from the library package. See [NOTICE.md](NOTICE.md).
1095
1264
  4. A product that plays that Spine data with a Spine Runtime has integrated the Spine
1096
1265
  Runtimes, whose licence permits it **under Section 2 of the
1097
1266
  [Spine Editor License Agreement](https://esotericsoftware.com/spine-editor-license)**,
@@ -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":"AACA,OAAO,EAAmB,KAAK,WAAW,EAAuB,MAAM,iBAAiB,CAAC;AAEzF,OAAO,KAAK,EAAwB,UAAU,EAAqC,MAAM,iBAAiB,CAAC;AAE3G,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC;AAE/C;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,MAAM,CAAC;AAuMjD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,WAAW;IA2IpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK;IA5IxB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,UAAQ;IAChB,8EAA8E;IAC9E,SAAS,SAAK;IACd;;;;;OAKG;IACH,aAAa,SAAK;IAClB;;;;OAIG;IACH,cAAc,SAAK;IACnB,2CAA2C;IAC3C,SAAS,SAAK;IACd,kEAAkE;IAClE,cAAc,SAAK;IACnB;;;;OAIG;IACH,kBAAkB,SAAK;IACvB,uCAAuC;IACvC,aAAa,SAAK;IAClB;;;;;OAKG;IACH,cAAc,SAAO;IACrB;;;;OAIG;IACH,cAAc,EAAE,cAAc,CAA2B;IACzD;;;;;;OAMG;IACH,UAAU,SAA+D;IACzE;;;;;;;;;;;;;;OAcG;IACH,WAAW,EAAE,WAAW,CAAW;IACnC,+EAA+E;IAC/E,iBAAiB,EAAE,WAAW,CAAW;IAEzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD,6FAA6F;IAC7F,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkB;IAC/C;;;;OAIG;IACH,OAAO,CAAC,OAAO,CAAsC;IACrD;;;;;;OAMG;IACH,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAA8B;IAC9C,iEAAiE;IACjE,OAAO,CAAC,UAAU,CAA0B;IAC5C,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAClD,OAAO,CAAC,WAAW,CAAS;IAC5B,yEAAyE;IACzE,OAAO,CAAC,UAAU,CAAS;IAC3B,0EAA0E;IAC1E,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,iBAAiB,CAAK;IAC9B;;;;OAIG;IACH,OAAO,CAAC,aAAa,CAAuB;IAC5C,6EAA6E;IAC7E,OAAO,CAAC,eAAe,CAAM;IAE7B;;;;;;;;;OASG;gBAEgB,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,EAC9C,KAAK,GAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAa;IAG3E;;;;;;;;;;;OAWG;IACH,IAAI,iBAAiB,IAAI,MAAM,CAM9B;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACH,cAAc,IAAI,MAAM;IAKxB;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAsE/B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,IAAI,IAAI;IAiBf,OAAO,CAAC,YAAY;IAwCpB,OAAO,CAAC,UAAU;IA8JlB;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IAWlB,sEAAsE;IACtE,OAAO,CAAC,eAAe;IAuCvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2DG;IACH,OAAO,CAAC,YAAY;IAWpB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,OAAO;IAmCf;;;;;;;;;;OAUG;IACH,OAAO,CAAC,SAAS;IAoDjB,OAAO,CAAC,WAAW;IAOnB,yEAAyE;IACzE,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,WAAW;IA4CnB,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,IAAI;IAsDZ,OAAO,CAAC,IAAI;CAWb"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { type CanvasBackend, CanvasRenderer, type CanvasViewport } from './CanvasRenderer.js';
2
2
  export { DomRenderer, type MeshBackend, type MeshSourceRect } from './DomRenderer.js';
3
3
  export { type PageLayout, type PageRegion, type RegionEncoding, type RegionImage, revokeRegions, type UnpackRegionsOptions, unpackRegions } from './DomTexture.js';
4
- export { type LoadModelOptions, loadModel, type ModelAssets, type ModelDocument, type RegionLoading } from './loadModel.js';
4
+ export { type LoadModelOptions, loadModel, type ModelAssets, type ModelDocument, type RegionLoading, type RigSet } from './loadModel.js';
5
5
  export { type AdjustableBones, type BoneAdjust, type BoneLocals, type BoneWorld, type PlayOptions, type PoseBounds, type QueueOptions, type RenderMode, type RigComplete, type RigEnvironment, type RigEvent, RigPlayer, type RigPlayerOptions, type SlotFilter, type TrackEntry } from './player.js';
6
6
  export type { BlendMode, PosedClip, PosedFrame, PosedMesh, PosedRegion, PosedSlot, } from './posedFrame.js';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnK,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5H,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACtS,YAAY,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnK,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACzI,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACtS,YAAY,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,iBAAiB,CAAC"}