rig-play 1.1.0 → 1.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
@@ -263,6 +263,35 @@ box, an inverse clip removes nothing, and bounding boxes, paths and points do
263
263
  not draw and do not count. Both cost nothing until called and read the same
264
264
  numbers in `dom` and `canvas` mode.
265
265
 
266
+ ### Adjusting bones
267
+
268
+ A per-pose write to bone locals — a breath's scale, a look's rotation, a mouth
269
+ driven while the body holds still:
270
+
271
+ ```ts
272
+ const player = new RigPlayer(root, assets, {
273
+ adjust: (bones) => { bones.bone('mouth').scaleY = 1 + openness; },
274
+ });
275
+ player.adjust = null; // or set it later; setting it re-poses the held pose at once
276
+ ```
277
+
278
+ The function runs once per pose, after the animation's timelines and before the
279
+ world transforms, constraints and physics — `rig-c/core`'s `openTrack({ adjust })`,
280
+ which rig-c holds to the Spine runtime at tolerance 0. **A write lasts one
281
+ pose.** The core poses every step from the setup pose, so a value you want held
282
+ is written again each pose and nothing compounds; a 0.8 caller that multiplied a
283
+ channel on a skeleton it kept between frames writes the value it wants, every
284
+ pose. It runs on every pose the animation is applied to, the first one after
285
+ `play` included, and `seek` and a `mode` change keep it.
286
+
287
+ A paused player and a zero step re-pose nothing, so a change the function would
288
+ make is not seen until the next step — unless you ask: setting `player.adjust`
289
+ re-poses the held pose at the same track time, and `player.repose()` does the
290
+ same for a function whose own state changed (the mouth above), without stepping,
291
+ firing events or drawing. A non-finite value, a bone the document does not have,
292
+ or an error the function throws refuses that step in the core's words, and the
293
+ track is reopened by the next `play` or `seek`.
294
+
266
295
  ### One load, several players
267
296
 
268
297
  One `loadModel` backs any number of players: the regions are cut once, and
@@ -406,7 +435,7 @@ onto shared pages instead. Both play here, unchanged:
406
435
  GPU pages handed back) and creates the other over the same root and assets;
407
436
  `pixelRatio` and `clipping` carry over and the held pose is redrawn at once.
408
437
  `player.renderer` is then a `CanvasRenderer`, whose knobs are `pixelRatio`,
409
- `clipping`, `viewport` and `backend`. What each mode costs, as counters:
438
+ `syncPixelRatio()`, `clipping`, `viewport` and `backend`. What each mode costs, as counters:
410
439
  - **dom** — one element per drawn slot, one style write per changed slot,
411
440
  and the mesh tier's rasters (the knobs below).
412
441
  - **canvas** — one canvas element per player and, per frame that changed,
@@ -559,7 +588,7 @@ name, and unloading is still elements first, bitmaps second.
559
588
  | `new SpineHtmlRenderer(root, regionImages)` | `new DomRenderer(root, regionImages, pages?)` | Only for drawing your own frames; `RigPlayer` constructs its renderer. `pages` is the page-image map the mesh tier samples (`ModelAssets.pageImages`). A hand-built `regionImages` map is still accepted. |
560
589
  | `renderer.render(skeleton)` | `renderer.render(frame)` | Takes a `PosedFrame`, not a skeleton. `player.posedFrame()` returns the one the player would draw. |
561
590
  | `renderer.pixelRatio` | `player.renderer.pixelRatio` | On both renderers. Carried over when `player.mode` changes. |
562
- | `renderer.syncPixelRatio()` | `DomRenderer.syncPixelRatio()` | DOM mode only. `player.renderer` is typed as either renderer, so narrow it (`instanceof DomRenderer`) before calling. |
591
+ | `renderer.syncPixelRatio()` | `player.renderer.syncPixelRatio()` | On both renderers, the same meaning and the same deadband (since 1.3.0; before it, DOM mode only). |
563
592
  | `renderer.meshBackingPixels` | `DomRenderer.meshBackingPixels` | DOM mode only. |
564
593
  | `renderer.meshBackend`, `meshBackendActive`, type `MeshBackend` | `DomRenderer.meshBackend`, `meshBackendActive`, type `MeshBackend` | Same values (`'canvas2d'` default, `'webgl'`). Also settable up front as `RigPlayerOptions.meshBackend`. |
565
594
  | `renderer.triangleExpand` | `DomRenderer.triangleExpand` | Same default (0.5). |
@@ -569,6 +598,9 @@ name, and unloading is still elements first, bitmaps second.
569
598
  | tint: skeleton × slot × attachment colour | `player.color` × slot × attachment | `player.color` is `[r, g, b, a]` and takes the place of the skeleton's colour. The product arrives as `tint` on each `PosedSlot`. |
570
599
  | dark (two-colour) tint: unsupported | `DomRenderer`: unsupported. `CanvasRenderer`: drawn | Carried as `dark` on a `PosedSlot`. The canvas mode's canvas2d fallback draws alpha only. |
571
600
  | `renderer.dispose()` | `player.dispose()` | Then `assets.dispose()`, as before. `DomRenderer.dispose()` and `CanvasRenderer.dispose()` exist for a renderer you constructed yourself. |
601
+ | `skeleton.findBone('head').worldX`, `.worldY`, `.a` … `.d` | `player.bone('head')` | `{ x, y, a, b, c, d, rotationX, rotationY, scaleX, scaleY, active }`, the core's world transform for the pose the player holds (the setup pose before `play`). An unknown name is refused by name. Since 1.1.0. |
602
+ | `bone.scaleY = …` on a `Skeleton` between `state.apply` and `updateWorldTransform` | `RigPlayerOptions.adjust`, `player.adjust`, `player.repose()` | A function called once per pose with the pose's bone locals (`bones.bone('mouth').scaleY = v`). A write lasts one pose: the core poses every step from the setup pose, so write the value you want, every pose — nothing compounds. See *Adjusting bones*. Since 1.2.0. |
603
+ | `skeleton.getBounds(offset, size)` | `player.bounds()` | `{ x, y, width, height }` or null, world units, Y up: the box of every drawn region's corners and mesh's vertices, a slot under a clip counted inside the clip's own box. `ModelAssets.stage` remains the declared framing, not this box. Since 1.1.0. |
572
604
 
573
605
  ### No counterpart in 1.0.0
574
606
 
@@ -586,13 +618,6 @@ export, for which 1.0.0 declares nothing:
586
618
  load, several players.
587
619
  - **More than one track, mixing between animations, or queueing one after another.**
588
620
  `RigPlayer` declares one track; `play` reopens it at the animation's first pose.
589
- - **Reading or writing a bone.** No bone is exposed: nothing sets a bone's local values
590
- between the step and the draw, and nothing returns a bone's world transform. What is
591
- readable is the posed slots: `player.posedFrame()` carries each drawn slot's world
592
- `corners` or `vertices`.
593
- - **A bounds query for the current pose.** None is declared. `ModelAssets.stage` is the
594
- stage the document states (or null), which is the rig's declared framing and not the
595
- box of the pose being drawn.
596
621
  - **Changing the skin after construction.** `skin` is a `RigPlayerOptions` field and
597
622
  `RigPlayer` declares no way to change it later; a second player over the same assets
598
623
  is the declared route.
@@ -608,8 +633,6 @@ export, for which 1.0.0 declares nothing:
608
633
 
609
634
  Knobs on `DomRenderer` that `CanvasRenderer` does not declare:
610
635
 
611
- - `syncPixelRatio()`. `CanvasRenderer.pixelRatio` exists and is set by hand
612
- (`devicePixelRatio * rootScale`).
613
636
  - `meshBackend` and `meshBackendActive`. The canvas mode has its own pair, `backend` and
614
637
  `backendActive` (type `CanvasBackend`, `'webgl'` by default).
615
638
  - `triangleExpand`, `meshBackingPixels`, `clipWriteCount`, `meshCount`, `meshReuseCount`,
@@ -52,7 +52,12 @@ export interface CanvasViewport {
52
52
  export declare class CanvasRenderer {
53
53
  private readonly root;
54
54
  private readonly pages;
55
- /** Backing-store pixels per root CSS pixel; defaults to the device pixel ratio. Fold a root scale in, as for the DOM tier. */
55
+ /**
56
+ * Backing-store pixels per root CSS pixel; defaults to the device pixel
57
+ * ratio. A root under a CSS-scaled ancestor rasters at the wrong resolution
58
+ * until the scale is folded in — `syncPixelRatio()` measures it, as for the
59
+ * DOM tier. The next `render` sizes the backing store to the new ratio.
60
+ */
56
61
  pixelRatio: number;
57
62
  /** Apply the clips the frame carries (default). False draws every slot unclipped and counts the clips in `clipSkipCount`. */
58
63
  clipping: boolean;
@@ -113,6 +118,16 @@ export declare class CanvasRenderer {
113
118
  */
114
119
  constructor(root: HTMLElement, pages: ReadonlyMap<string, HTMLImageElement>);
115
120
  /** Grows the automatic viewport to cover `box` (world units, Y up) ahead of the frames reaching it. */
121
+ /**
122
+ * Measures the root's effective on-screen scale and sets `pixelRatio` to
123
+ * `devicePixelRatio × scale`, returning the ratio now in effect — the same
124
+ * call, the same meaning and the same deadband as `DomRenderer`'s, so code
125
+ * written against `player.renderer` survives a `mode` change. One forced
126
+ * layout per call (a hidden box appended to the root, read, removed), which
127
+ * is why the renderer never calls it for you. The backing store follows on
128
+ * the next `render`; a root that is not laid out leaves the ratio alone.
129
+ */
130
+ syncPixelRatio(): number;
116
131
  reserve(box: CanvasViewport): void;
117
132
  /** Draws one frame. */
118
133
  render(frame: PosedFrame): void;
@@ -1 +1 @@
1
- {"version":3,"file":"CanvasRenderer.d.ts","sourceRoot":"","sources":["../src/CanvasRenderer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAwB,UAAU,EAAa,MAAM,iBAAiB,CAAC;AAEnF,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,CAAC;AAEjD,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAYD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,qBAAa,cAAc;IAgEvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAhExB,8HAA8H;IAC9H,UAAU,SAA+D;IACzE,6HAA6H;IAC7H,QAAQ,UAAQ;IAChB;;;;OAIG;IACH,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAQ;IACvC,mHAAmH;IACnH,OAAO,EAAE,aAAa,CAAW;IACjC,wEAAwE;IACxE,aAAa,EAAE,aAAa,CAAW;IACvC,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAEnC,8EAA8E;IAC9E,SAAS,SAAK;IACd,oEAAoE;IACpE,YAAY,SAAK;IACjB,iEAAiE;IACjE,cAAc,SAAK;IACnB,oFAAoF;IACpF,YAAY,SAAK;IACjB,yDAAyD;IACzD,KAAK,SAAK;IACV,wEAAwE;IACxE,kBAAkB,SAAK;IACvB,yCAAyC;IACzC,SAAS,SAAK;IACd,gIAAgI;IAChI,aAAa,SAAK;IAElB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkC;IACtD,gHAAgH;IAChH,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,sFAAsF;IACtF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,yGAAyG;IACzG,OAAO,CAAC,GAAG,CAAyB;IACpC,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,QAAQ,CAAiB;IAEjC;;;;;;OAMG;gBAEgB,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAgB/D,uGAAuG;IACvG,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI;IAIlC,uBAAuB;IACvB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAuD/B,+GAA+G;IAC/G,OAAO,IAAI,IAAI;IAYf,OAAO,CAAC,MAAM;IAkBd,OAAO,CAAC,OAAO;IAUf,oFAAoF;IACpF,OAAO,CAAC,WAAW;IAkBnB,uGAAuG;IACvG,OAAO,CAAC,gBAAgB;IAoExB,iFAAiF;IACjF,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,MAAM,CAAa;IAE3B;;;OAGG;IACH,OAAO,CAAC,QAAQ;IA4BhB,+CAA+C;IAC/C,OAAO,CAAC,aAAa;IAmErB,OAAO,CAAC,MAAM;CAmEf"}
1
+ {"version":3,"file":"CanvasRenderer.d.ts","sourceRoot":"","sources":["../src/CanvasRenderer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAwB,UAAU,EAAa,MAAM,iBAAiB,CAAC;AAEnF,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,CAAC;AAEjD,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAYD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,qBAAa,cAAc;IAqEvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IArExB;;;;;OAKG;IACH,UAAU,SAA+D;IACzE,6HAA6H;IAC7H,QAAQ,UAAQ;IAChB;;;;OAIG;IACH,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAQ;IACvC,mHAAmH;IACnH,OAAO,EAAE,aAAa,CAAW;IACjC,wEAAwE;IACxE,aAAa,EAAE,aAAa,CAAW;IACvC,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAEnC,8EAA8E;IAC9E,SAAS,SAAK;IACd,oEAAoE;IACpE,YAAY,SAAK;IACjB,iEAAiE;IACjE,cAAc,SAAK;IACnB,oFAAoF;IACpF,YAAY,SAAK;IACjB,yDAAyD;IACzD,KAAK,SAAK;IACV,wEAAwE;IACxE,kBAAkB,SAAK;IACvB,yCAAyC;IACzC,SAAS,SAAK;IACd,gIAAgI;IAChI,aAAa,SAAK;IAElB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkC;IACtD,gHAAgH;IAChH,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,sFAAsF;IACtF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,yGAAyG;IACzG,OAAO,CAAC,GAAG,CAAyB;IACpC,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,QAAQ,CAAiB;IAEjC;;;;;;OAMG;gBAEgB,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAgB/D,uGAAuG;IACvG;;;;;;;;OAQG;IACH,cAAc,IAAI,MAAM;IAKxB,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI;IAIlC,uBAAuB;IACvB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAuD/B,+GAA+G;IAC/G,OAAO,IAAI,IAAI;IAYf,OAAO,CAAC,MAAM;IAkBd,OAAO,CAAC,OAAO;IAUf,oFAAoF;IACpF,OAAO,CAAC,WAAW;IAkBnB,uGAAuG;IACvG,OAAO,CAAC,gBAAgB;IAoExB,iFAAiF;IACjF,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,MAAM,CAAa;IAE3B;;;OAGG;IACH,OAAO,CAAC,QAAQ;IA4BhB,+CAA+C;IAC/C,OAAO,CAAC,aAAa;IAmErB,OAAO,CAAC,MAAM;CAmEf"}
@@ -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.d.ts CHANGED
@@ -2,6 +2,6 @@ export { type CanvasBackend, CanvasRenderer, type CanvasViewport } from './Canva
2
2
  export { DomRenderer, type MeshBackend } from './DomRenderer.js';
3
3
  export { type PageLayout, type PageRegion, type RegionImage, revokeRegions, unpackRegions } from './DomTexture.js';
4
4
  export { type LoadModelOptions, loadModel, type ModelAssets, type ModelDocument } from './loadModel.js';
5
- export { type BoneWorld, type PoseBounds, type RenderMode, type RigEvent, RigPlayer, type RigPlayerOptions } from './player.js';
5
+ export { type AdjustableBones, type BoneAdjust, type BoneLocals, type BoneWorld, type PoseBounds, type RenderMode, type RigEvent, RigPlayer, type RigPlayerOptions } 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,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnH,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxG,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAChI,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,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnH,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxG,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACxL,YAAY,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,31 @@
1
+ const SCALE_PROBE_PX = 100;
2
+ const PIXEL_RATIO_DEADBAND = 1e-3;
3
+ function syncedPixelRatio(root, current) {
4
+ const probe = document.createElement("div");
5
+ probe.style.position = "absolute";
6
+ probe.style.left = "0";
7
+ probe.style.top = "0";
8
+ probe.style.width = `${SCALE_PROBE_PX}px`;
9
+ probe.style.height = `${SCALE_PROBE_PX}px`;
10
+ probe.style.visibility = "hidden";
11
+ probe.style.pointerEvents = "none";
12
+ root.appendChild(probe);
13
+ let width = 0;
14
+ let height = 0;
15
+ try {
16
+ const rect = probe.getBoundingClientRect();
17
+ width = rect.width;
18
+ height = rect.height;
19
+ } finally {
20
+ probe.remove();
21
+ }
22
+ const scale = Math.max(width, height) / SCALE_PROBE_PX;
23
+ if (!(scale > 0)) return current;
24
+ const dpr = typeof devicePixelRatio === "number" ? devicePixelRatio : 1;
25
+ const next = dpr * scale;
26
+ if (current > 0 && Math.abs(next - current) < current * PIXEL_RATIO_DEADBAND) return current;
27
+ return next;
28
+ }
1
29
  const RUNTIME_PI = 3.1415927;
2
30
  const RAD$3 = RUNTIME_PI / 180;
3
31
  const RUNTIME_DEG = 180 / RUNTIME_PI;
@@ -3819,6 +3847,81 @@ function posedBones(doc, timelines, t, plant = {}) {
3819
3847
  return bone2;
3820
3848
  });
3821
3849
  }
3850
+ const LOCAL_CHANNELS = { rotation: 0, x: 0, y: 0, scaleX: 1, scaleY: 1, shearX: 0, shearY: 0 };
3851
+ class StepLocals {
3852
+ constructor(bones, index, setup) {
3853
+ this.bones = bones;
3854
+ this.index = index;
3855
+ this.setup = setup;
3856
+ }
3857
+ read(channel2) {
3858
+ return this.bones[this.index][channel2] ?? LOCAL_CHANNELS[channel2];
3859
+ }
3860
+ write(channel2, value) {
3861
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new CoreInputError(`the adjustment wrote bone "${this.setup.name}" ${channel2} = ${String(value)}, not a finite number`);
3862
+ if (this.bones[this.index] === this.setup) this.bones[this.index] = { ...this.setup };
3863
+ this.bones[this.index][channel2] = value;
3864
+ }
3865
+ get rotation() {
3866
+ return this.read("rotation");
3867
+ }
3868
+ set rotation(v) {
3869
+ this.write("rotation", v);
3870
+ }
3871
+ get x() {
3872
+ return this.read("x");
3873
+ }
3874
+ set x(v) {
3875
+ this.write("x", v);
3876
+ }
3877
+ get y() {
3878
+ return this.read("y");
3879
+ }
3880
+ set y(v) {
3881
+ this.write("y", v);
3882
+ }
3883
+ get scaleX() {
3884
+ return this.read("scaleX");
3885
+ }
3886
+ set scaleX(v) {
3887
+ this.write("scaleX", v);
3888
+ }
3889
+ get scaleY() {
3890
+ return this.read("scaleY");
3891
+ }
3892
+ set scaleY(v) {
3893
+ this.write("scaleY", v);
3894
+ }
3895
+ get shearX() {
3896
+ return this.read("shearX");
3897
+ }
3898
+ set shearX(v) {
3899
+ this.write("shearX", v);
3900
+ }
3901
+ get shearY() {
3902
+ return this.read("shearY");
3903
+ }
3904
+ set shearY(v) {
3905
+ this.write("shearY", v);
3906
+ }
3907
+ }
3908
+ function adjustLocals(doc, bones, adjust) {
3909
+ const views = /* @__PURE__ */ new Map();
3910
+ const names = doc.bones.map((b) => b.name);
3911
+ adjust({
3912
+ names,
3913
+ bone(name) {
3914
+ let view = views.get(name);
3915
+ if (view === void 0) {
3916
+ const index = names.indexOf(name);
3917
+ if (index < 0) throw new CoreInputError(`the adjustment asked for bone ${JSON.stringify(name)}, which is not one of this document's bones`);
3918
+ view = new StepLocals(bones, index, doc.bones[index]);
3919
+ views.set(name, view);
3920
+ }
3921
+ return view;
3922
+ }
3923
+ });
3924
+ }
3822
3925
  const clamp01 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
3823
3926
  function posedSlots(doc, timelines, t, plant = {}, sliders = [], placeholders) {
3824
3927
  const resolve = plant.shown ?? shownAttachment;
@@ -3895,6 +3998,7 @@ function stepRows(posed) {
3895
3998
  function posedBoneStep(doc, timelines, t, plant, constraints, sliders, step) {
3896
3999
  const active = activeBones(doc);
3897
4000
  const bones = posedBones(doc, timelines, t, plant);
4001
+ if (step?.adjust !== void 0) adjustLocals(doc, bones, step.adjust);
3898
4002
  let world = (plant.evaluate ?? worldTransforms)(bones, active);
3899
4003
  if (constraints !== void 0 && step !== void 0) {
3900
4004
  const records = stepPhysicsRecords(pathDeformed(doc, posedRecords(constraintRecords(doc), constraints, t), timelines, t, plant), constraints.physicsKeyed ?? [], t, active, step.ctx, step.before);
@@ -4819,16 +4923,16 @@ function animationOf(doc, animation) {
4819
4923
  if (anim === void 0) throw new CoreInputError(`animation "${animation}" is not one of this document's [${doc.animations.map((a) => a.name).join(", ")}]`);
4820
4924
  return anim;
4821
4925
  }
4822
- function openWalk(doc, anim, plant, reset, mode, shape) {
4926
+ function openWalk(doc, anim, plant, reset, mode, shape, adjust) {
4823
4927
  const why = constraintsAbsentWhy(doc) ?? pathAnimationsWhy(doc) ?? steppedPreviousPassWhy(doc);
4824
4928
  if (why !== null) throw new CoreInputError(`the raw walk leaves the bones out: ${why}`);
4825
4929
  const ctx = freshStepContext(plant.physicsStep);
4826
4930
  if (mode.loop && mode.wrapResets !== false) ctx.loop = true;
4827
- const track = { doc, anim, duration: anim.timelines.duration, mode, plant, raw: { ...plant, ...roundPlant(mode) }, resolve: plant.shown ?? shownAttachment, shape, ctx, trackTime: 0, last: -1 };
4931
+ const track = { doc, anim, duration: anim.timelines.duration, mode, plant, raw: { ...plant, ...roundPlant(mode) }, resolve: plant.shown ?? shownAttachment, shape, ctx, adjust, trackTime: 0, last: -1 };
4828
4932
  return { track, first: stepWalk(track, 0, true) };
4829
4933
  }
4830
4934
  function stepWalk(track, dt, first = false) {
4831
- const { doc, anim, duration, mode, plant, raw, resolve, shape, ctx } = track;
4935
+ const { doc, anim, duration, mode, plant, raw, resolve, shape, ctx, adjust } = track;
4832
4936
  track.trackTime += dt;
4833
4937
  const trackTime = track.trackTime;
4834
4938
  const last = track.last;
@@ -4836,7 +4940,7 @@ function stepWalk(track, dt, first = false) {
4836
4940
  const before = ctx.time;
4837
4941
  ctx.time += mode.clock === void 0 ? dt : mode.clock(dt, t - (first ? 0 : Math.max(last, 0)));
4838
4942
  const sliders = [];
4839
- const world = shape.rows ? posedBoneWorld(doc, anim.timelines, t, raw, anim.constraints, sliders, { ctx, before }).world : posedBoneWorldAlone(doc, anim.timelines, t, raw, anim.constraints, sliders, { ctx, before });
4943
+ const world = shape.rows ? posedBoneWorld(doc, anim.timelines, t, raw, anim.constraints, sliders, { ctx, before, adjust }).world : posedBoneWorldAlone(doc, anim.timelines, t, raw, anim.constraints, sliders, { ctx, before, adjust });
4840
4944
  if (first) ctx.phase = "update";
4841
4945
  const placeholders = /* @__PURE__ */ new Map();
4842
4946
  const slots = posedSlots(doc, anim.timelines, t, raw, sliders, placeholders);
@@ -4856,8 +4960,8 @@ function stepWalk(track, dt, first = false) {
4856
4960
  track.last = t;
4857
4961
  return pose;
4858
4962
  }
4859
- function openRawTrack(doc, animation, plant, reset, mode) {
4860
- return openWalk(doc, animationOf(doc, animation), plant, reset, mode, RAW_SHAPE);
4963
+ function openRawTrack(doc, animation, plant, reset, mode, adjust) {
4964
+ return openWalk(doc, animationOf(doc, animation), plant, reset, mode, RAW_SHAPE, adjust);
4861
4965
  }
4862
4966
  function stepRawTrack(track, dt) {
4863
4967
  return stepWalk(track, dt);
@@ -4866,7 +4970,8 @@ const HELD = { loop: false, keep: false };
4866
4970
  const LOOPED = { loop: true, keep: false, live: true };
4867
4971
  function openTrack(doc, animation, options, plant = {}) {
4868
4972
  if (typeof options !== "object" || options === null || typeof options.loop !== "boolean") throw new CoreInputError(`the live track's options.loop is ${JSON.stringify(options?.loop)}, not true or false`);
4869
- const { track, first } = openRawTrack(doc, animation, plant, options.reset, options.loop ? LOOPED : HELD);
4973
+ if (options.adjust !== void 0 && typeof options.adjust !== "function") throw new CoreInputError(`the live track's options.adjust is ${typeof options.adjust}, not a function`);
4974
+ const { track, first } = openRawTrack(doc, animation, plant, options.reset, options.loop ? LOOPED : HELD, options.adjust);
4870
4975
  return new Track(track, first);
4871
4976
  }
4872
4977
  class Track {
@@ -4896,7 +5001,7 @@ class Track {
4896
5001
  this.latest = pose.animationTime;
4897
5002
  return pose;
4898
5003
  } catch (err) {
4899
- if (err instanceof CoreInputError) this.refused = `${n} (${err.message})`;
5004
+ this.refused = `${n} (${err instanceof Error ? err.message : String(err)})`;
4900
5005
  throw err;
4901
5006
  }
4902
5007
  }
@@ -5661,8 +5766,6 @@ function getMeshGlBlitter() {
5661
5766
  const regionVertices = new Float32Array(8);
5662
5767
  const SVG_NS = "http://www.w3.org/2000/svg";
5663
5768
  let tintFilterSeq = 0;
5664
- const SCALE_PROBE_PX = 100;
5665
- const PIXEL_RATIO_DEADBAND = 1e-3;
5666
5769
  function expandPoint(x, y, cx, cy, amount) {
5667
5770
  const dx = x - cx;
5668
5771
  const dy = y - cy;
@@ -5873,32 +5976,8 @@ class DomRenderer {
5873
5976
  * @returns the pixel ratio now in effect (the current one if nothing moved).
5874
5977
  */
5875
5978
  syncPixelRatio() {
5876
- const probe = document.createElement("div");
5877
- probe.style.position = "absolute";
5878
- probe.style.left = "0";
5879
- probe.style.top = "0";
5880
- probe.style.width = `${SCALE_PROBE_PX}px`;
5881
- probe.style.height = `${SCALE_PROBE_PX}px`;
5882
- probe.style.visibility = "hidden";
5883
- probe.style.pointerEvents = "none";
5884
- this.root.appendChild(probe);
5885
- let width = 0;
5886
- let height = 0;
5887
- try {
5888
- const rect = probe.getBoundingClientRect();
5889
- width = rect.width;
5890
- height = rect.height;
5891
- } finally {
5892
- probe.remove();
5893
- }
5894
- const scale = Math.max(width, height) / SCALE_PROBE_PX;
5895
- if (!(scale > 0)) return this.pixelRatio;
5896
- const dpr = typeof devicePixelRatio === "number" ? devicePixelRatio : 1;
5897
- const next = dpr * scale;
5898
- const current = this.pixelRatio;
5899
- if (current > 0 && Math.abs(next - current) < current * PIXEL_RATIO_DEADBAND) return current;
5900
- this.pixelRatio = next;
5901
- return next;
5979
+ this.pixelRatio = syncedPixelRatio(this.root, this.pixelRatio);
5980
+ return this.pixelRatio;
5902
5981
  }
5903
5982
  /**
5904
5983
  * Draws one frame. Slots the frame does not carry — no attachment, a
@@ -6563,7 +6642,12 @@ class CanvasRenderer {
6563
6642
  this.ctx = canvas.getContext("2d");
6564
6643
  root.appendChild(canvas);
6565
6644
  }
6566
- /** Backing-store pixels per root CSS pixel; defaults to the device pixel ratio. Fold a root scale in, as for the DOM tier. */
6645
+ /**
6646
+ * Backing-store pixels per root CSS pixel; defaults to the device pixel
6647
+ * ratio. A root under a CSS-scaled ancestor rasters at the wrong resolution
6648
+ * until the scale is folded in — `syncPixelRatio()` measures it, as for the
6649
+ * DOM tier. The next `render` sizes the backing store to the new ratio.
6650
+ */
6567
6651
  pixelRatio = typeof devicePixelRatio === "number" ? devicePixelRatio : 1;
6568
6652
  /** Apply the clips the frame carries (default). False draws every slot unclipped and counts the clips in `clipSkipCount`. */
6569
6653
  clipping = true;
@@ -6616,6 +6700,19 @@ class CanvasRenderer {
6616
6700
  nextSig = new Float64Array(256);
6617
6701
  nextRefs = [];
6618
6702
  /** Grows the automatic viewport to cover `box` (world units, Y up) ahead of the frames reaching it. */
6703
+ /**
6704
+ * Measures the root's effective on-screen scale and sets `pixelRatio` to
6705
+ * `devicePixelRatio × scale`, returning the ratio now in effect — the same
6706
+ * call, the same meaning and the same deadband as `DomRenderer`'s, so code
6707
+ * written against `player.renderer` survives a `mode` change. One forced
6708
+ * layout per call (a hidden box appended to the root, read, removed), which
6709
+ * is why the renderer never calls it for you. The backing store follows on
6710
+ * the next `render`; a root that is not laid out leaves the ratio alone.
6711
+ */
6712
+ syncPixelRatio() {
6713
+ this.pixelRatio = syncedPixelRatio(this.root, this.pixelRatio);
6714
+ return this.pixelRatio;
6715
+ }
6619
6716
  reserve(box) {
6620
6717
  this.growTo(box.x, -(box.y + box.height), box.x + box.width, -box.y);
6621
6718
  }
@@ -7221,6 +7318,11 @@ class RigPlayer {
7221
7318
  paused = false;
7222
7319
  pose = null;
7223
7320
  setup = null;
7321
+ adjustFn = null;
7322
+ /** Handed to every track the player opens; reads the current `adjust` so setting it later needs no reopen. */
7323
+ adjustHook = (locals) => {
7324
+ if (this.adjustFn !== null) this.adjustFn(locals);
7325
+ };
7224
7326
  listeners = {
7225
7327
  event: /* @__PURE__ */ new Set(),
7226
7328
  complete: /* @__PURE__ */ new Set()
@@ -7234,6 +7336,7 @@ class RigPlayer {
7234
7336
  this.root = root;
7235
7337
  this.assets = assets;
7236
7338
  this.meshBackend = options.meshBackend;
7339
+ this.adjustFn = options.adjust ?? null;
7237
7340
  this.active = this.create(options.mode ?? "dom");
7238
7341
  }
7239
7342
  /**
@@ -7342,6 +7445,33 @@ class RigPlayer {
7342
7445
  if (this.pose === null) return;
7343
7446
  this.renderer.render(this.posedFrame());
7344
7447
  }
7448
+ /**
7449
+ * The per-pose adjustment of bone locals (`BoneAdjust`), or null for none.
7450
+ * It is applied by every track the player opens — `play`, the reopen inside
7451
+ * `seek` — and by the pose drawn again after `mode` changes, on every pose
7452
+ * the animation is applied to, the first one included. Setting it re-poses
7453
+ * the pose the player holds at once (`repose`), so a held or paused player
7454
+ * shows the change on its next `draw` without a step.
7455
+ */
7456
+ get adjust() {
7457
+ return this.adjustFn;
7458
+ }
7459
+ set adjust(fn) {
7460
+ if (fn !== null && typeof fn !== "function") throw new Error(`adjust must be a function or null, got ${typeof fn}`);
7461
+ this.adjustFn = fn;
7462
+ this.repose();
7463
+ }
7464
+ /**
7465
+ * Poses the held pose again at the same track time, through the current
7466
+ * `adjust`, without stepping, firing or drawing. A paused player and a zero
7467
+ * step re-pose nothing, so a caller whose adjustment reads its own state
7468
+ * (a mouth driven while the body is held) calls this when that state
7469
+ * changed, then `draw`. Nothing before `play`.
7470
+ */
7471
+ repose() {
7472
+ if (this.track === null || this.pose === null) return;
7473
+ this.pose = this.track.step(0);
7474
+ }
7345
7475
  /**
7346
7476
  * Where `name` is in the pose the player holds — the pose of the last
7347
7477
  * `advance`/`frame`/`seek`, or the setup pose before `play`. Read off the
@@ -7427,7 +7557,7 @@ class RigPlayer {
7427
7557
  this.pose = null;
7428
7558
  }
7429
7559
  open() {
7430
- this.track = openTrack(this.view, this.animation, { loop: this.loop, reset: "animation" });
7560
+ this.track = openTrack(this.view, this.animation, { loop: this.loop, reset: "animation", adjust: this.adjustHook });
7431
7561
  this.pose = this.track.first;
7432
7562
  }
7433
7563
  /**