@vectojs/core 1.26.0 → 1.27.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.
@@ -1,5 +1,52 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5;const __vecto_cjs_url=require("url").pathToFileURL(__filename).href;
2
2
 
3
+ // src/renderer/IRenderer.ts
4
+ var RENDERER_STYLE_PROPERTY_HINTS = {
5
+ globalAlpha: "setGlobalAlpha(alpha)",
6
+ strokeStyle: "stroke(color, lineWidth)",
7
+ lineWidth: "stroke(color, lineWidth)",
8
+ fillStyle: "fill(color) \u2014 or fillText(text, x, y, font, color)",
9
+ font: "fillText(text, x, y, font, color)",
10
+ lineCap: "stroke(color, lineWidth) (cap is backend-chosen)",
11
+ lineJoin: "stroke(color, lineWidth) (join is backend-chosen)",
12
+ globalCompositeOperation: "no equivalent \u2014 composite via a separate canvas",
13
+ shadowBlur: "no equivalent \u2014 draw the shadow explicitly",
14
+ shadowColor: "no equivalent \u2014 draw the shadow explicitly",
15
+ textAlign: "no equivalent \u2014 measure and offset x yourself",
16
+ textBaseline: "no equivalent \u2014 measure and offset y yourself"
17
+ };
18
+ var rendererDevMode = false;
19
+ function setRendererDevMode(active) {
20
+ rendererDevMode = active;
21
+ }
22
+ function isRendererDevMode() {
23
+ if (rendererDevMode) return true;
24
+ const g = typeof globalThis !== "undefined" ? globalThis : void 0;
25
+ if (_optionalChain([g, 'optionalAccess', _ => _.__DEV__])) return true;
26
+ return _optionalChain([g, 'optionalAccess', _2 => _2.process, 'optionalAccess', _3 => _3.env, 'optionalAccess', _4 => _4.NODE_ENV]) === "development";
27
+ }
28
+ function installRendererDevTraps(renderer, label) {
29
+ if (!isRendererDevMode()) return;
30
+ for (const [prop, hint] of Object.entries(RENDERER_STYLE_PROPERTY_HINTS)) {
31
+ if (prop in renderer) continue;
32
+ let stored;
33
+ let warned = false;
34
+ Object.defineProperty(renderer, prop, {
35
+ configurable: true,
36
+ enumerable: false,
37
+ get: () => stored,
38
+ set: (value) => {
39
+ stored = value;
40
+ if (warned) return;
41
+ warned = true;
42
+ console.warn(
43
+ `[vectojs/dev] \`${prop}\` is not a renderer property \u2014 assigning it on ${label} has no effect on what is drawn. Call \`${hint}\` instead.`
44
+ );
45
+ }
46
+ });
47
+ }
48
+ }
49
+
3
50
  // src/renderer/CanvasRenderer.ts
4
51
  function emptyDrawCounters() {
5
52
  return {
@@ -79,8 +126,8 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
79
126
  constructor(canvas, size, maxDPR) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);_class.prototype.__init8.call(this);_class.prototype.__init9.call(this);_class.prototype.__init10.call(this);_class.prototype.__init11.call(this);
80
127
  this.maxDPR = maxDPR;
81
128
  const dpr = this.effectiveDPR();
82
- this.width = _nullishCoalesce(_optionalChain([size, 'optionalAccess', _ => _.width]), () => ( (typeof window !== "undefined" ? window.innerWidth : canvas.width || 0)));
83
- this.height = _nullishCoalesce(_optionalChain([size, 'optionalAccess', _2 => _2.height]), () => ( (typeof window !== "undefined" ? window.innerHeight : canvas.height || 0)));
129
+ this.width = _nullishCoalesce(_optionalChain([size, 'optionalAccess', _5 => _5.width]), () => ( (typeof window !== "undefined" ? window.innerWidth : canvas.width || 0)));
130
+ this.height = _nullishCoalesce(_optionalChain([size, 'optionalAccess', _6 => _6.height]), () => ( (typeof window !== "undefined" ? window.innerHeight : canvas.height || 0)));
84
131
  canvas.width = this.width * dpr;
85
132
  canvas.height = this.height * dpr;
86
133
  if (canvas.style) {
@@ -92,6 +139,7 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
92
139
  if (ctx) ctx.scale(dpr, dpr);
93
140
  this.canvas = canvas;
94
141
  this.setupContextLossRecovery();
142
+ installRendererDevTraps(this, "CanvasRenderer");
95
143
  }
96
144
  /** Register a callback fired after a lost 2D context is restored + re-scaled,
97
145
  * so the owner can repaint (the restored canvas comes back cleared). */
@@ -122,7 +170,7 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
122
170
  this.batchActive = false;
123
171
  this.batchCount = 0;
124
172
  this.contextLost = false;
125
- _optionalChain([this, 'access', _3 => _3.contextRestoredCb, 'optionalCall', _4 => _4()]);
173
+ _optionalChain([this, 'access', _7 => _7.contextRestoredCb, 'optionalCall', _8 => _8()]);
126
174
  });
127
175
  }
128
176
  /**
@@ -491,6 +539,7 @@ var SVGRenderer = (_class2 = class {
491
539
  constructor(width, height) {;_class2.prototype.__init12.call(this);_class2.prototype.__init13.call(this);_class2.prototype.__init14.call(this);_class2.prototype.__init15.call(this);_class2.prototype.__init16.call(this);_class2.prototype.__init17.call(this);_class2.prototype.__init18.call(this);_class2.prototype.__init19.call(this);_class2.prototype.__init20.call(this);_class2.prototype.__init21.call(this);_class2.prototype.__init22.call(this);_class2.prototype.__init23.call(this);_class2.prototype.__init24.call(this);_class2.prototype.__init25.call(this);_class2.prototype.__init26.call(this);_class2.prototype.__init27.call(this);_class2.prototype.__init28.call(this);_class2.prototype.__init29.call(this);_class2.prototype.__init30.call(this);_class2.prototype.__init31.call(this);_class2.prototype.__init32.call(this);_class2.prototype.__init33.call(this);_class2.prototype.__init34.call(this);
492
540
  this.width = width;
493
541
  this.height = height;
542
+ installRendererDevTraps(this, "SVGRenderer");
494
543
  }
495
544
  clear() {
496
545
  this.buffer = [];
@@ -712,8 +761,8 @@ var SVGRenderer = (_class2 = class {
712
761
  }
713
762
  drawImage(source, dx, dy, dw, dh) {
714
763
  this.flush();
715
- const fromCanvas2 = typeof _optionalChain([source, 'optionalAccess', _5 => _5.toDataURL]) === "function";
716
- const rawHref = fromCanvas2 ? source.toDataURL() : _optionalChain([source, 'optionalAccess', _6 => _6.src]) || "";
764
+ const fromCanvas2 = typeof _optionalChain([source, 'optionalAccess', _9 => _9.toDataURL]) === "function";
765
+ const rawHref = fromCanvas2 ? source.toDataURL() : _optionalChain([source, 'optionalAccess', _10 => _10.src]) || "";
717
766
  const href = fromCanvas2 && this.isSafeRasterDataUrl(rawHref) ? rawHref : sanitizeUrl(String(rawHref));
718
767
  const transformStr = `matrix(${this.ma},${this.mb},${this.mc},${this.md},${this.me},${this.mf})`;
719
768
  if (href) {
@@ -2285,4 +2334,7 @@ var TextRasterCache = (_class5 = class {
2285
2334
 
2286
2335
 
2287
2336
 
2288
- exports.CanvasRenderer = CanvasRenderer; exports.sanitizeUrl = sanitizeUrl; exports.isSafeUrl = isSafeUrl; exports.SVGRenderer = SVGRenderer; exports.parseColorToRGBA = parseColorToRGBA; exports.createWebGLPointRenderer = createWebGLPointRenderer; exports.WebGPUParticleSystemManager = WebGPUParticleSystemManager; exports.GlyphRasterAtlas = GlyphRasterAtlas; exports.TextRasterCache = TextRasterCache;
2337
+
2338
+
2339
+
2340
+ exports.setRendererDevMode = setRendererDevMode; exports.isRendererDevMode = isRendererDevMode; exports.installRendererDevTraps = installRendererDevTraps; exports.CanvasRenderer = CanvasRenderer; exports.sanitizeUrl = sanitizeUrl; exports.isSafeUrl = isSafeUrl; exports.SVGRenderer = SVGRenderer; exports.parseColorToRGBA = parseColorToRGBA; exports.createWebGLPointRenderer = createWebGLPointRenderer; exports.WebGPUParticleSystemManager = WebGPUParticleSystemManager; exports.GlyphRasterAtlas = GlyphRasterAtlas; exports.TextRasterCache = TextRasterCache;
@@ -1,3 +1,50 @@
1
+ // src/renderer/IRenderer.ts
2
+ var RENDERER_STYLE_PROPERTY_HINTS = {
3
+ globalAlpha: "setGlobalAlpha(alpha)",
4
+ strokeStyle: "stroke(color, lineWidth)",
5
+ lineWidth: "stroke(color, lineWidth)",
6
+ fillStyle: "fill(color) \u2014 or fillText(text, x, y, font, color)",
7
+ font: "fillText(text, x, y, font, color)",
8
+ lineCap: "stroke(color, lineWidth) (cap is backend-chosen)",
9
+ lineJoin: "stroke(color, lineWidth) (join is backend-chosen)",
10
+ globalCompositeOperation: "no equivalent \u2014 composite via a separate canvas",
11
+ shadowBlur: "no equivalent \u2014 draw the shadow explicitly",
12
+ shadowColor: "no equivalent \u2014 draw the shadow explicitly",
13
+ textAlign: "no equivalent \u2014 measure and offset x yourself",
14
+ textBaseline: "no equivalent \u2014 measure and offset y yourself"
15
+ };
16
+ var rendererDevMode = false;
17
+ function setRendererDevMode(active) {
18
+ rendererDevMode = active;
19
+ }
20
+ function isRendererDevMode() {
21
+ if (rendererDevMode) return true;
22
+ const g = typeof globalThis !== "undefined" ? globalThis : void 0;
23
+ if (g?.__DEV__) return true;
24
+ return g?.process?.env?.NODE_ENV === "development";
25
+ }
26
+ function installRendererDevTraps(renderer, label) {
27
+ if (!isRendererDevMode()) return;
28
+ for (const [prop, hint] of Object.entries(RENDERER_STYLE_PROPERTY_HINTS)) {
29
+ if (prop in renderer) continue;
30
+ let stored;
31
+ let warned = false;
32
+ Object.defineProperty(renderer, prop, {
33
+ configurable: true,
34
+ enumerable: false,
35
+ get: () => stored,
36
+ set: (value) => {
37
+ stored = value;
38
+ if (warned) return;
39
+ warned = true;
40
+ console.warn(
41
+ `[vectojs/dev] \`${prop}\` is not a renderer property \u2014 assigning it on ${label} has no effect on what is drawn. Call \`${hint}\` instead.`
42
+ );
43
+ }
44
+ });
45
+ }
46
+ }
47
+
1
48
  // src/renderer/CanvasRenderer.ts
2
49
  function emptyDrawCounters() {
3
50
  return {
@@ -90,6 +137,7 @@ var CanvasRenderer = class _CanvasRenderer {
90
137
  if (ctx) ctx.scale(dpr, dpr);
91
138
  this.canvas = canvas;
92
139
  this.setupContextLossRecovery();
140
+ installRendererDevTraps(this, "CanvasRenderer");
93
141
  }
94
142
  /** Register a callback fired after a lost 2D context is restored + re-scaled,
95
143
  * so the owner can repaint (the restored canvas comes back cleared). */
@@ -489,6 +537,7 @@ var SVGRenderer = class {
489
537
  constructor(width, height) {
490
538
  this.width = width;
491
539
  this.height = height;
540
+ installRendererDevTraps(this, "SVGRenderer");
492
541
  }
493
542
  clear() {
494
543
  this.buffer = [];
@@ -2274,6 +2323,9 @@ var TextRasterCache = class {
2274
2323
  };
2275
2324
 
2276
2325
  export {
2326
+ setRendererDevMode,
2327
+ isRendererDevMode,
2328
+ installRendererDevTraps,
2277
2329
  CanvasRenderer,
2278
2330
  sanitizeUrl,
2279
2331
  isSafeUrl,
package/dist/index.js CHANGED
@@ -9,7 +9,10 @@
9
9
 
10
10
 
11
11
 
12
- var _chunkKHGHP2J3js = require('./chunk-KHGHP2J3.js');
12
+
13
+
14
+
15
+ var _chunkK2UGEIT6js = require('./chunk-K2UGEIT6.js');
13
16
 
14
17
 
15
18
 
@@ -2840,10 +2843,26 @@ var Scene = (_class7 = class _Scene {
2840
2843
  //
2841
2844
  // Checks run once every ~120 frames (~2s at 60fps) to keep overhead
2842
2845
  // negligible even when dev mode is on.
2843
- /** Toggle development-mode runtime warnings globally. */
2844
- static __initStatic5() {this.devMode = false}
2846
+ static __initStatic5() {this._devMode = false}
2847
+ /**
2848
+ * Toggle development-mode runtime warnings globally.
2849
+ *
2850
+ * An accessor rather than a plain field so the renderer layer learns about it
2851
+ * immediately: renderers cannot import `Scene` (the dependency runs
2852
+ * `Scene → renderer`), and their diagnostics are installed per instance at
2853
+ * construction. A plain field would only reach them the next time a `Scene`
2854
+ * happened to be built, which made a directly-constructed `CanvasRenderer`
2855
+ * silently untrapped.
2856
+ */
2857
+ static get devMode() {
2858
+ return _Scene._devMode;
2859
+ }
2860
+ static set devMode(active) {
2861
+ _Scene._devMode = active;
2862
+ _chunkK2UGEIT6js.setRendererDevMode.call(void 0, active);
2863
+ }
2845
2864
  static _devModeDetected() {
2846
- if (_Scene.devMode) return true;
2865
+ if (_Scene._devMode) return true;
2847
2866
  const gp = typeof globalThis !== "undefined" ? globalThis : void 0;
2848
2867
  if (_optionalChain([gp, 'optionalAccess', _41 => _41.__DEV__])) return true;
2849
2868
  if (_optionalChain([gp, 'optionalAccess', _42 => _42.process, 'optionalAccess', _43 => _43.env, 'optionalAccess', _44 => _44.NODE_ENV]) === "development") return true;
@@ -2952,6 +2971,7 @@ var Scene = (_class7 = class _Scene {
2952
2971
  this.readingDirection = _nullishCoalesce(options.readingDirection, () => ( "ltr"));
2953
2972
  this.renderMode = _nullishCoalesce(options.renderMode, () => ( "always"));
2954
2973
  this._devActive = _Scene._devModeDetected();
2974
+ _chunkK2UGEIT6js.setRendererDevMode.call(void 0, this._devActive);
2955
2975
  this._warnUnknownOptions(options);
2956
2976
  this.reducedMotionQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
2957
2977
  if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
@@ -2979,7 +2999,7 @@ var Scene = (_class7 = class _Scene {
2979
2999
  if (options.renderer) {
2980
3000
  this.renderer = options.renderer;
2981
3001
  } else {
2982
- this.renderer = new (0, _chunkKHGHP2J3js.CanvasRenderer)(
3002
+ this.renderer = new (0, _chunkK2UGEIT6js.CanvasRenderer)(
2983
3003
  canvas,
2984
3004
  this.disableWindowResize ? { width: this.width, height: this.height } : void 0,
2985
3005
  this.maxDPR
@@ -3620,10 +3640,24 @@ var Scene = (_class7 = class _Scene {
3620
3640
  * resume when it returns — instead of running the full update/render every
3621
3641
  * frame for a scene nobody can see. No-op (stays "on screen") where
3622
3642
  * `IntersectionObserver` is unavailable, so SSR/jsdom behavior is unchanged.
3643
+ *
3644
+ * Also a no-op for a canvas that is not in the document. An offscreen canvas
3645
+ * used purely as a texture source — `@vectojs/three`'s `ThreeAdapter` wraps
3646
+ * one in a `CanvasTexture`, and the same pattern shows up in any
3647
+ * render-to-texture setup — is never appended anywhere, and an
3648
+ * `IntersectionObserver` reports a detached element as not intersecting.
3649
+ * Observing it would therefore set `_canvasOnScreen = false` on the first
3650
+ * callback, and since {@link loop} returns without rescheduling in that
3651
+ * state, the loop would stop permanently: the only resume path is an
3652
+ * `isIntersecting` transition, which a detached element can never produce.
3653
+ * Such a canvas is always "visible" as far as this scene is concerned,
3654
+ * because whether its output is seen depends on the consumer sampling the
3655
+ * texture, which this scene cannot observe.
3623
3656
  */
3624
3657
  watchCanvasVisibility() {
3625
3658
  if (this._canvasObserver || typeof IntersectionObserver === "undefined") return;
3626
3659
  if (!this.canvas || typeof this.canvas.getBoundingClientRect !== "function") return;
3660
+ if (this.canvas.isConnected === false) return;
3627
3661
  this._canvasObserver = new IntersectionObserver((entries) => {
3628
3662
  const entry = entries[entries.length - 1];
3629
3663
  if (!entry) return;
@@ -4054,7 +4088,7 @@ var Scene = (_class7 = class _Scene {
4054
4088
  this.syncOptionalAttribute(
4055
4089
  el,
4056
4090
  "href",
4057
- attrs.href === void 0 ? void 0 : _chunkKHGHP2J3js.sanitizeUrl.call(void 0, attrs.href)
4091
+ attrs.href === void 0 ? void 0 : _chunkK2UGEIT6js.sanitizeUrl.call(void 0, attrs.href)
4058
4092
  );
4059
4093
  this.syncOptionalAttribute(el, "target", attrs.target);
4060
4094
  }
@@ -5489,7 +5523,7 @@ var Scene = (_class7 = class _Scene {
5489
5523
  * Export the current scene state to a lightweight, flat SVG XML string.
5490
5524
  */
5491
5525
  toSVG() {
5492
- const renderer = new (0, _chunkKHGHP2J3js.SVGRenderer)(this.width, this.height);
5526
+ const renderer = new (0, _chunkK2UGEIT6js.SVGRenderer)(this.width, this.height);
5493
5527
  this.render(renderer, 0, 0);
5494
5528
  return renderer.toXMLString();
5495
5529
  }
@@ -6550,8 +6584,11 @@ var DOMPortalEntity = (_class11 = class extends _chunkZ3HFY75Rjs.Entity {
6550
6584
  }, _class11);
6551
6585
 
6552
6586
  // src/index.ts
6553
- Scene.registerWebGLPointRendererCreator(_chunkKHGHP2J3js.createWebGLPointRenderer);
6554
- Scene.registerWebGPUParticleSystemManager(_chunkKHGHP2J3js.WebGPUParticleSystemManager);
6587
+ Scene.registerWebGLPointRendererCreator(_chunkK2UGEIT6js.createWebGLPointRenderer);
6588
+ Scene.registerWebGPUParticleSystemManager(_chunkK2UGEIT6js.WebGPUParticleSystemManager);
6589
+
6590
+
6591
+
6555
6592
 
6556
6593
 
6557
6594
 
@@ -6592,4 +6629,4 @@ Scene.registerWebGPUParticleSystemManager(_chunkKHGHP2J3js.WebGPUParticleSystemM
6592
6629
 
6593
6630
 
6594
6631
 
6595
- exports.CanvasRenderer = _chunkKHGHP2J3js.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Entity = _chunkZ3HFY75Rjs.Entity; exports.GlyphRasterAtlas = _chunkKHGHP2J3js.GlyphRasterAtlas; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.MSDFTextEntity = _chunkZ3HFY75Rjs.MSDFTextEntity; exports.PARTICLE_OFFSET_LIFE = PARTICLE_OFFSET_LIFE; exports.PARTICLE_OFFSET_ORIGIN_X = PARTICLE_OFFSET_ORIGIN_X; exports.PARTICLE_OFFSET_ORIGIN_Y = PARTICLE_OFFSET_ORIGIN_Y; exports.PARTICLE_OFFSET_POSITION_X = PARTICLE_OFFSET_POSITION_X; exports.PARTICLE_OFFSET_POSITION_Y = PARTICLE_OFFSET_POSITION_Y; exports.PARTICLE_OFFSET_SIZE = PARTICLE_OFFSET_SIZE; exports.PARTICLE_OFFSET_VELOCITY_X = PARTICLE_OFFSET_VELOCITY_X; exports.PARTICLE_OFFSET_VELOCITY_Y = PARTICLE_OFFSET_VELOCITY_Y; exports.PARTICLE_STRIDE_FLOATS = PARTICLE_STRIDE_FLOATS; exports.REDUCED_MOTION_FPS = REDUCED_MOTION_FPS; exports.Rect = Rect; exports.SCENE_OPTION_KEYS = SCENE_OPTION_KEYS; exports.SVGEntity = _chunkZ3HFY75Rjs.SVGEntity; exports.SVGRenderer = _chunkKHGHP2J3js.SVGRenderer; exports.Scene = Scene; exports.SplineEntity = SplineEntity; exports.TextEntity = TextEntity; exports.TextRasterCache = _chunkKHGHP2J3js.TextRasterCache; exports.VECTO_USER_TIMING = VECTO_USER_TIMING; exports.VectoJSEvent = _chunkZ3HFY75Rjs.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkKHGHP2J3js.WebGPUParticleSystemManager; exports.beginVectoUserTiming = beginVectoUserTiming; exports.createWebGLPointRenderer = _chunkKHGHP2J3js.createWebGLPointRenderer; exports.endVectoUserTiming = endVectoUserTiming; exports.isSafeUrl = _chunkKHGHP2J3js.isSafeUrl; exports.loadSpline = loadSpline; exports.measureVectoUserTiming = measureVectoUserTiming; exports.parseColorToRGBA = _chunkKHGHP2J3js.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkKHGHP2J3js.sanitizeUrl;
6632
+ exports.CanvasRenderer = _chunkK2UGEIT6js.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Entity = _chunkZ3HFY75Rjs.Entity; exports.GlyphRasterAtlas = _chunkK2UGEIT6js.GlyphRasterAtlas; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.MSDFTextEntity = _chunkZ3HFY75Rjs.MSDFTextEntity; exports.PARTICLE_OFFSET_LIFE = PARTICLE_OFFSET_LIFE; exports.PARTICLE_OFFSET_ORIGIN_X = PARTICLE_OFFSET_ORIGIN_X; exports.PARTICLE_OFFSET_ORIGIN_Y = PARTICLE_OFFSET_ORIGIN_Y; exports.PARTICLE_OFFSET_POSITION_X = PARTICLE_OFFSET_POSITION_X; exports.PARTICLE_OFFSET_POSITION_Y = PARTICLE_OFFSET_POSITION_Y; exports.PARTICLE_OFFSET_SIZE = PARTICLE_OFFSET_SIZE; exports.PARTICLE_OFFSET_VELOCITY_X = PARTICLE_OFFSET_VELOCITY_X; exports.PARTICLE_OFFSET_VELOCITY_Y = PARTICLE_OFFSET_VELOCITY_Y; exports.PARTICLE_STRIDE_FLOATS = PARTICLE_STRIDE_FLOATS; exports.REDUCED_MOTION_FPS = REDUCED_MOTION_FPS; exports.Rect = Rect; exports.SCENE_OPTION_KEYS = SCENE_OPTION_KEYS; exports.SVGEntity = _chunkZ3HFY75Rjs.SVGEntity; exports.SVGRenderer = _chunkK2UGEIT6js.SVGRenderer; exports.Scene = Scene; exports.SplineEntity = SplineEntity; exports.TextEntity = TextEntity; exports.TextRasterCache = _chunkK2UGEIT6js.TextRasterCache; exports.VECTO_USER_TIMING = VECTO_USER_TIMING; exports.VectoJSEvent = _chunkZ3HFY75Rjs.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkK2UGEIT6js.WebGPUParticleSystemManager; exports.beginVectoUserTiming = beginVectoUserTiming; exports.createWebGLPointRenderer = _chunkK2UGEIT6js.createWebGLPointRenderer; exports.endVectoUserTiming = endVectoUserTiming; exports.installRendererDevTraps = _chunkK2UGEIT6js.installRendererDevTraps; exports.isRendererDevMode = _chunkK2UGEIT6js.isRendererDevMode; exports.isSafeUrl = _chunkK2UGEIT6js.isSafeUrl; exports.loadSpline = loadSpline; exports.measureVectoUserTiming = measureVectoUserTiming; exports.parseColorToRGBA = _chunkK2UGEIT6js.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkK2UGEIT6js.sanitizeUrl; exports.setRendererDevMode = _chunkK2UGEIT6js.setRendererDevMode;
package/dist/index.mjs CHANGED
@@ -5,10 +5,13 @@ import {
5
5
  TextRasterCache,
6
6
  WebGPUParticleSystemManager,
7
7
  createWebGLPointRenderer,
8
+ installRendererDevTraps,
9
+ isRendererDevMode,
8
10
  isSafeUrl,
9
11
  parseColorToRGBA,
10
- sanitizeUrl
11
- } from "./chunk-I4WQY7CJ.mjs";
12
+ sanitizeUrl,
13
+ setRendererDevMode
14
+ } from "./chunk-TI5EMJGL.mjs";
12
15
  import {
13
16
  Entity,
14
17
  MSDFTextEntity,
@@ -2839,10 +2842,26 @@ var Scene = class _Scene {
2839
2842
  //
2840
2843
  // Checks run once every ~120 frames (~2s at 60fps) to keep overhead
2841
2844
  // negligible even when dev mode is on.
2842
- /** Toggle development-mode runtime warnings globally. */
2843
- static devMode = false;
2845
+ static _devMode = false;
2846
+ /**
2847
+ * Toggle development-mode runtime warnings globally.
2848
+ *
2849
+ * An accessor rather than a plain field so the renderer layer learns about it
2850
+ * immediately: renderers cannot import `Scene` (the dependency runs
2851
+ * `Scene → renderer`), and their diagnostics are installed per instance at
2852
+ * construction. A plain field would only reach them the next time a `Scene`
2853
+ * happened to be built, which made a directly-constructed `CanvasRenderer`
2854
+ * silently untrapped.
2855
+ */
2856
+ static get devMode() {
2857
+ return _Scene._devMode;
2858
+ }
2859
+ static set devMode(active) {
2860
+ _Scene._devMode = active;
2861
+ setRendererDevMode(active);
2862
+ }
2844
2863
  static _devModeDetected() {
2845
- if (_Scene.devMode) return true;
2864
+ if (_Scene._devMode) return true;
2846
2865
  const gp = typeof globalThis !== "undefined" ? globalThis : void 0;
2847
2866
  if (gp?.__DEV__) return true;
2848
2867
  if (gp?.process?.env?.NODE_ENV === "development") return true;
@@ -2951,6 +2970,7 @@ var Scene = class _Scene {
2951
2970
  this.readingDirection = options.readingDirection ?? "ltr";
2952
2971
  this.renderMode = options.renderMode ?? "always";
2953
2972
  this._devActive = _Scene._devModeDetected();
2973
+ setRendererDevMode(this._devActive);
2954
2974
  this._warnUnknownOptions(options);
2955
2975
  this.reducedMotionQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
2956
2976
  if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
@@ -3619,10 +3639,24 @@ var Scene = class _Scene {
3619
3639
  * resume when it returns — instead of running the full update/render every
3620
3640
  * frame for a scene nobody can see. No-op (stays "on screen") where
3621
3641
  * `IntersectionObserver` is unavailable, so SSR/jsdom behavior is unchanged.
3642
+ *
3643
+ * Also a no-op for a canvas that is not in the document. An offscreen canvas
3644
+ * used purely as a texture source — `@vectojs/three`'s `ThreeAdapter` wraps
3645
+ * one in a `CanvasTexture`, and the same pattern shows up in any
3646
+ * render-to-texture setup — is never appended anywhere, and an
3647
+ * `IntersectionObserver` reports a detached element as not intersecting.
3648
+ * Observing it would therefore set `_canvasOnScreen = false` on the first
3649
+ * callback, and since {@link loop} returns without rescheduling in that
3650
+ * state, the loop would stop permanently: the only resume path is an
3651
+ * `isIntersecting` transition, which a detached element can never produce.
3652
+ * Such a canvas is always "visible" as far as this scene is concerned,
3653
+ * because whether its output is seen depends on the consumer sampling the
3654
+ * texture, which this scene cannot observe.
3622
3655
  */
3623
3656
  watchCanvasVisibility() {
3624
3657
  if (this._canvasObserver || typeof IntersectionObserver === "undefined") return;
3625
3658
  if (!this.canvas || typeof this.canvas.getBoundingClientRect !== "function") return;
3659
+ if (this.canvas.isConnected === false) return;
3626
3660
  this._canvasObserver = new IntersectionObserver((entries) => {
3627
3661
  const entry = entries[entries.length - 1];
3628
3662
  if (!entry) return;
@@ -6585,10 +6619,13 @@ export {
6585
6619
  beginVectoUserTiming,
6586
6620
  createWebGLPointRenderer,
6587
6621
  endVectoUserTiming,
6622
+ installRendererDevTraps,
6623
+ isRendererDevMode,
6588
6624
  isSafeUrl,
6589
6625
  loadSpline,
6590
6626
  measureVectoUserTiming,
6591
6627
  parseColorToRGBA,
6592
6628
  polySegmentToBezier,
6593
- sanitizeUrl
6629
+ sanitizeUrl,
6630
+ setRendererDevMode
6594
6631
  };
@@ -299,3 +299,25 @@ export interface IRenderer {
299
299
  */
300
300
  onContextRestored?(cb: () => void): void;
301
301
  }
302
+ /**
303
+ * Publish dev-mode state to the renderer layer. Called by `Scene`; also usable
304
+ * directly when a renderer is constructed without one.
305
+ */
306
+ export declare function setRendererDevMode(active: boolean): void;
307
+ /** Whether renderer dev diagnostics are currently enabled. */
308
+ export declare function isRendererDevMode(): boolean;
309
+ /**
310
+ * Install dev-mode-only accessors that warn when Canvas2D style *properties* are
311
+ * assigned on a renderer instead of calling the corresponding method.
312
+ *
313
+ * Call once per renderer instance, from its constructor. No-ops outside dev
314
+ * mode, so the accessors never exist in production.
315
+ * Each trapped property warns on its **first** write only — a per-frame
316
+ * assignment would otherwise flood the console at 240fps — and then stores and
317
+ * returns the value like a plain field, so a warned write is never a hard break
318
+ * for code that assigns and reads back.
319
+ *
320
+ * Skips any property the instance genuinely defines, so a backend that really
321
+ * does expose one keeps its own behavior.
322
+ */
323
+ export declare function installRendererDevTraps(renderer: object, label: string): void;
package/dist/renderer.js CHANGED
@@ -7,13 +7,19 @@
7
7
 
8
8
 
9
9
 
10
- var _chunkKHGHP2J3js = require('./chunk-KHGHP2J3.js');
11
10
 
12
11
 
13
12
 
13
+ var _chunkK2UGEIT6js = require('./chunk-K2UGEIT6.js');
14
14
 
15
15
 
16
16
 
17
17
 
18
18
 
19
- exports.CanvasRenderer = _chunkKHGHP2J3js.CanvasRenderer; exports.GlyphRasterAtlas = _chunkKHGHP2J3js.GlyphRasterAtlas; exports.SVGRenderer = _chunkKHGHP2J3js.SVGRenderer; exports.TextRasterCache = _chunkKHGHP2J3js.TextRasterCache; exports.WebGPUParticleSystemManager = _chunkKHGHP2J3js.WebGPUParticleSystemManager; exports.createWebGLPointRenderer = _chunkKHGHP2J3js.createWebGLPointRenderer; exports.parseColorToRGBA = _chunkKHGHP2J3js.parseColorToRGBA;
19
+
20
+
21
+
22
+
23
+
24
+
25
+ exports.CanvasRenderer = _chunkK2UGEIT6js.CanvasRenderer; exports.GlyphRasterAtlas = _chunkK2UGEIT6js.GlyphRasterAtlas; exports.SVGRenderer = _chunkK2UGEIT6js.SVGRenderer; exports.TextRasterCache = _chunkK2UGEIT6js.TextRasterCache; exports.WebGPUParticleSystemManager = _chunkK2UGEIT6js.WebGPUParticleSystemManager; exports.createWebGLPointRenderer = _chunkK2UGEIT6js.createWebGLPointRenderer; exports.installRendererDevTraps = _chunkK2UGEIT6js.installRendererDevTraps; exports.isRendererDevMode = _chunkK2UGEIT6js.isRendererDevMode; exports.parseColorToRGBA = _chunkK2UGEIT6js.parseColorToRGBA; exports.setRendererDevMode = _chunkK2UGEIT6js.setRendererDevMode;
package/dist/renderer.mjs CHANGED
@@ -5,8 +5,11 @@ import {
5
5
  TextRasterCache,
6
6
  WebGPUParticleSystemManager,
7
7
  createWebGLPointRenderer,
8
- parseColorToRGBA
9
- } from "./chunk-I4WQY7CJ.mjs";
8
+ installRendererDevTraps,
9
+ isRendererDevMode,
10
+ parseColorToRGBA,
11
+ setRendererDevMode
12
+ } from "./chunk-TI5EMJGL.mjs";
10
13
  export {
11
14
  CanvasRenderer,
12
15
  GlyphRasterAtlas,
@@ -14,5 +17,8 @@ export {
14
17
  TextRasterCache,
15
18
  WebGPUParticleSystemManager,
16
19
  createWebGLPointRenderer,
17
- parseColorToRGBA
20
+ installRendererDevTraps,
21
+ isRendererDevMode,
22
+ parseColorToRGBA,
23
+ setRendererDevMode
18
24
  };
@@ -979,8 +979,19 @@ export declare class Scene {
979
979
  private pointerEventTarget;
980
980
  private hasWarnedZeroSize;
981
981
  private fontLoadHandler;
982
- /** Toggle development-mode runtime warnings globally. */
983
- static devMode: boolean;
982
+ private static _devMode;
983
+ /**
984
+ * Toggle development-mode runtime warnings globally.
985
+ *
986
+ * An accessor rather than a plain field so the renderer layer learns about it
987
+ * immediately: renderers cannot import `Scene` (the dependency runs
988
+ * `Scene → renderer`), and their diagnostics are installed per instance at
989
+ * construction. A plain field would only reach them the next time a `Scene`
990
+ * happened to be built, which made a directly-constructed `CanvasRenderer`
991
+ * silently untrapped.
992
+ */
993
+ static get devMode(): boolean;
994
+ static set devMode(active: boolean);
984
995
  private static _devModeDetected;
985
996
  private _devActive;
986
997
  private _devFrameCount;
@@ -1157,6 +1168,19 @@ export declare class Scene {
1157
1168
  * resume when it returns — instead of running the full update/render every
1158
1169
  * frame for a scene nobody can see. No-op (stays "on screen") where
1159
1170
  * `IntersectionObserver` is unavailable, so SSR/jsdom behavior is unchanged.
1171
+ *
1172
+ * Also a no-op for a canvas that is not in the document. An offscreen canvas
1173
+ * used purely as a texture source — `@vectojs/three`'s `ThreeAdapter` wraps
1174
+ * one in a `CanvasTexture`, and the same pattern shows up in any
1175
+ * render-to-texture setup — is never appended anywhere, and an
1176
+ * `IntersectionObserver` reports a detached element as not intersecting.
1177
+ * Observing it would therefore set `_canvasOnScreen = false` on the first
1178
+ * callback, and since {@link loop} returns without rescheduling in that
1179
+ * state, the loop would stop permanently: the only resume path is an
1180
+ * `isIntersecting` transition, which a detached element can never produce.
1181
+ * Such a canvas is always "visible" as far as this scene is concerned,
1182
+ * because whether its output is seen depends on the consumer sampling the
1183
+ * texture, which this scene cannot observe.
1160
1184
  */
1161
1185
  private watchCanvasVisibility;
1162
1186
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectojs/core",
3
- "version": "1.26.0",
3
+ "version": "1.27.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },