rig-play 1.8.2 → 1.9.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
@@ -38,7 +38,21 @@ links to either earlier name keep working.
38
38
 
39
39
  ### Measured
40
40
 
41
- Measured on the 0.x line, on the spineboy exports it then played (PoC, Apple silicon —
41
+ **The element mode's mesh backend is `'webgl'` by default since 1.9 (#109)**, read off
42
+ macOS Safari on 2026-10-13 (1.8.2, gallery rig `look-packed`: 4 meshes, 464
43
+ triangles, `sweep`; the demo's stats line after a 30 s settle; the Mac was also
44
+ serving the builds, so absolute fps is low and only the comparison is the point —
45
+ readings verbatim on #25):
46
+
47
+ | macOS Safari | 1 rig | 10 rigs (4,640 triangles) |
48
+ | --- | --: | --: |
49
+ | canvas2d mesh backend | 21–26 fps | 2–3 fps |
50
+ | webgl mesh backend | 60 fps | 58 fps |
51
+
52
+ Nothing is claimed here for mobile browsers: no phone or tablet has been measured
53
+ on the 1.x line.
54
+
55
+ The numbers below are older: measured on the 0.x line, on the spineboy exports it then played (PoC, Apple silicon —
42
56
  headless and on-device numbers are labeled, they do **not** substitute for each other).
43
57
  The renderer tiers they describe carried over; they have not been re-measured since the
44
58
  player moved to rigc's model (#60):
@@ -150,8 +164,8 @@ default stays `dom`.
150
164
  37 fps, meshed ×10 = 3–4 fps with JS flat at ~4–5 ms — put the real cost in the
151
165
  GPU process: Safari antialiases canvas2d **clip paths**, so the per-triangle clip
152
166
  mapping pays a per-triangle AA-mask tax (the same AA that caused the seam cracks)
153
- - ✅ Optional WebGL blit backend for the mesh tier: `renderer.meshBackend =
154
- 'webgl'` (default stays `'canvas2d'`). All dirty meshes are shelf-packed into
167
+ - ✅ WebGL blit backend for the mesh tier, the default since 1.9 (#109;
168
+ `renderer.meshBackend = 'canvas2d'` keeps the 2d raster). All dirty meshes are shelf-packed into
155
169
  **one shared offscreen WebGL context** (module-level — browsers cap contexts at
156
170
  ~16), drawn as textured triangles with premultiplied alpha, then rect-blitted
157
171
  onto the same per-part canvases with an unclipped `drawImage` — cheap on Safari.
@@ -586,12 +600,19 @@ onto shared pages instead. Both play here, unchanged:
586
600
  (Σ width × height), computed on demand. This is what `pixelRatio` moves
587
601
  quadratically, and the cheapest way to see an oversampling stage; the demo
588
602
  prints it in the stats line as `backing N Mpx`.
589
- - `renderer.meshBackend` — `'canvas2d'` (default) or `'webgl'`; same output, but
590
- heavy deforming scenes on Safari want `'webgl'` (see Measured above). Falls back
591
- to canvas2d automatically when WebGL is unavailable. Switching re-rasters every
603
+ - `renderer.meshBackend` — `'webgl'` (default since 1.9) or `'canvas2d'`; same
604
+ output, and on macOS Safari webgl holds 58–60 fps where canvas2d reads 2–26
605
+ (see Measured above). Falls back to canvas2d automatically when WebGL is
606
+ unavailable or the shared context is lost; `meshBackendActive` says which drew. Switching re-rasters every
592
607
  mesh once (no reallocation), so it is fine to expose as a user setting.
593
608
  - `renderer.triangleExpand` — how far (canvas px) each triangle edge's clip is
594
609
  moved outward to close antialiased mesh seams (default 0.5). Also re-rasters every mesh once when changed.
610
+ - `renderer.meshSourceRect` — what a canvas2d mesh triangle is drawn from:
611
+ `'page'` (the whole page) or `'triangle'` (a sub-rect covering its clip). Both
612
+ draw the same picture; the default is `'triangle'` on Linux WebKit, which
613
+ garbles whole-page draws, and `'page'` elsewhere, because macOS Safari ran the
614
+ sub-rect 12–15% slower (#25). Also on `CanvasRenderer` for its canvas2d
615
+ fallback. Re-rasters every mesh once when changed.
595
616
  - `renderer.clipping` — apply the clips the frame carries (default `true`).
596
617
  Which slots a clip covers is decided where the frame is made — the player's
597
618
  adapter walks the draw order the way the runtime's draw loop does (one clip in
@@ -643,6 +664,30 @@ on-device (Chromium, dpr 2, stage under `scale(0.25)`, ~2.2 M CSS px on screen):
643
664
  | 92 meshes | `devicePixelRatio` (2) | 141.1 Mpx | 36–39 |
644
665
  | 92 meshes | `dpr × zoom` (0.5) | 9.1 Mpx | 60–61 |
645
666
 
667
+ ## Coming from 1.8: meshes draw through WebGL by default
668
+
669
+ From 1.9 the element mode rasterizes its meshes through the one shared WebGL
670
+ context unless told otherwise (`DomRenderer.meshBackend` defaults to `'webgl'`,
671
+ #109). The picture is the same within the parity suite's bounds, the API is
672
+ unchanged, and canvas2d is still drawn wherever WebGL is unavailable or the
673
+ context is lost. What a caller can notice:
674
+
675
+ - The page holds one more WebGL context (one for every mesh of every player, not
676
+ one per player). A page already near the browser's cap of about 16 live
677
+ contexts can lose its oldest one when this one is created.
678
+ - `meshBackendActive` reads `'webgl'` where it read `'canvas2d'`.
679
+ - Frame cost moves from the page to the GPU blit (see *Measured*).
680
+
681
+ To keep 1.8's raster, set it back, up front or on a live player:
682
+
683
+ ```ts
684
+ const player = new RigPlayer(root, assets, { meshBackend: 'canvas2d' });
685
+ // or, on a renderer you hold:
686
+ renderer.meshBackend = 'canvas2d';
687
+ ```
688
+
689
+ The canvas mode was already webgl by default and does not change.
690
+
646
691
  ## Coming from spine-html 0.8
647
692
 
648
693
  This is not a drop-in upgrade. 0.8 drew a Spine export (`.json` or `.skel`, plus its
@@ -695,7 +740,7 @@ name, and unloading is still elements first, bitmaps second.
695
740
  | `renderer.pixelRatio` | `player.renderer.pixelRatio` | On both renderers. Carried over when `player.mode` changes. |
696
741
  | `renderer.syncPixelRatio()` | `player.renderer.syncPixelRatio()` | On both renderers, the same meaning and the same deadband (since 1.3.0; before it, DOM mode only). |
697
742
  | `renderer.meshBackingPixels` | `DomRenderer.meshBackingPixels` | DOM mode only. |
698
- | `renderer.meshBackend`, `meshBackendActive`, type `MeshBackend` | `DomRenderer.meshBackend`, `meshBackendActive`, type `MeshBackend` | Same values (`'canvas2d'` default, `'webgl'`). Also settable up front as `RigPlayerOptions.meshBackend`. |
743
+ | `renderer.meshBackend`, `meshBackendActive`, type `MeshBackend` | `DomRenderer.meshBackend`, `meshBackendActive`, type `MeshBackend` | Same values; the default is `'webgl'` since 1.9 (`'canvas2d'` before). Also settable up front as `RigPlayerOptions.meshBackend`. |
699
744
  | `renderer.triangleExpand` | `DomRenderer.triangleExpand` | Same default (0.5). |
700
745
  | `renderer.clipping` | `player.renderer.clipping` | On both renderers. Carried over when `player.mode` changes. |
701
746
  | `clipCount`, `clipSkipCount`, `clipWriteCount` | same names on `DomRenderer` | `clipSkipCount` counts less than it did: a second clip met while one is in force, and a clip on an inactive bone, no longer reach the frame, so they are not counted. |
@@ -833,7 +878,8 @@ scenes (floors 0.585–1.553%, Chromium and WebKit). The DOM tier's two mesh
833
878
  backends get the same A/B (`?backend=canvas2d` against `?backend=webgl`, at most
834
879
  0.5%). Hairline seams are guarded by a deterministic canary (`?expand=0` must
835
880
  change the canvas2d raster), the canvas2d source sub-rect by another (expand 32
836
- against 8), and counter tests pin the dirty-skip / grow-only-backing /
881
+ against 8, forced to the sub-rect), the two source rects by an A/B that must
882
+ match exactly, and counter tests pin the dirty-skip / grow-only-backing /
837
883
  clip-counter invariants plus the region corner order (BL, UL, UR, BR) and the
838
884
  turned-region UVs, read off rig-c's pose against hand-written numbers.
839
885
 
@@ -1,3 +1,4 @@
1
+ import { type MeshSourceRect } from './DomRenderer.js';
1
2
  import type { PosedFrame } from './posedFrame.js';
2
3
  /** What actually drew the last frame of a `CanvasRenderer`. */
3
4
  export type CanvasBackend = 'webgl' | 'canvas2d';
@@ -69,6 +70,8 @@ export declare class CanvasRenderer {
69
70
  viewport: CanvasViewport | null;
70
71
  /** The backend to draw with: 'webgl' (default) through the shared context, or 'canvas2d' to force the fallback. */
71
72
  backend: CanvasBackend;
73
+ /** What the canvas2d fallback draws each mesh triangle from — as `DomRenderer.meshSourceRect`, with the same default. */
74
+ meshSourceRect: MeshSourceRect;
72
75
  /** What drew the last frame (or would have, had it not been reused). */
73
76
  backendActive: CanvasBackend;
74
77
  /** The visible canvas — the renderer's one element in the root. */
@@ -1 +1 @@
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
+ {"version":3,"file":"CanvasRenderer.d.ts","sourceRoot":"","sources":["../src/CanvasRenderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAA+C,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGpG,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;IAuEvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAvExB;;;;;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,yHAAyH;IACzH,cAAc,EAAE,cAAc,CAA2B;IACzD,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;IAqExB,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"}
@@ -2,6 +2,12 @@ import { type RegionImage } from './DomTexture.js';
2
2
  import type { PosedFrame } from './posedFrame.js';
3
3
  /** Rasterizer used for the mesh (deform) tier. */
4
4
  export type MeshBackend = 'canvas2d' | 'webgl';
5
+ /**
6
+ * What a canvas2d mesh triangle is drawn from: `'triangle'`, a source sub-rect
7
+ * of the page covering the triangle's clip, or `'page'`, the whole page. Both
8
+ * draw the same picture under the same clip; they differ in cost by engine.
9
+ */
10
+ export type MeshSourceRect = 'triangle' | 'page';
5
11
  /**
6
12
  * Renders a posed frame (`PosedFrame`) as DOM, split by slot kind:
7
13
  *
@@ -88,6 +94,12 @@ export declare class DomRenderer {
88
94
  * to see them.
89
95
  */
90
96
  triangleExpand: number;
97
+ /**
98
+ * What the canvas2d mesh backend draws each triangle from (`MeshSourceRect`):
99
+ * by default the sub-rect on Linux WebKit and the whole page elsewhere.
100
+ * Re-rasters every mesh once when changed.
101
+ */
102
+ meshSourceRect: MeshSourceRect;
91
103
  /**
92
104
  * Mesh-canvas backing-store pixels per CSS pixel. Defaults to the device
93
105
  * pixel ratio. If the caller scales the root element, fold that scale in
@@ -97,9 +109,9 @@ export declare class DomRenderer {
97
109
  */
98
110
  pixelRatio: number;
99
111
  /**
100
- * Rasterizer for the mesh (deform) tier. 'canvas2d' (default) maps each
101
- * triangle with clip+transform+drawImage directly on the per-part canvas.
102
- * 'webgl' rasterizes every dirty mesh into one shared offscreen WebGL
112
+ * Rasterizer for the mesh (deform) tier. 'canvas2d' maps each triangle
113
+ * with clip+transform+drawImage directly on the per-part canvas. 'webgl'
114
+ * (default) rasterizes every dirty mesh into one shared offscreen WebGL
103
115
  * canvas and rect-blits each mesh back onto its per-part canvas — the DOM
104
116
  * structure and all element-level behavior (z-index interleave, tint
105
117
  * filter, mix-blend-mode, dirty-skip) are identical, only the raster step
@@ -108,7 +120,8 @@ export declare class DomRenderer {
108
120
  * process that rAF-limits heavy scenes; GL rasterizes shared edges
109
121
  * seamlessly (no clip, no crack overdraw) and the blit is an unclipped
110
122
  * rect copy. Falls back to 'canvas2d' when WebGL is unavailable or the
111
- * shared context is lost — see meshBackendActive.
123
+ * shared context is lost — see meshBackendActive. The default since 1.9
124
+ * (#109); before it, 'canvas2d'. Set 'canvas2d' to keep the 2d raster.
112
125
  */
113
126
  meshBackend: MeshBackend;
114
127
  /** Backend that actually rasterized the mesh tier during the last render(). */
@@ -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
@@ -1,5 +1,5 @@
1
1
  export { type CanvasBackend, CanvasRenderer, type CanvasViewport } from './CanvasRenderer.js';
2
- export { DomRenderer, type MeshBackend } from './DomRenderer.js';
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
4
  export { type LoadModelOptions, loadModel, type ModelAssets, type ModelDocument, type RegionLoading } 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 RigEvent, RigPlayer, type RigPlayerOptions, type SlotFilter, type TrackEntry } from './player.js';
@@ -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,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,QAAQ,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACjR,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,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,QAAQ,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACjR,YAAY,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -6842,6 +6842,10 @@ function getMeshGlBlitter() {
6842
6842
  }
6843
6843
  return shared && !shared.lost ? shared : null;
6844
6844
  }
6845
+ function defaultMeshSourceRect(userAgent = typeof navigator === "object" ? navigator.userAgent : "") {
6846
+ const linuxWebKit = /AppleWebKit/.test(userAgent) && /Linux|X11/.test(userAgent) && !/Android|Chrome|Chromium|CriOS|Edg/.test(userAgent);
6847
+ return linuxWebKit ? "triangle" : "page";
6848
+ }
6845
6849
  const regionVertices = new Float32Array(8);
6846
6850
  const SVG_NS = "http://www.w3.org/2000/svg";
6847
6851
  let tintFilterSeq = 0;
@@ -6965,6 +6969,12 @@ class DomRenderer {
6965
6969
  * to see them.
6966
6970
  */
6967
6971
  triangleExpand = 0.5;
6972
+ /**
6973
+ * What the canvas2d mesh backend draws each triangle from (`MeshSourceRect`):
6974
+ * by default the sub-rect on Linux WebKit and the whole page elsewhere.
6975
+ * Re-rasters every mesh once when changed.
6976
+ */
6977
+ meshSourceRect = defaultMeshSourceRect();
6968
6978
  /**
6969
6979
  * Mesh-canvas backing-store pixels per CSS pixel. Defaults to the device
6970
6980
  * pixel ratio. If the caller scales the root element, fold that scale in
@@ -6974,9 +6984,9 @@ class DomRenderer {
6974
6984
  */
6975
6985
  pixelRatio = typeof devicePixelRatio === "number" ? devicePixelRatio : 1;
6976
6986
  /**
6977
- * Rasterizer for the mesh (deform) tier. 'canvas2d' (default) maps each
6978
- * triangle with clip+transform+drawImage directly on the per-part canvas.
6979
- * 'webgl' rasterizes every dirty mesh into one shared offscreen WebGL
6987
+ * Rasterizer for the mesh (deform) tier. 'canvas2d' maps each triangle
6988
+ * with clip+transform+drawImage directly on the per-part canvas. 'webgl'
6989
+ * (default) rasterizes every dirty mesh into one shared offscreen WebGL
6980
6990
  * canvas and rect-blits each mesh back onto its per-part canvas — the DOM
6981
6991
  * structure and all element-level behavior (z-index interleave, tint
6982
6992
  * filter, mix-blend-mode, dirty-skip) are identical, only the raster step
@@ -6985,11 +6995,12 @@ class DomRenderer {
6985
6995
  * process that rAF-limits heavy scenes; GL rasterizes shared edges
6986
6996
  * seamlessly (no clip, no crack overdraw) and the blit is an unclipped
6987
6997
  * rect copy. Falls back to 'canvas2d' when WebGL is unavailable or the
6988
- * shared context is lost — see meshBackendActive.
6998
+ * shared context is lost — see meshBackendActive. The default since 1.9
6999
+ * (#109); before it, 'canvas2d'. Set 'canvas2d' to keep the 2d raster.
6989
7000
  */
6990
- meshBackend = "canvas2d";
7001
+ meshBackend = "webgl";
6991
7002
  /** Backend that actually rasterized the mesh tier during the last render(). */
6992
- meshBackendActive = "canvas2d";
7003
+ meshBackendActive = "webgl";
6993
7004
  views = /* @__PURE__ */ new Map();
6994
7005
  /** Counts render() calls: the stamp a view drawn this frame carries (`SlotView.drawnIn`). */
6995
7006
  frameNumber = 0;
@@ -7237,7 +7248,7 @@ class DomRenderer {
7237
7248
  const ratio = this.pixelRatio;
7238
7249
  const uvs = slot.uvs;
7239
7250
  const triangles = slot.triangles;
7240
- let dirty = view.meshUvs !== uvs || view.meshTriangles !== triangles || view.meshPage !== page || view.meshSequenceIndex !== sequenceIndex || view.meshExpand !== this.triangleExpand || view.meshVertexCount !== count || view.meshBackendDrawn !== this.meshBackendActive;
7251
+ let dirty = view.meshUvs !== uvs || view.meshTriangles !== triangles || view.meshPage !== page || view.meshSequenceIndex !== sequenceIndex || view.meshExpand !== this.triangleExpand || view.meshSourceRect !== this.meshSourceRect || view.meshVertexCount !== count || view.meshBackendDrawn !== this.meshBackendActive;
7241
7252
  const needW = Math.max(1, Math.round(w * ratio));
7242
7253
  const needH = Math.max(1, Math.round(h * ratio));
7243
7254
  const ratioChanged = view.meshRatio !== ratio;
@@ -7277,6 +7288,7 @@ class DomRenderer {
7277
7288
  view.meshPage = page;
7278
7289
  view.meshSequenceIndex = sequenceIndex;
7279
7290
  view.meshExpand = this.triangleExpand;
7291
+ view.meshSourceRect = this.meshSourceRect;
7280
7292
  view.meshVertexCount = count;
7281
7293
  view.meshBackendDrawn = this.meshBackendActive;
7282
7294
  if (this.meshBackendActive === "webgl") {
@@ -7409,7 +7421,7 @@ class DomRenderer {
7409
7421
  * class of offset the `uv * size` addressing removes.
7410
7422
  */
7411
7423
  drawTriangle(ctx, img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) {
7412
- drawTexturedTriangle(ctx, img, this.triangleExpand, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
7424
+ drawTexturedTriangle(ctx, img, this.triangleExpand, this.meshSourceRect, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
7413
7425
  }
7414
7426
  // --- clipping tier ---------------------------------------------------------
7415
7427
  /**
@@ -7635,6 +7647,7 @@ class DomRenderer {
7635
7647
  meshPage: null,
7636
7648
  meshSequenceIndex: -1,
7637
7649
  meshExpand: -1,
7650
+ meshSourceRect: "",
7638
7651
  meshVertexCount: -1,
7639
7652
  meshBackendDrawn: "",
7640
7653
  meshVertices: new Float64Array(0),
@@ -7653,7 +7666,7 @@ class DomRenderer {
7653
7666
  this.setClipPath(view, "");
7654
7667
  }
7655
7668
  }
7656
- function drawTexturedTriangle(ctx, img, expand, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) {
7669
+ function drawTexturedTriangle(ctx, img, expand, sourceRect, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) {
7657
7670
  const corners = offsetTriangle(x0, y0, x1, y1, x2, y2, expand);
7658
7671
  const px0 = corners[0], py0 = corners[1];
7659
7672
  const px1 = corners[2], py1 = corners[3];
@@ -7676,6 +7689,14 @@ function drawTexturedTriangle(ctx, img, expand, x0, y0, u0, v0, x1, y1, u1, v1,
7676
7689
  const d = (eu1 * ey2 - eu2 * ey1) * det;
7677
7690
  const e = x0 - a * u0 - c * v0;
7678
7691
  const f = y0 - b * u0 - d * v0;
7692
+ if (sourceRect === "page") {
7693
+ ctx.save();
7694
+ ctx.transform(a, b, c, d, e, f);
7695
+ ctx.clip();
7696
+ ctx.drawImage(img, 0, 0);
7697
+ ctx.restore();
7698
+ return;
7699
+ }
7679
7700
  let minU = Math.min(u0, u1, u2);
7680
7701
  let maxU = Math.max(u0, u1, u2);
7681
7702
  let minV = Math.min(v0, v1, v2);
@@ -7767,6 +7788,8 @@ class CanvasRenderer {
7767
7788
  viewport = null;
7768
7789
  /** The backend to draw with: 'webgl' (default) through the shared context, or 'canvas2d' to force the fallback. */
7769
7790
  backend = "webgl";
7791
+ /** What the canvas2d fallback draws each mesh triangle from — as `DomRenderer.meshSourceRect`, with the same default. */
7792
+ meshSourceRect = defaultMeshSourceRect();
7770
7793
  /** What drew the last frame (or would have, had it not been reused). */
7771
7794
  backendActive = "webgl";
7772
7795
  /** The visible canvas — the renderer's one element in the root. */
@@ -7940,7 +7963,8 @@ class CanvasRenderer {
7940
7963
  this.nextSig = grown;
7941
7964
  }
7942
7965
  };
7943
- need(8);
7966
+ need(9);
7967
+ sig[n++] = this.meshSourceRect === "triangle" ? 1 : 0;
7944
7968
  sig[n++] = this.left;
7945
7969
  sig[n++] = this.top;
7946
7970
  sig[n++] = this.backingW;
@@ -8155,6 +8179,7 @@ class CanvasRenderer {
8155
8179
  ctx,
8156
8180
  source,
8157
8181
  0.5,
8182
+ this.meshSourceRect,
8158
8183
  X(vertices[i0]),
8159
8184
  Y(vertices[i0 + 1]),
8160
8185
  uvs[i0] * uw,