rig-play 1.10.0 → 1.10.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/README.md CHANGED
@@ -131,9 +131,11 @@ default stays `dom`.
131
131
  not expressible this way and stays out of scope
132
132
  - ✅ DPR-aware mesh canvas backing store: `renderer.pixelRatio` (defaults to
133
133
  `devicePixelRatio`; if you scale the root element, fold that scale in)
134
- - ✅ Dirty-skip: a mesh whose canvas-space vertices didn't change reuses last frame's
135
- raster — the CSS translate still tracks it, so parts that hold a pose (or move by
136
- whole pixels) pay zero raster. 10 frozen spineboys: WebKit ~141 → ~0.5 ms/frame
134
+ - ✅ Dirty-skip: a mesh whose canvas-space vertices match the last raster reuses it;
135
+ whole-pixel translations allow at most half a Float32 ULP at the current world
136
+ coordinate, strictly less than half a pixel. CSS still tracks the translation, while
137
+ stationary axes stay exact and the comparison anchor changes only on a redraw.
138
+ 10 frozen spineboys: WebKit ~141 → ~0.5 ms/frame
137
139
  - ✅ Clipping attachments as element-level CSS `clip-path`: spine-core's semantics
138
140
  (one active clip at a time, applied from the clip's slot through its end slot
139
141
  inclusive), with the polygon expressed in each element's own local frame — the
@@ -294,6 +296,11 @@ layer answers the same world, and a `seek` replays under the environment as it
294
296
  stands — no history is kept. A rig with no physics ignores both.
295
297
  `tests/readme-page.spec.ts` runs this block in the minimal page.
296
298
 
299
+ The demo's `wind.html` is the same thing with controls: wind and gravity
300
+ sliders, a drag on the stage, and the rig named by `?model=` (the `cloth` test
301
+ rig by default; `bun run dev`, then `/wind.html?model=rigs/<name>/skeleton.model.json`).
302
+ `tests/wind-page.spec.ts` holds it.
303
+
297
304
  The player owns one track: `play(name, { loop })` opens an animation at its first
298
305
  pose, `frame(dt)` steps it (or `advance(dt)` then `draw()`, to time the two
299
306
  apart), `pause()` / `resume()` hold and release it, `timeScale` scales every
@@ -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
@@ -7003,6 +7003,17 @@ function clipNum(v) {
7003
7003
  return Math.round(v * 1e3) / 1e3;
7004
7004
  }
7005
7005
  const CLIP_COORD_LIMIT = 1e9;
7006
+ function float32HalfUlp(value) {
7007
+ if (!Number.isFinite(value)) return 0;
7008
+ return 2 ** (Math.max(-149, Math.floor(Math.log2(Math.abs(value))) - 23) - 1);
7009
+ }
7010
+ function sameMeshCoordinate(relative, cached, world, offset) {
7011
+ if (relative === cached) return true;
7012
+ if (offset === 0) return false;
7013
+ const tolerance = float32HalfUlp(world);
7014
+ const residual = Math.abs(relative - cached);
7015
+ return residual < 0.5 && residual <= tolerance;
7016
+ }
7006
7017
  const BLEND_CSS = {
7007
7018
  Normal: "",
7008
7019
  Additive: "plus-lighter",
@@ -7382,18 +7393,24 @@ class DomRenderer {
7382
7393
  dirty = true;
7383
7394
  }
7384
7395
  const rel = view.meshVertices;
7385
- for (let v = 0; v < count; v += 2) {
7386
- const x = vertices[v] - minX;
7387
- const y = vertices[v + 1] - minY;
7388
- if (rel[v] !== x || rel[v + 1] !== y) dirty = true;
7389
- rel[v] = x;
7390
- rel[v + 1] = y;
7396
+ if (!dirty) {
7397
+ const offsetX = minX - view.meshOriginX;
7398
+ const offsetY = minY - view.meshOriginY;
7399
+ for (let v = 0; v < count && !dirty; v += 2) {
7400
+ dirty = !sameMeshCoordinate(vertices[v] - minX, rel[v], vertices[v], offsetX) || !sameMeshCoordinate(vertices[v + 1] - minY, rel[v + 1], vertices[v + 1], offsetY);
7401
+ }
7391
7402
  }
7392
7403
  this.setTransform(view, `translate(${minX}px,${minY}px)`);
7393
7404
  this.applyClip(view, 1, 0, 0, 1, minX, minY, view.canvasW / ratio, view.canvasH / ratio);
7394
7405
  if (!dirty) {
7395
7406
  this.meshReuseCount++;
7396
7407
  } else {
7408
+ for (let v = 0; v < count; v += 2) {
7409
+ rel[v] = vertices[v] - minX;
7410
+ rel[v + 1] = vertices[v + 1] - minY;
7411
+ }
7412
+ view.meshOriginX = minX;
7413
+ view.meshOriginY = minY;
7397
7414
  view.meshUvs = uvs;
7398
7415
  view.meshTriangles = triangles;
7399
7416
  view.meshPage = page;
@@ -7762,6 +7779,8 @@ class DomRenderer {
7762
7779
  meshVertexCount: -1,
7763
7780
  meshBackendDrawn: "",
7764
7781
  meshVertices: new Float64Array(0),
7782
+ meshOriginX: 0,
7783
+ meshOriginY: 0,
7765
7784
  drawnIn: 0
7766
7785
  };
7767
7786
  this.views.set(slot, view);