@oh-just-another/renderer-canvas 0.59.0 → 0.60.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +3 -0
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/canvas-target.d.ts +6 -1
  5. package/dist/canvas-target.d.ts.map +1 -1
  6. package/dist/canvas-target.js +12 -2
  7. package/dist/canvas-target.js.map +1 -1
  8. package/dist/constants.d.ts +49 -0
  9. package/dist/constants.d.ts.map +1 -1
  10. package/dist/constants.js +49 -0
  11. package/dist/constants.js.map +1 -1
  12. package/dist/hi-dpi.d.ts +10 -0
  13. package/dist/hi-dpi.d.ts.map +1 -1
  14. package/dist/hi-dpi.js +12 -1
  15. package/dist/hi-dpi.js.map +1 -1
  16. package/dist/image-source.d.ts +11 -0
  17. package/dist/image-source.d.ts.map +1 -1
  18. package/dist/image-source.js +20 -0
  19. package/dist/image-source.js.map +1 -1
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -2
  23. package/dist/index.js.map +1 -1
  24. package/dist/layered-canvas.d.ts +7 -1
  25. package/dist/layered-canvas.d.ts.map +1 -1
  26. package/dist/layered-canvas.js +6 -3
  27. package/dist/layered-canvas.js.map +1 -1
  28. package/dist/layered-surface.d.ts +16 -0
  29. package/dist/layered-surface.d.ts.map +1 -1
  30. package/dist/layered-surface.js +50 -13
  31. package/dist/layered-surface.js.map +1 -1
  32. package/dist/recording-target.d.ts +36 -12
  33. package/dist/recording-target.d.ts.map +1 -1
  34. package/dist/recording-target.js +159 -33
  35. package/dist/recording-target.js.map +1 -1
  36. package/dist/tile-compositor.d.ts +43 -1
  37. package/dist/tile-compositor.d.ts.map +1 -1
  38. package/dist/tile-compositor.js +48 -5
  39. package/dist/tile-compositor.js.map +1 -1
  40. package/dist/webgl2-curve.d.ts +11 -0
  41. package/dist/webgl2-curve.d.ts.map +1 -1
  42. package/dist/webgl2-curve.js +147 -32
  43. package/dist/webgl2-curve.js.map +1 -1
  44. package/dist/webgl2-ellipse.d.ts +0 -27
  45. package/dist/webgl2-ellipse.d.ts.map +1 -1
  46. package/dist/webgl2-ellipse.js +17 -12
  47. package/dist/webgl2-ellipse.js.map +1 -1
  48. package/dist/webgl2-msdf-text.d.ts +14 -0
  49. package/dist/webgl2-msdf-text.d.ts.map +1 -1
  50. package/dist/webgl2-msdf-text.js +80 -1
  51. package/dist/webgl2-msdf-text.js.map +1 -1
  52. package/dist/webgl2-rect-batch.d.ts +81 -0
  53. package/dist/webgl2-rect-batch.d.ts.map +1 -0
  54. package/dist/webgl2-rect-batch.js +201 -0
  55. package/dist/webgl2-rect-batch.js.map +1 -0
  56. package/dist/webgl2-stroke.d.ts +6 -30
  57. package/dist/webgl2-stroke.d.ts.map +1 -1
  58. package/dist/webgl2-stroke.js +16 -24
  59. package/dist/webgl2-stroke.js.map +1 -1
  60. package/dist/webgl2-target.d.ts +63 -7
  61. package/dist/webgl2-target.d.ts.map +1 -1
  62. package/dist/webgl2-target.js +308 -193
  63. package/dist/webgl2-target.js.map +1 -1
  64. package/package.json +4 -3
package/dist/constants.js CHANGED
@@ -70,6 +70,32 @@ export const OFFSCREEN_IMAGE_CACHE_CAP = 64;
70
70
  * cost).
71
71
  */
72
72
  export const WEBGL2_IMAGE_TEXTURE_CACHE_CAP = 64;
73
+ /**
74
+ * Cap applied to `window.devicePixelRatio` when sizing canvas bitmaps
75
+ * (`setupHiDpi`, `createLayeredSurface`). Mobile / hi-end displays report
76
+ * DPR 3–4; rendering the full ratio quadruples-to-sixteenfolds the pixel
77
+ * fill cost per layer for visual gains that are imperceptible in a
78
+ * diagram editor (thin strokes, flat fills). Capping at 2 keeps bitmap
79
+ * memory and raster time bounded — text and hairlines render very
80
+ * slightly softer on DPR-3 devices. Range: 1–4; hosts needing exact
81
+ * native sharpness can raise it via `CreateLayeredSurfaceOptions.maxDpr`
82
+ * or by passing an explicit `dpr` to `setupHiDpi`.
83
+ */
84
+ export const MAX_DEVICE_PIXEL_RATIO = 2;
85
+ /**
86
+ * LRU cap on the Loop-Blinn triangulation cache in `webgl2-curve.ts`.
87
+ * Keyed by curve control-point content (renderers emit paths in
88
+ * element-local coordinates, so identical geometry — e.g. every
89
+ * same-size rounded rect — shares one entry, and pan / zoom / drag
90
+ * never invalidate it: the transform is applied in the vertex shader).
91
+ *
92
+ * Each entry stores the packed positions + uvs plus the key floats —
93
+ * a rounded rect (4 triangles) is ≈ 500 bytes, so the cap bounds the
94
+ * cache at a few MB worst-case. On overflow the least-recently-drawn
95
+ * geometry is evicted and re-triangulated on next draw (cheap, no GPU
96
+ * resources involved). Range: 512–16384.
97
+ */
98
+ export const WEBGL2_CURVE_TRIANGULATION_CACHE_CAP = 4096;
73
99
  /**
74
100
  * Lower bound on the polygon approximation of an ellipse. Keeps small
75
101
  * ellipses from collapsing to a coarse hexagon at far zoom. Range: 12–48.
@@ -81,4 +107,27 @@ export const ELLIPSE_MIN_SEGMENTS = 24;
81
107
  * improvement. Range: 256–1024.
82
108
  */
83
109
  export const ELLIPSE_MAX_SEGMENTS = 512;
110
+ /**
111
+ * Initial per-target capacity, in instances, of the sharp-rect instance
112
+ * batcher (`webgl2-rect-batch.ts` `RectBatch`). One frame's worth of
113
+ * same-run rect fills packs into this without a grow; capacity doubles
114
+ * on demand and never shrinks. 256 covers typical grid / background
115
+ * scenes at ~10 KB (40 bytes/instance). Range: 64–4096.
116
+ */
117
+ export const INITIAL_RECT_BATCH_INSTANCES = 256;
118
+ /**
119
+ * LRU cap on the per-atlas MSDF run-width memo (`webgl2-msdf-text.ts`).
120
+ * The em-width of a text run (Σ advance/unitsPerEm) is immutable once its
121
+ * glyphs are cached, so it is memoized keyed by `(fontId, text)`: a
122
+ * repeat `measureText`, or a `measureText` after the same string was
123
+ * drawn, returns in O(1) instead of re-walking the codepoints. Caret
124
+ * positioning and selection geometry call `measureText` on the same
125
+ * label many times per frame, so the hit rate is high.
126
+ *
127
+ * Each entry is a single number keyed by the run string — cheap. 1024
128
+ * covers a large editing session's distinct labels with margin; on
129
+ * overflow the least-recently-measured run is evicted and re-walked on
130
+ * next measure (cheap, no GPU resources). Range: 256–8192.
131
+ */
132
+ export const WEBGL2_MSDF_RUN_WIDTH_CACHE_CAP = 1024;
84
133
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,EAAE,CAAC;AAEjD;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,EAAE,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,IAAI,CAAC;AAEzD;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAExC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,IAAI,CAAC"}
package/dist/hi-dpi.d.ts CHANGED
@@ -19,6 +19,16 @@
19
19
  * subsequent `getContext("webgl2")` returns null. Use `false` for the WebGL2
20
20
  * main canvas in `WebGL2LayeredSurface`; its viewport is set inside
21
21
  * `WebGL2Target` after the GL context is obtained.
22
+ *
23
+ * The default `dpr` is `window.devicePixelRatio` capped at
24
+ * `MAX_DEVICE_PIXEL_RATIO` (see constants.ts). An explicit `dpr` argument
25
+ * is honoured as-is — pass the raw ratio to opt out of the cap.
22
26
  */
23
27
  export declare const setupHiDpi: (canvas: HTMLCanvasElement, width: number, height: number, dpr?: number, setupContext?: boolean) => number;
28
+ /**
29
+ * The live `window.devicePixelRatio` clamped to `maxDpr` (SSR-safe:
30
+ * resolves to 1 when there is no `window`). Callers that re-read the DPR
31
+ * on resize (monitor changes) go through this instead of the raw ratio.
32
+ */
33
+ export declare const cappedDpr: (maxDpr?: number) => number;
24
34
  //# sourceMappingURL=hi-dpi.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hi-dpi.d.ts","sourceRoot":"","sources":["../src/hi-dpi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,UAAU,GACrB,QAAQ,iBAAiB,EACzB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,MAAK,MAAqC,EAC1C,sBAAmB,KAClB,MAuBF,CAAC"}
1
+ {"version":3,"file":"hi-dpi.d.ts","sourceRoot":"","sources":["../src/hi-dpi.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,UAAU,GACrB,QAAQ,iBAAiB,EACzB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,MAAK,MAAoB,EACzB,sBAAmB,KAClB,MAuBF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,SAAQ,MAA+B,KAAG,MACgB,CAAC"}
package/dist/hi-dpi.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { MAX_DEVICE_PIXEL_RATIO } from "./constants.js";
1
2
  /**
2
3
  * Configures a `<canvas>` for hi-DPI rendering. Sets the bitmap size to
3
4
  * `width * dpr` × `height * dpr`, the CSS size to `width` × `height`, and
@@ -19,8 +20,12 @@
19
20
  * subsequent `getContext("webgl2")` returns null. Use `false` for the WebGL2
20
21
  * main canvas in `WebGL2LayeredSurface`; its viewport is set inside
21
22
  * `WebGL2Target` after the GL context is obtained.
23
+ *
24
+ * The default `dpr` is `window.devicePixelRatio` capped at
25
+ * `MAX_DEVICE_PIXEL_RATIO` (see constants.ts). An explicit `dpr` argument
26
+ * is honoured as-is — pass the raw ratio to opt out of the cap.
22
27
  */
23
- export const setupHiDpi = (canvas, width, height, dpr = window.devicePixelRatio || 1, setupContext = true) => {
28
+ export const setupHiDpi = (canvas, width, height, dpr = cappedDpr(), setupContext = true) => {
24
29
  const targetW = Math.round(width * dpr);
25
30
  const targetH = Math.round(height * dpr);
26
31
  const cssW = `${width}px`;
@@ -43,4 +48,10 @@ export const setupHiDpi = (canvas, width, height, dpr = window.devicePixelRatio
43
48
  }
44
49
  return dpr;
45
50
  };
51
+ /**
52
+ * The live `window.devicePixelRatio` clamped to `maxDpr` (SSR-safe:
53
+ * resolves to 1 when there is no `window`). Callers that re-read the DPR
54
+ * on resize (monitor changes) go through this instead of the raw ratio.
55
+ */
56
+ export const cappedDpr = (maxDpr = MAX_DEVICE_PIXEL_RATIO) => Math.min(typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1, maxDpr);
46
57
  //# sourceMappingURL=hi-dpi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hi-dpi.js","sourceRoot":"","sources":["../src/hi-dpi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,MAAyB,EACzB,KAAa,EACb,MAAc,EACd,MAAc,MAAM,CAAC,gBAAgB,IAAI,CAAC,EAC1C,YAAY,GAAG,IAAI,EACX,EAAE;IACV,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC;IAC1B,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC;IAC3B,IACE,MAAM,CAAC,KAAK,KAAK,OAAO;QACxB,MAAM,CAAC,MAAM,KAAK,OAAO;QACzB,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI;QAC3B,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,IAAI,EAC5B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC;IACvB,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC;IACxB,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACzD,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
1
+ {"version":3,"file":"hi-dpi.js","sourceRoot":"","sources":["../src/hi-dpi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,MAAyB,EACzB,KAAa,EACb,MAAc,EACd,MAAc,SAAS,EAAE,EACzB,YAAY,GAAG,IAAI,EACX,EAAE;IACV,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC;IAC1B,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC;IAC3B,IACE,MAAM,CAAC,KAAK,KAAK,OAAO;QACxB,MAAM,CAAC,MAAM,KAAK,OAAO;QACzB,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI;QAC3B,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,IAAI,EAC5B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC;IACvB,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC;IACxB,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACzD,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,SAAiB,sBAAsB,EAAU,EAAE,CAC3E,IAAI,CAAC,GAAG,CAAC,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC"}
@@ -1,3 +1,14 @@
1
1
  export declare const isDrawableImageSource: (value: unknown) => value is CanvasImageSource;
2
+ /**
3
+ * Intrinsic pixel size of a drawable image source, or `null` when it can't be
4
+ * determined. Handles the differing width/height accessors of the DOM image
5
+ * types (`naturalWidth` for `<img>`, `videoWidth` for `<video>`, plain
6
+ * `width`/`height` for bitmaps / canvases). Needed to turn a normalised crop
7
+ * (fractions) into a pixel source rectangle for `ctx.drawImage`.
8
+ */
9
+ export declare const intrinsicImageSize: (source: CanvasImageSource) => {
10
+ readonly width: number;
11
+ readonly height: number;
12
+ } | null;
2
13
  export declare const warnSkippedImage: (value: unknown) => void;
3
14
  //# sourceMappingURL=image-source.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image-source.d.ts","sourceRoot":"","sources":["../src/image-source.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,qBAAqB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,iBAa/D,CAAC;AAUF,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,IAoBjD,CAAC"}
1
+ {"version":3,"file":"image-source.d.ts","sourceRoot":"","sources":["../src/image-source.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,qBAAqB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,iBAa/D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,iBAAiB,KACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAmBxD,CAAC;AAUF,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,IAoBjD,CAAC"}
@@ -37,6 +37,26 @@ export const isDrawableImageSource = (value) => {
37
37
  }
38
38
  return false;
39
39
  };
40
+ /**
41
+ * Intrinsic pixel size of a drawable image source, or `null` when it can't be
42
+ * determined. Handles the differing width/height accessors of the DOM image
43
+ * types (`naturalWidth` for `<img>`, `videoWidth` for `<video>`, plain
44
+ * `width`/`height` for bitmaps / canvases). Needed to turn a normalised crop
45
+ * (fractions) into a pixel source rectangle for `ctx.drawImage`.
46
+ */
47
+ export const intrinsicImageSize = (source) => {
48
+ const s = source;
49
+ if (typeof s.naturalWidth === "number" && s.naturalWidth > 0) {
50
+ return { width: s.naturalWidth, height: s.naturalHeight ?? s.naturalWidth };
51
+ }
52
+ if (typeof s.videoWidth === "number" && s.videoWidth > 0) {
53
+ return { width: s.videoWidth, height: s.videoHeight ?? s.videoWidth };
54
+ }
55
+ if (typeof s.width === "number" && s.width > 0 && typeof s.height === "number") {
56
+ return { width: s.width, height: s.height };
57
+ }
58
+ return null;
59
+ };
40
60
  /**
41
61
  * Warn (once per distinct kind) when an image draw is skipped because
42
62
  * the handle isn't drawable. Throttled by a module-level `Set` so a
@@ -1 +1 @@
1
- {"version":3,"file":"image-source.js","sourceRoot":"","sources":["../src/image-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,mBAAmB,GAAG;IAC1B,kBAAkB;IAClB,mBAAmB;IACnB,kBAAkB;IAClB,aAAa;IACb,iBAAiB;IACjB,iBAAiB;IACjB,YAAY;CACJ,CAAC;AAEX,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAc,EAA8B,EAAE;IAClF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,UAAqC,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QACrB,IACE,OAAO,IAAI,KAAK,UAAU;YAC1B,KAAK,YAAa,IAA0C,EAC5D,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;AAE3C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAQ,EAAE;IACvD,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO;IAC3C,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ;QACvB,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;YACzB,CAAC,CAAC,eAAe;YACjB,CAAC,CAAC,YAAY;QAChB,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YACrC,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,cAAc,CAAC,CAAC,oCAAoC;IAC5D,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO;IACvC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE3B,OAAO,CAAC,IAAI,CACV,yDAAyD,IAAI,KAAK;QAChE,oEAAoE;QACpE,oEAAoE;QACpE,qEAAqE;QACrE,2CAA2C,CAC9C,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"image-source.js","sourceRoot":"","sources":["../src/image-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,mBAAmB,GAAG;IAC1B,kBAAkB;IAClB,mBAAmB;IACnB,kBAAkB;IAClB,aAAa;IACb,iBAAiB;IACjB,iBAAiB;IACjB,YAAY;CACJ,CAAC;AAEX,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAc,EAA8B,EAAE;IAClF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,UAAqC,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QACrB,IACE,OAAO,IAAI,KAAK,UAAU;YAC1B,KAAK,YAAa,IAA0C,EAC5D,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,MAAyB,EACmC,EAAE;IAC9D,MAAM,CAAC,GAAG,MAOT,CAAC;IACF,IAAI,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ,IAAI,CAAC,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;QAC7D,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;IAC9E,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;IACxE,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/E,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;AAE3C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAQ,EAAE;IACvD,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO;IAC3C,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ;QACvB,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;YACzB,CAAC,CAAC,eAAe;YACjB,CAAC,CAAC,YAAY;QAChB,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YACrC,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,cAAc,CAAC,CAAC,oCAAoC;IAC5D,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO;IACvC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE3B,OAAO,CAAC,IAAI,CACV,yDAAyD,IAAI,KAAK;QAChE,oEAAoE;QACpE,oEAAoE;QACpE,qEAAqE;QACrE,2CAA2C,CAC9C,CAAC;AACJ,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  export { Canvas2DTarget } from "./canvas-target.js";
2
2
  export { Canvas2DTextShaper } from "./canvas-text-shaper.js";
3
- export { WebGL2Target } from "./webgl2-target.js";
3
+ export { WebGL2Target, type WebGL2TargetOptions } from "./webgl2-target.js";
4
4
  export { renderViaTiles, type RenderViaTilesOptions } from "./tile-compositor.js";
5
- export { setupHiDpi } from "./hi-dpi.js";
5
+ export { setupHiDpi, cappedDpr } from "./hi-dpi.js";
6
6
  export { LayeredCanvas, type LayeredCanvasOptions } from "./layered-canvas.js";
7
7
  export { supportsOffscreenCanvas, createOffscreenCanvas2DTarget, transferCanvasToWorker, } from "./offscreen.js";
8
8
  export { createRenderWorker } from "./worker-factory.js";
@@ -10,7 +10,7 @@ export { WorkerPool, LayerWorkerPool } from "@oh-just-another/renderer-workers";
10
10
  export { RecordingTarget, replayCommands, type RenderCommand } from "./recording-target.js";
11
11
  export { createLayeredSurface, createLayeredSurfaceWithFallback, type LayeredSurface, type RendererBackend, type CreateLayeredSurfaceOptions, } from "./layered-surface.js";
12
12
  export { isWebGPUAvailable, isWebGL2Available, pickAvailableBackend } from "./webgpu-detect.js";
13
- export { LARGE_SCENE_WORKER_THRESHOLD } from "./constants.js";
13
+ export { LARGE_SCENE_WORKER_THRESHOLD, MAX_DEVICE_PIXEL_RATIO } from "./constants.js";
14
14
  export { installBuiltinRenderers, wrapText } from "@oh-just-another/renderer-core";
15
15
  export type { WrapOptions, WrappedLine } from "@oh-just-another/renderer-core";
16
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EACL,oBAAoB,EACpB,gCAAgC,EAChC,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,2BAA2B,GACjC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACnF,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EACL,oBAAoB,EACpB,gCAAgC,EAChC,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,2BAA2B,GACjC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACnF,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ export { Canvas2DTarget } from "./canvas-target.js";
2
2
  export { Canvas2DTextShaper } from "./canvas-text-shaper.js";
3
3
  export { WebGL2Target } from "./webgl2-target.js";
4
4
  export { renderViaTiles } from "./tile-compositor.js";
5
- export { setupHiDpi } from "./hi-dpi.js";
5
+ export { setupHiDpi, cappedDpr } from "./hi-dpi.js";
6
6
  export { LayeredCanvas } from "./layered-canvas.js";
7
7
  export { supportsOffscreenCanvas, createOffscreenCanvas2DTarget, transferCanvasToWorker, } from "./offscreen.js";
8
8
  export { createRenderWorker } from "./worker-factory.js";
@@ -10,7 +10,7 @@ export { WorkerPool, LayerWorkerPool } from "@oh-just-another/renderer-workers";
10
10
  export { RecordingTarget, replayCommands } from "./recording-target.js";
11
11
  export { createLayeredSurface, createLayeredSurfaceWithFallback, } from "./layered-surface.js";
12
12
  export { isWebGPUAvailable, isWebGL2Available, pickAvailableBackend } from "./webgpu-detect.js";
13
- export { LARGE_SCENE_WORKER_THRESHOLD } from "./constants.js";
13
+ export { LARGE_SCENE_WORKER_THRESHOLD, MAX_DEVICE_PIXEL_RATIO } from "./constants.js";
14
14
  export { installBuiltinRenderers, wrapText } from "@oh-just-another/renderer-core";
15
15
  // `installBuiltinRenderers()` must be called once before built-in shapes
16
16
  // can be drawn. It is not auto-invoked so this package stays
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAA8B,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAsB,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EACL,oBAAoB,EACpB,gCAAgC,GAIjC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAGnF,yEAAyE;AACzE,6DAA6D;AAC7D,sEAAsE;AACtE,oBAAoB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAA4B,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAA8B,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAsB,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EACL,oBAAoB,EACpB,gCAAgC,GAIjC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAGnF,yEAAyE;AACzE,6DAA6D;AAC7D,sEAAsE;AACtE,oBAAoB"}
@@ -3,8 +3,13 @@ import { Canvas2DTarget } from "./canvas-target.js";
3
3
  export interface LayeredCanvasOptions {
4
4
  /** Subset of layers to create. Defaults to all three. */
5
5
  readonly layers?: readonly LayerName[];
6
- /** Override `window.devicePixelRatio`. */
6
+ /** Override `window.devicePixelRatio`. Takes precedence over `maxDpr`. */
7
7
  readonly dpr?: number;
8
+ /**
9
+ * Cap applied to the live `window.devicePixelRatio` on create and every
10
+ * resize. Defaults to `MAX_DEVICE_PIXEL_RATIO`. Ignored when `dpr` is set.
11
+ */
12
+ readonly maxDpr?: number;
8
13
  }
9
14
  /**
10
15
  * Manages one stacked `<canvas>` per layer. The background canvas sits at the
@@ -22,6 +27,7 @@ export declare class LayeredCanvas {
22
27
  private width;
23
28
  private height;
24
29
  private dprOverride;
30
+ private readonly maxDpr;
25
31
  constructor(host: HTMLElement, width: number, height: number, options?: LayeredCanvasOptions);
26
32
  /** Get the target for a layer. Throws if the layer was not created. */
27
33
  get(name: LayerName): Canvas2DTarget;
@@ -1 +1 @@
1
- {"version":3,"file":"layered-canvas.d.ts","sourceRoot":"","sources":["../src/layered-canvas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;IACrE,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAqB;gBAGtC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,oBAAyB;IAkCpC,uEAAuE;IACvE,GAAG,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc;IAMpC,yDAAyD;IACzD,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB;IAM7C;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAY3C,IAAI,IAAI,IAAI;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAE9D;IAED,8EAA8E;IAC9E,OAAO,IAAI,IAAI;CAKhB"}
1
+ {"version":3,"file":"layered-canvas.d.ts","sourceRoot":"","sources":["../src/layered-canvas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC,0EAA0E;IAC1E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;IACrE,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAG9B,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,oBAAyB;IAmCpC,uEAAuE;IACvE,GAAG,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc;IAMpC,yDAAyD;IACzD,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB;IAM7C;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAY3C,IAAI,IAAI,IAAI;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAE9D;IAED,8EAA8E;IAC9E,OAAO,IAAI,IAAI;CAKhB"}
@@ -1,6 +1,7 @@
1
1
  import { LAYER_ORDER } from "@oh-just-another/renderer-core";
2
2
  import { Canvas2DTarget } from "./canvas-target.js";
3
- import { setupHiDpi } from "./hi-dpi.js";
3
+ import { cappedDpr, setupHiDpi } from "./hi-dpi.js";
4
+ import { MAX_DEVICE_PIXEL_RATIO } from "./constants.js";
4
5
  /**
5
6
  * Manages one stacked `<canvas>` per layer. The background canvas sits at the
6
7
  * bottom of the DOM stack and the overlay at the top, so drawing onto `main`
@@ -17,11 +18,13 @@ export class LayeredCanvas {
17
18
  width;
18
19
  height;
19
20
  dprOverride;
21
+ maxDpr;
20
22
  constructor(host, width, height, options = {}) {
21
23
  this.host = host;
22
24
  this.width = width;
23
25
  this.height = height;
24
26
  this.dprOverride = options.dpr;
27
+ this.maxDpr = options.maxDpr ?? MAX_DEVICE_PIXEL_RATIO;
25
28
  if (getComputedStyle(host).position === "static") {
26
29
  host.style.position = "relative";
27
30
  }
@@ -37,7 +40,7 @@ export class LayeredCanvas {
37
40
  canvas.style.inset = "0";
38
41
  canvas.style.pointerEvents = name === "overlay" ? "auto" : "none";
39
42
  host.appendChild(canvas);
40
- const dpr = setupHiDpi(canvas, width, height, this.dprOverride);
43
+ const dpr = setupHiDpi(canvas, width, height, this.dprOverride ?? cappedDpr(this.maxDpr));
41
44
  const ctx = canvas.getContext("2d");
42
45
  if (!ctx)
43
46
  throw new Error("Failed to obtain 2D context");
@@ -75,7 +78,7 @@ export class LayeredCanvas {
75
78
  this.width = width;
76
79
  this.height = height;
77
80
  for (const [name, canvas] of this.canvases) {
78
- const dpr = setupHiDpi(canvas, width, height, this.dprOverride);
81
+ const dpr = setupHiDpi(canvas, width, height, this.dprOverride ?? cappedDpr(this.maxDpr));
79
82
  const layer = this.layers.get(name);
80
83
  if (layer === undefined)
81
84
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"layered-canvas.js","sourceRoot":"","sources":["../src/layered-canvas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"layered-canvas.js","sourceRoot":"","sources":["../src/layered-canvas.ts"],"names":[],"mappings":"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"}
@@ -54,6 +54,22 @@ export interface CreateLayeredSurfaceOptions {
54
54
  * always-safe `canvas2d` backend. Only the offscreen backend calls it.
55
55
  */
56
56
  readonly onWorkerError?: (error: unknown) => void;
57
+ /**
58
+ * Cap applied to `window.devicePixelRatio` when sizing layer bitmaps.
59
+ * Defaults to `MAX_DEVICE_PIXEL_RATIO` (2). Raise it for hosts that
60
+ * need native sharpness on DPR-3+ displays at the cost of 2–4× the
61
+ * raster work per layer.
62
+ */
63
+ readonly maxDpr?: number;
64
+ /**
65
+ * Forwarded to the `webgl2` backend's main-layer context. Defaults to
66
+ * `true`, which the incremental dirty-rect renderer requires (the rest
67
+ * of the previous frame must survive between composites). Set `false`
68
+ * only when the host redraws the whole frame every time — it removes a
69
+ * Safari/iOS full-recomposite-per-swap cost. Ignored by the `canvas2d`
70
+ * and `offscreen` backends. Does not affect PNG export / screenshots.
71
+ */
72
+ readonly preserveDrawingBuffer?: boolean;
57
73
  }
58
74
  /**
59
75
  * Factory entry point. Picks the right backend implementation, builds
@@ -1 +1 @@
1
- {"version":3,"file":"layered-surface.d.ts","sourceRoot":"","sources":["../src/layered-surface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAMhG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,GAAG,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;IACnC,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,oEAAoE;IACpE,OAAO,IAAI,IAAI,CAAC;IAChB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC;IACnC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IACtC;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAC/B,MAAM,WAAW,EACjB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,UAAS,2BAAgC,KACxC,cAqBF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gCAAgC,GAC3C,MAAM,WAAW,EACjB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,UAAS,2BAAgC,EACzC,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,KAC9D;IAAE,OAAO,EAAE,cAAc,CAAC;IAAC,gBAAgB,EAAE,eAAe,CAAA;CAe9D,CAAC"}
1
+ {"version":3,"file":"layered-surface.d.ts","sourceRoot":"","sources":["../src/layered-surface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAOhG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,GAAG,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;IACnC,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,oEAAoE;IACpE,OAAO,IAAI,IAAI,CAAC;IAChB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC;IACnC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IACtC;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAC1C;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAC/B,MAAM,WAAW,EACjB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,UAAS,2BAAgC,KACxC,cA2BF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gCAAgC,GAC3C,MAAM,WAAW,EACjB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,UAAS,2BAAgC,EACzC,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,KAC9D;IAAE,OAAO,EAAE,cAAc,CAAC;IAAC,gBAAgB,EAAE,eAAe,CAAA;CAe9D,CAAC"}
@@ -2,7 +2,8 @@ import { LAYER_ORDER } from "@oh-just-another/renderer-core";
2
2
  import { LayeredCanvas } from "./layered-canvas.js";
3
3
  import { WebGL2Target } from "./webgl2-target.js";
4
4
  import { RecordingTarget } from "./recording-target.js";
5
- import { setupHiDpi } from "./hi-dpi.js";
5
+ import { cappedDpr, setupHiDpi } from "./hi-dpi.js";
6
+ import { MAX_DEVICE_PIXEL_RATIO } from "./constants.js";
6
7
  /**
7
8
  * Factory entry point. Picks the right backend implementation, builds
8
9
  * it, and returns the common `LayeredSurface` interface. Canvas2D is
@@ -15,16 +16,21 @@ import { setupHiDpi } from "./hi-dpi.js";
15
16
  */
16
17
  export const createLayeredSurface = (host, width, height, options = {}) => {
17
18
  const backend = options.backend ?? "canvas2d";
19
+ const maxDpr = options.maxDpr ?? MAX_DEVICE_PIXEL_RATIO;
18
20
  switch (backend) {
19
21
  case "canvas2d":
20
- return new Canvas2DLayeredSurface(host, width, height);
22
+ return new Canvas2DLayeredSurface(host, width, height, maxDpr);
21
23
  case "webgl2":
22
- return new WebGL2LayeredSurface(host, width, height);
24
+ return new WebGL2LayeredSurface(host, width, height, maxDpr, {
25
+ ...(options.preserveDrawingBuffer !== undefined
26
+ ? { preserveDrawingBuffer: options.preserveDrawingBuffer }
27
+ : {}),
28
+ });
23
29
  case "offscreen":
24
30
  if (!options.workerFactory) {
25
31
  throw new Error("createLayeredSurface: workerFactory is required for the offscreen backend");
26
32
  }
27
- return new OffscreenLayeredSurface(host, width, height, options.workerFactory, options.onWorkerError);
33
+ return new OffscreenLayeredSurface(host, width, height, options.workerFactory, options.onWorkerError, maxDpr);
28
34
  }
29
35
  };
30
36
  /**
@@ -60,8 +66,8 @@ export const createLayeredSurfaceWithFallback = (host, width, height, options =
60
66
  class Canvas2DLayeredSurface {
61
67
  backend = "canvas2d";
62
68
  inner;
63
- constructor(host, width, height) {
64
- this.inner = new LayeredCanvas(host, width, height);
69
+ constructor(host, width, height, maxDpr) {
70
+ this.inner = new LayeredCanvas(host, width, height, { maxDpr });
65
71
  }
66
72
  get(name) {
67
73
  return this.inner.get(name);
@@ -102,13 +108,16 @@ class WebGL2LayeredSurface {
102
108
  mainTarget;
103
109
  _width;
104
110
  _height;
105
- constructor(host, width, height) {
111
+ maxDpr;
112
+ constructor(host, width, height, maxDpr, options = {}) {
106
113
  this._width = width;
107
114
  this._height = height;
115
+ this.maxDpr = maxDpr;
108
116
  // Build the Canvas2D layers first; the WebGL2 main canvas is
109
117
  // spliced into the same stack between background and overlay.
110
118
  this.base = new LayeredCanvas(host, width, height, {
111
119
  layers: LAYER_ORDER.filter((name) => name !== "main"),
120
+ maxDpr,
112
121
  });
113
122
  const overlay = this.base.getCanvas("overlay");
114
123
  const canvas = host.ownerDocument.createElement("canvas");
@@ -123,10 +132,14 @@ class WebGL2LayeredSurface {
123
132
  // exclusive — one canvas, one context kind, for the life of the
124
133
  // element. `setupContext: false` sizes the bitmap without touching
125
134
  // the context.
126
- setupHiDpi(canvas, width, height, window.devicePixelRatio || 1, false);
135
+ setupHiDpi(canvas, width, height, cappedDpr(maxDpr), false);
127
136
  try {
128
137
  this.mainCanvas = canvas;
129
- this.mainTarget = new WebGL2Target(canvas, width, height);
138
+ this.mainTarget = new WebGL2Target(canvas, width, height, {
139
+ ...(options.preserveDrawingBuffer !== undefined
140
+ ? { preserveDrawingBuffer: options.preserveDrawingBuffer }
141
+ : {}),
142
+ });
130
143
  }
131
144
  catch (err) {
132
145
  canvas.remove();
@@ -150,14 +163,17 @@ class WebGL2LayeredSurface {
150
163
  this._width = width;
151
164
  this._height = height;
152
165
  this.base.resize(width, height);
153
- setupHiDpi(this.mainCanvas, width, height, window.devicePixelRatio || 1, false);
166
+ setupHiDpi(this.mainCanvas, width, height, cappedDpr(this.maxDpr), false);
154
167
  this.mainTarget.resize(width, height);
155
168
  }
156
169
  get size() {
157
170
  return { width: this._width, height: this._height };
158
171
  }
159
172
  present() {
160
- // Canvas2D + WebGL2 both paint synchronously nothing to flush.
173
+ // Canvas2D paints synchronously; the WebGL2 main layer defers
174
+ // same-style sharp-rect fills into an instanced batch, so drain it
175
+ // here so trailing rects reach the framebuffer within this frame.
176
+ this.mainTarget.flushBatch();
161
177
  }
162
178
  dispose() {
163
179
  this.mainTarget.dispose();
@@ -184,13 +200,21 @@ class OffscreenLayeredSurface {
184
200
  canvases = new Map();
185
201
  targets = new Map();
186
202
  workers = new Map();
203
+ /**
204
+ * Content signature of the command stream last posted to each layer's
205
+ * worker. A frame whose flushed buffer matches its layer's entry replays
206
+ * to the same pixels the worker already shows, so `present()` skips the
207
+ * postMessage (clone) + replay entirely — e.g. a static grid / overlay
208
+ * while only the main layer's GIF advances.
209
+ */
210
+ lastSentSig = new Map();
187
211
  _width;
188
212
  _height;
189
213
  dpr;
190
- constructor(host, width, height, workerFactory, onWorkerError) {
214
+ constructor(host, width, height, workerFactory, onWorkerError, maxDpr = MAX_DEVICE_PIXEL_RATIO) {
191
215
  this._width = width;
192
216
  this._height = height;
193
- this.dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
217
+ this.dpr = cappedDpr(maxDpr);
194
218
  if (getComputedStyle(host).position === "static") {
195
219
  host.style.position = "relative";
196
220
  }
@@ -258,6 +282,10 @@ class OffscreenLayeredSurface {
258
282
  this.targets.get(name)?.resize(width, height);
259
283
  this.workers.get(name)?.postMessage({ type: "resize", width, height });
260
284
  }
285
+ // A resize clears each worker's OffscreenCanvas (its bitmap is re-sized),
286
+ // so the next frame must repost even if its content signature is
287
+ // unchanged — drop the cached signatures to force it.
288
+ this.lastSentSig.clear();
261
289
  }
262
290
  get size() {
263
291
  return { width: this._width, height: this._height };
@@ -267,6 +295,15 @@ class OffscreenLayeredSurface {
267
295
  const cmds = target.flush();
268
296
  if (cmds.length === 0)
269
297
  continue;
298
+ // Skip layers whose command stream is identical to the one already
299
+ // shipped: the worker retains its last frame between replays, so not
300
+ // reposting leaves the correct pixels in place and saves the clone +
301
+ // worker redraw. `defineImage` (first bitmap ship) and `resize` change
302
+ // the stream, so image / size updates never get skipped.
303
+ const sig = target.lastSignature;
304
+ if (this.lastSentSig.get(name) === sig)
305
+ continue;
306
+ this.lastSentSig.set(name, sig);
270
307
  this.workers.get(name)?.postMessage({ type: "replay", commands: cmds });
271
308
  }
272
309
  }
@@ -1 +1 @@
1
- {"version":3,"file":"layered-surface.js","sourceRoot":"","sources":["../src/layered-surface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"layered-surface.js","sourceRoot":"","sources":["../src/layered-surface.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,5 @@
1
1
  import type { Bounds, Color, Transform } from "@oh-just-another/types";
2
2
  import { LruCache, type FillRule, type LineCap, type LineJoin, type RenderTarget, type TextAlign, type TextBaseline } from "@oh-just-another/renderer-core";
3
- /**
4
- * Backend-agnostic RenderTarget that captures every method call as a
5
- * structured command. Powers the "offscreen" pipeline: the main thread
6
- * renders into a RecordingTarget, the resulting buffer is shipped to a
7
- * worker via postMessage, and the worker replays the commands onto its
8
- * OffscreenCanvas.
9
- *
10
- * Commands are a tagged union of primitive payloads (no class
11
- * instances) so they survive `structuredClone` cleanly across the
12
- * worker boundary. `flush()` returns the buffered commands and resets
13
- * the internal log.
14
- */
15
3
  export type RenderCommand = {
16
4
  readonly k: "setFill";
17
5
  readonly color: Color | null;
@@ -175,12 +163,48 @@ export declare class RecordingTarget implements RenderTarget {
175
163
  */
176
164
  private readonly imageIds;
177
165
  private nextImageId;
166
+ /**
167
+ * Rolling 64-bit content signature (two 32-bit halves) of the commands
168
+ * accumulated since the last {@link flush}. Every {@link emit} folds the
169
+ * command's tag and primitive fields in, so two frames that record a
170
+ * byte-identical stream produce the same signature — letting the
171
+ * offscreen surface skip re-posting a layer whose replay would reproduce
172
+ * the pixels the worker already shows. Reset to the seeds on `flush`.
173
+ */
174
+ private sigA;
175
+ private sigB;
176
+ private cmdCount;
177
+ /** Signature of the buffer returned by the most recent {@link flush}. */
178
+ private _lastSignature;
178
179
  constructor(width: number, height: number);
179
180
  get size(): {
180
181
  readonly width: number;
181
182
  readonly height: number;
182
183
  };
183
184
  resize(width: number, height: number): void;
185
+ /** Buffer one command and fold it into the rolling content signature. */
186
+ private emit;
187
+ /** Fold one 32-bit word into both signature halves (Murmur-style mix). */
188
+ private mix32;
189
+ /** Fold a number by its exact 64-bit IEEE-754 bit pattern. */
190
+ private mixNumber;
191
+ private mixString;
192
+ /**
193
+ * Fold an arbitrary command-field value: numbers by bits, strings by
194
+ * chars, nested `Transform` / bounds / options objects field-by-field,
195
+ * dash arrays element-by-element. `ImageBitmap` pixels are NOT hashed —
196
+ * a bitmap only ever appears in a `defineImage`, whose presence (and the
197
+ * accompanying numeric `id`) already differentiates the stream, so the
198
+ * per-frame `drawImage`-by-id path stays exact without touching pixels.
199
+ */
200
+ private mixValue;
201
+ /**
202
+ * Content signature of the buffer returned by the most recent
203
+ * {@link flush}. Stable across frames that record an identical command
204
+ * stream; used by the offscreen surface to skip re-posting unchanged
205
+ * layers. Empty string before the first flush.
206
+ */
207
+ get lastSignature(): string;
184
208
  /** Pop the buffered commands and clear the internal log. */
185
209
  flush(): readonly RenderCommand[];
186
210
  /** Snapshot of the buffered commands without clearing. */