@vectojs/core 1.10.0 → 1.11.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.
@@ -710,6 +710,25 @@ var Entity = (_class4 = class {
710
710
  handlers.forEach((h) => h(payload));
711
711
  }
712
712
  }
713
+ /**
714
+ * Programmatically focus the entity's projected a11y shadow element, if one
715
+ * exists. After `scene.add(entity)` the shadow element is typically created
716
+ * on the next a11y sync (within one animation frame), so this method retries
717
+ * once on the next rAF if the element isn't immediately available — matching
718
+ * the timing pattern the prior workaround described in findings.md achieved
719
+ * with `requestAnimationFrame(() => document.getElementById(id)?.focus())`.
720
+ */
721
+ focus() {
722
+ const el = _optionalChain([this, 'access', _57 => _57.scene, 'optionalAccess', _58 => _58.getA11yElement, 'call', _59 => _59(this.id)]);
723
+ if (el) {
724
+ el.focus();
725
+ return;
726
+ }
727
+ requestAnimationFrame(() => {
728
+ const retry = _optionalChain([this, 'access', _60 => _60.scene, 'optionalAccess', _61 => _61.getA11yElement, 'call', _62 => _62(this.id)]);
729
+ if (retry) retry.focus();
730
+ });
731
+ }
713
732
  /** Run one node's listeners for the event, honoring stopImmediatePropagation. */
714
733
  fireListeners(node, map, event) {
715
734
  const handlers = map.get(event.type);
@@ -1141,7 +1160,7 @@ var MSDFTextEntity = (_class6 = class extends Entity {
1141
1160
  if (res.seqId < this.lastRenderedSeqId) return;
1142
1161
  this.lastRenderedSeqId = res.seqId;
1143
1162
  this.layoutResult = res;
1144
- _optionalChain([this, 'access', _57 => _57.scene, 'optionalAccess', _58 => _58.markDirty, 'call', _59 => _59()]);
1163
+ _optionalChain([this, 'access', _63 => _63.scene, 'optionalAccess', _64 => _64.markDirty, 'call', _65 => _65()]);
1145
1164
  }
1146
1165
  });
1147
1166
  }
@@ -710,6 +710,25 @@ var Entity = class {
710
710
  handlers.forEach((h) => h(payload));
711
711
  }
712
712
  }
713
+ /**
714
+ * Programmatically focus the entity's projected a11y shadow element, if one
715
+ * exists. After `scene.add(entity)` the shadow element is typically created
716
+ * on the next a11y sync (within one animation frame), so this method retries
717
+ * once on the next rAF if the element isn't immediately available — matching
718
+ * the timing pattern the prior workaround described in findings.md achieved
719
+ * with `requestAnimationFrame(() => document.getElementById(id)?.focus())`.
720
+ */
721
+ focus() {
722
+ const el = this.scene?.getA11yElement(this.id);
723
+ if (el) {
724
+ el.focus();
725
+ return;
726
+ }
727
+ requestAnimationFrame(() => {
728
+ const retry = this.scene?.getA11yElement(this.id);
729
+ if (retry) retry.focus();
730
+ });
731
+ }
713
732
  /** Run one node's listeners for the event, honoring stopImmediatePropagation. */
714
733
  fireListeners(node, map, event) {
715
734
  const handlers = map.get(event.type);
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ var _chunkORCPCIJ7js = require('./chunk-ORCPCIJ7.js');
27
27
 
28
28
 
29
29
 
30
- var _chunkGKLTTGBRjs = require('./chunk-GKLTTGBR.js');
30
+ var _chunk2Z23LTH3js = require('./chunk-2Z23LTH3.js');
31
31
 
32
32
 
33
33
 
@@ -44,7 +44,7 @@ var PARTICLE_OFFSET_ORIGIN_X = 4;
44
44
  var PARTICLE_OFFSET_ORIGIN_Y = 5;
45
45
  var PARTICLE_OFFSET_SIZE = 6;
46
46
  var PARTICLE_OFFSET_LIFE = 7;
47
- var ComputeParticleEntity = (_class = class extends _chunkGKLTTGBRjs.Entity {
47
+ var ComputeParticleEntity = (_class = class extends _chunk2Z23LTH3js.Entity {
48
48
 
49
49
 
50
50
 
@@ -735,14 +735,75 @@ var Scene = (_class2 = class _Scene {
735
735
  __init59() {this.pointerLeaveListener = null}
736
736
  __init60() {this.hasWarnedZeroSize = false}
737
737
  __init61() {this.fontLoadHandler = null}
738
- constructor(canvas, options = {}) {;_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);_class2.prototype.__init10.call(this);_class2.prototype.__init11.call(this);_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);_class2.prototype.__init35.call(this);_class2.prototype.__init36.call(this);_class2.prototype.__init37.call(this);_class2.prototype.__init38.call(this);_class2.prototype.__init39.call(this);_class2.prototype.__init40.call(this);_class2.prototype.__init41.call(this);_class2.prototype.__init42.call(this);_class2.prototype.__init43.call(this);_class2.prototype.__init44.call(this);_class2.prototype.__init45.call(this);_class2.prototype.__init46.call(this);_class2.prototype.__init47.call(this);_class2.prototype.__init48.call(this);_class2.prototype.__init49.call(this);_class2.prototype.__init50.call(this);_class2.prototype.__init51.call(this);_class2.prototype.__init52.call(this);_class2.prototype.__init53.call(this);_class2.prototype.__init54.call(this);_class2.prototype.__init55.call(this);_class2.prototype.__init56.call(this);_class2.prototype.__init57.call(this);_class2.prototype.__init58.call(this);_class2.prototype.__init59.call(this);_class2.prototype.__init60.call(this);_class2.prototype.__init61.call(this);
738
+ // ── Dev-mode warning infrastructure ──────────────────────────────
739
+ //
740
+ // Enable with `Scene.devMode = true` or by setting `globalThis.__DEV__`.
741
+ // Auto-detected when `NODE_ENV === 'development'`.
742
+ //
743
+ // Checks run once every ~120 frames (~2s at 60fps) to keep overhead
744
+ // negligible even when dev mode is on.
745
+ /** Toggle development-mode runtime warnings globally. */
746
+ static __initStatic3() {this.devMode = false}
747
+ static _devModeDetected() {
748
+ if (_Scene.devMode) return true;
749
+ const gp = typeof globalThis !== "undefined" ? globalThis : void 0;
750
+ if (_optionalChain([gp, 'optionalAccess', _23 => _23.__DEV__])) return true;
751
+ if (_optionalChain([gp, 'optionalAccess', _24 => _24.process, 'optionalAccess', _25 => _25.env, 'optionalAccess', _26 => _26.NODE_ENV]) === "development") return true;
752
+ return false;
753
+ }
754
+
755
+ __init62() {this._devFrameCount = 0}
756
+ _devWarn(message) {
757
+ if (!this._devActive) return;
758
+ console.warn(`[vectojs/dev] ${message}`);
759
+ }
760
+ /** @internal Periodic dev checks — called once per frame in dev mode. */
761
+ _devRunChecks() {
762
+ this._devFrameCount++;
763
+ if (this._devFrameCount % 120 !== 0) return;
764
+ if (this.a11yElements) {
765
+ let interactiveCount = 0;
766
+ const walk = (node) => {
767
+ if (node.interactive && node.width > 0) interactiveCount++;
768
+ for (const c of node.children) walk(c);
769
+ };
770
+ walk(this.root);
771
+ for (const c of this.overlayRoot.children) walk(c);
772
+ const shadowCount = this.a11yElements.size;
773
+ if (shadowCount > interactiveCount + 2) {
774
+ this._devWarn(
775
+ `a11yElements (${shadowCount}) exceeds interactive entities (${interactiveCount}). Call scene.detachA11y(entity) before removing interactive children from the tree, or their shadow nodes leak.`
776
+ );
777
+ }
778
+ }
779
+ let checked = 0;
780
+ const walkProjections = (node) => {
781
+ if (checked > 10) return;
782
+ const proj = _optionalChain([node, 'access', _27 => _27.getContentProjection, 'optionalCall', _28 => _28()]);
783
+ if (_optionalChain([proj, 'optionalAccess', _29 => _29.text]) && proj.selectable !== false) {
784
+ const el = _optionalChain([this, 'access', _30 => _30.contentElements, 'optionalAccess', _31 => _31.get, 'call', _32 => _32(node.id)]);
785
+ if (el) {
786
+ const projectedText = el.textContent || "";
787
+ if (projectedText !== "" && projectedText !== proj.text) {
788
+ this._devWarn(
789
+ `Content projection mismatch for entity "${node.id}": projection says "${proj.text.slice(0, 60)}" but DOM shows "${projectedText.slice(0, 60)}". Ensure getContentProjection() output matches what drawSelf renders.`
790
+ );
791
+ }
792
+ }
793
+ }
794
+ checked++;
795
+ for (const c of node.children) walkProjections(c);
796
+ };
797
+ walkProjections(this.root);
798
+ }
799
+ constructor(canvas, options = {}) {;_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);_class2.prototype.__init10.call(this);_class2.prototype.__init11.call(this);_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);_class2.prototype.__init35.call(this);_class2.prototype.__init36.call(this);_class2.prototype.__init37.call(this);_class2.prototype.__init38.call(this);_class2.prototype.__init39.call(this);_class2.prototype.__init40.call(this);_class2.prototype.__init41.call(this);_class2.prototype.__init42.call(this);_class2.prototype.__init43.call(this);_class2.prototype.__init44.call(this);_class2.prototype.__init45.call(this);_class2.prototype.__init46.call(this);_class2.prototype.__init47.call(this);_class2.prototype.__init48.call(this);_class2.prototype.__init49.call(this);_class2.prototype.__init50.call(this);_class2.prototype.__init51.call(this);_class2.prototype.__init52.call(this);_class2.prototype.__init53.call(this);_class2.prototype.__init54.call(this);_class2.prototype.__init55.call(this);_class2.prototype.__init56.call(this);_class2.prototype.__init57.call(this);_class2.prototype.__init58.call(this);_class2.prototype.__init59.call(this);_class2.prototype.__init60.call(this);_class2.prototype.__init61.call(this);_class2.prototype.__init62.call(this);
739
800
  this.canvas = canvas;
740
801
  this.debugA11y = _nullishCoalesce(options.debugA11y, () => ( false));
741
802
  this.disableWindowResize = _nullishCoalesce(options.disableWindowResize, () => ( false));
742
803
  this.maxDPR = options.maxDPR;
743
804
  if (this.disableWindowResize) {
744
- const styleWidth = parseInlinePx(_optionalChain([canvas, 'access', _23 => _23.style, 'optionalAccess', _24 => _24.width]));
745
- const styleHeight = parseInlinePx(_optionalChain([canvas, 'access', _25 => _25.style, 'optionalAccess', _26 => _26.height]));
805
+ const styleWidth = parseInlinePx(_optionalChain([canvas, 'access', _33 => _33.style, 'optionalAccess', _34 => _34.width]));
806
+ const styleHeight = parseInlinePx(_optionalChain([canvas, 'access', _35 => _35.style, 'optionalAccess', _36 => _36.height]));
746
807
  this.width = _nullishCoalesce(styleWidth, () => ( (canvas.width || canvas.clientWidth || 0)));
747
808
  this.height = _nullishCoalesce(styleHeight, () => ( (canvas.height || canvas.clientHeight || 0)));
748
809
  } else {
@@ -750,15 +811,16 @@ var Scene = (_class2 = class _Scene {
750
811
  this.height = typeof window !== "undefined" ? window.innerHeight : canvas.clientHeight || canvas.height || 600;
751
812
  }
752
813
  const globalProcess = typeof globalThis !== "undefined" ? globalThis.process : void 0;
753
- const isTest = globalProcess && (_optionalChain([globalProcess, 'access', _27 => _27.env, 'optionalAccess', _28 => _28.NODE_ENV]) === "test" || _optionalChain([globalProcess, 'access', _29 => _29.env, 'optionalAccess', _30 => _30.VITEST]) === "true");
814
+ const isTest = globalProcess && (_optionalChain([globalProcess, 'access', _37 => _37.env, 'optionalAccess', _38 => _38.NODE_ENV]) === "test" || _optionalChain([globalProcess, 'access', _39 => _39.env, 'optionalAccess', _40 => _40.VITEST]) === "true");
754
815
  this.maxFPS = _nullishCoalesce(options.maxFPS, () => ( (isTest ? 0 : 60)));
755
816
  this.respectReducedMotion = _nullishCoalesce(options.respectReducedMotion, () => ( true));
756
817
  this.autoThrottle = _nullishCoalesce(options.autoThrottle, () => ( true));
757
818
  this.particleBackend = _nullishCoalesce(options.particleBackend, () => ( "auto"));
758
819
  this.a11ySyncInterval = _nullishCoalesce(options.a11ySyncInterval, () => ( 0));
759
820
  this.contentProjectionEnabled = _nullishCoalesce(options.contentProjection, () => ( true));
821
+ this._devActive = _Scene._devModeDetected();
760
822
  this.reducedMotionQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
761
- this.root = new class RootEntity extends _chunkGKLTTGBRjs.Entity {
823
+ this.root = new class RootEntity extends _chunk2Z23LTH3js.Entity {
762
824
  isPointInside() {
763
825
  return false;
764
826
  }
@@ -767,7 +829,7 @@ var Scene = (_class2 = class _Scene {
767
829
  }
768
830
  }("root");
769
831
  this.root._scene = this;
770
- this.overlayRoot = new class OverlayRoot extends _chunkGKLTTGBRjs.Entity {
832
+ this.overlayRoot = new class OverlayRoot extends _chunk2Z23LTH3js.Entity {
771
833
  isPointInside() {
772
834
  return false;
773
835
  }
@@ -920,7 +982,7 @@ var Scene = (_class2 = class _Scene {
920
982
  };
921
983
  if (typeof document !== "undefined" && document.fonts) {
922
984
  this.fontLoadHandler = () => {
923
- _chunkGKLTTGBRjs.clearCssLineBoxMetrics.call(void 0, );
985
+ _chunk2Z23LTH3js.clearCssLineBoxMetrics.call(void 0, );
924
986
  this.contentFontEpoch++;
925
987
  this.markDirty();
926
988
  };
@@ -936,10 +998,10 @@ var Scene = (_class2 = class _Scene {
936
998
  }
937
999
  releaseContentSelectionForRebuild(el) {
938
1000
  const selection = typeof window !== "undefined" && typeof window.getSelection === "function" ? window.getSelection() : null;
939
- const ownsSelection = this.contentSelectionAnchor && el.contains(this.contentSelectionAnchor.node) || (_optionalChain([selection, 'optionalAccess', _31 => _31.anchorNode]) ? el.contains(selection.anchorNode) : false) || (_optionalChain([selection, 'optionalAccess', _32 => _32.focusNode]) ? el.contains(selection.focusNode) : false);
1001
+ const ownsSelection = this.contentSelectionAnchor && el.contains(this.contentSelectionAnchor.node) || (_optionalChain([selection, 'optionalAccess', _41 => _41.anchorNode]) ? el.contains(selection.anchorNode) : false) || (_optionalChain([selection, 'optionalAccess', _42 => _42.focusNode]) ? el.contains(selection.focusNode) : false);
940
1002
  if (!ownsSelection) return;
941
1003
  this.endContentSelectionDrag();
942
- _optionalChain([selection, 'optionalAccess', _33 => _33.removeAllRanges, 'call', _34 => _34()]);
1004
+ _optionalChain([selection, 'optionalAccess', _43 => _43.removeAllRanges, 'call', _44 => _44()]);
943
1005
  }
944
1006
  /**
945
1007
  * Expose the underlying {@link IRenderer} for advanced direct-draw operations.
@@ -951,7 +1013,7 @@ var Scene = (_class2 = class _Scene {
951
1013
  }
952
1014
  /** Convert browser viewport coordinates into this Scene's logical coordinates. */
953
1015
  clientToScene(clientX, clientY) {
954
- const rect = _optionalChain([this, 'access', _35 => _35.canvas, 'access', _36 => _36.getBoundingClientRect, 'optionalCall', _37 => _37()]);
1016
+ const rect = _optionalChain([this, 'access', _45 => _45.canvas, 'access', _46 => _46.getBoundingClientRect, 'optionalCall', _47 => _47()]);
955
1017
  if (!rect) return { x: clientX, y: clientY };
956
1018
  const cssWidth = rect.width || this.canvas.clientWidth || this.width;
957
1019
  const cssHeight = rect.height || this.canvas.clientHeight || this.height;
@@ -977,7 +1039,7 @@ var Scene = (_class2 = class _Scene {
977
1039
  cancelAnimationFrame(calibrationFrame);
978
1040
  }
979
1041
  this.contentGridCalibrationFrames.delete(entityId);
980
- _optionalChain([this, 'access', _38 => _38.contentGridCalibrationProbes, 'access', _39 => _39.get, 'call', _40 => _40(entityId), 'optionalAccess', _41 => _41.remove, 'call', _42 => _42()]);
1042
+ _optionalChain([this, 'access', _48 => _48.contentGridCalibrationProbes, 'access', _49 => _49.get, 'call', _50 => _50(entityId), 'optionalAccess', _51 => _51.remove, 'call', _52 => _52()]);
981
1043
  this.contentGridCalibrationProbes.delete(entityId);
982
1044
  delete el.dataset.vectoGridCalibrationPending;
983
1045
  delete el.dataset.vectoGridCalibration;
@@ -1093,8 +1155,8 @@ var Scene = (_class2 = class _Scene {
1093
1155
  this.canvas.removeEventListener("pointerleave", this.pointerLeaveListener);
1094
1156
  }
1095
1157
  }
1096
- _optionalChain([this, 'access', _43 => _43.a11yRoot, 'optionalAccess', _44 => _44.remove, 'call', _45 => _45()]);
1097
- _optionalChain([this, 'access', _46 => _46.portalRoot, 'optionalAccess', _47 => _47.remove, 'call', _48 => _48()]);
1158
+ _optionalChain([this, 'access', _53 => _53.a11yRoot, 'optionalAccess', _54 => _54.remove, 'call', _55 => _55()]);
1159
+ _optionalChain([this, 'access', _56 => _56.portalRoot, 'optionalAccess', _57 => _57.remove, 'call', _58 => _58()]);
1098
1160
  this.a11yElements.clear();
1099
1161
  for (const el of this.contentElements.values()) el.remove();
1100
1162
  this.contentElements.clear();
@@ -1107,10 +1169,10 @@ var Scene = (_class2 = class _Scene {
1107
1169
  for (const probe of this.contentGridCalibrationProbes.values()) probe.remove();
1108
1170
  this.contentGridCalibrationProbes.clear();
1109
1171
  this.endContentSelectionDrag();
1110
- _optionalChain([this, 'access', _49 => _49.pointRenderer, 'optionalAccess', _50 => _50.destroy, 'call', _51 => _51()]);
1111
- _optionalChain([this, 'access', _52 => _52.renderer, 'access', _53 => _53.dispose, 'optionalCall', _54 => _54()]);
1112
- _optionalChain([this, 'access', _55 => _55.glCanvas, 'optionalAccess', _56 => _56.remove, 'call', _57 => _57()]);
1113
- _optionalChain([this, 'access', _58 => _58.gpuCanvas, 'optionalAccess', _59 => _59.remove, 'call', _60 => _60()]);
1172
+ _optionalChain([this, 'access', _59 => _59.pointRenderer, 'optionalAccess', _60 => _60.destroy, 'call', _61 => _61()]);
1173
+ _optionalChain([this, 'access', _62 => _62.renderer, 'access', _63 => _63.dispose, 'optionalCall', _64 => _64()]);
1174
+ _optionalChain([this, 'access', _65 => _65.glCanvas, 'optionalAccess', _66 => _66.remove, 'call', _67 => _67()]);
1175
+ _optionalChain([this, 'access', _68 => _68.gpuCanvas, 'optionalAccess', _69 => _69.remove, 'call', _70 => _70()]);
1114
1176
  this.gpuCanvas = null;
1115
1177
  this.gpuContext = null;
1116
1178
  if (this.recoveryTimerId) {
@@ -1122,7 +1184,7 @@ var Scene = (_class2 = class _Scene {
1122
1184
  this.manager = null;
1123
1185
  }
1124
1186
  if (this.device) {
1125
- _optionalChain([this, 'access', _61 => _61.device, 'access', _62 => _62.destroy, 'optionalCall', _63 => _63()]);
1187
+ _optionalChain([this, 'access', _71 => _71.device, 'access', _72 => _72.destroy, 'optionalCall', _73 => _73()]);
1126
1188
  this.device = null;
1127
1189
  }
1128
1190
  }
@@ -1271,15 +1333,18 @@ var Scene = (_class2 = class _Scene {
1271
1333
  el.style.background = "transparent";
1272
1334
  }
1273
1335
  el.addEventListener("click", (e) => {
1274
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("click", node, e));
1336
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("click", node, e));
1337
+ });
1338
+ el.addEventListener("dblclick", (e) => {
1339
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("dblclick", node, e));
1275
1340
  });
1276
1341
  el.addEventListener("mouseenter", (e) => {
1277
1342
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.2)";
1278
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("hover", node, e, false));
1343
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("hover", node, e, false));
1279
1344
  });
1280
1345
  el.addEventListener("mouseleave", (e) => {
1281
1346
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.05)";
1282
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("pointerleave", node, e, false));
1347
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("pointerleave", node, e, false));
1283
1348
  });
1284
1349
  const capEl = el;
1285
1350
  const releasePointer = (event) => {
@@ -1295,32 +1360,32 @@ var Scene = (_class2 = class _Scene {
1295
1360
  };
1296
1361
  el.addEventListener("pointerdown", (e) => {
1297
1362
  if (typeof capEl.setPointerCapture === "function") capEl.setPointerCapture(e.pointerId);
1298
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("pointerdown", node, e));
1363
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("pointerdown", node, e));
1299
1364
  });
1300
1365
  el.addEventListener("pointerup", (e) => {
1301
1366
  releasePointer(e);
1302
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("pointerup", node, e));
1367
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("pointerup", node, e));
1303
1368
  });
1304
1369
  el.addEventListener("pointercancel", (e) => {
1305
1370
  releasePointer(e);
1306
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("pointercancel", node, e));
1371
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("pointercancel", node, e));
1307
1372
  });
1308
1373
  el.addEventListener(
1309
1374
  "pointermove",
1310
- (e) => node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("pointermove", node, e))
1375
+ (e) => node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("pointermove", node, e))
1311
1376
  );
1312
1377
  el.addEventListener(
1313
1378
  "wheel",
1314
1379
  (e) => {
1315
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("wheel", node, e));
1380
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("wheel", node, e));
1316
1381
  },
1317
1382
  { passive: false }
1318
1383
  );
1319
1384
  el.addEventListener("keydown", (e) => {
1320
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("keydown", node, e));
1385
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("keydown", node, e));
1321
1386
  });
1322
1387
  el.addEventListener("keyup", (e) => {
1323
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("keyup", node, e));
1388
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("keyup", node, e));
1324
1389
  });
1325
1390
  if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
1326
1391
  const input = el;
@@ -1347,7 +1412,7 @@ var Scene = (_class2 = class _Scene {
1347
1412
  });
1348
1413
  el.addEventListener("compositionupdate", (e) => {
1349
1414
  const data = _nullishCoalesce(e.data, () => ( ""));
1350
- composition = { start: _nullishCoalesce(_optionalChain([composition, 'optionalAccess', _64 => _64.start]), () => ( 0)), length: data.length };
1415
+ composition = { start: _nullishCoalesce(_optionalChain([composition, 'optionalAccess', _74 => _74.start]), () => ( 0)), length: data.length };
1351
1416
  forward();
1352
1417
  });
1353
1418
  el.addEventListener("compositionend", () => {
@@ -1380,7 +1445,7 @@ var Scene = (_class2 = class _Scene {
1380
1445
  el.addEventListener("keydown", (e) => {
1381
1446
  if (e.key === "Enter" || e.key === " ") {
1382
1447
  e.preventDefault();
1383
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("click", node, e));
1448
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("click", node, e));
1384
1449
  }
1385
1450
  });
1386
1451
  }
@@ -1539,7 +1604,7 @@ var Scene = (_class2 = class _Scene {
1539
1604
  el.addEventListener(
1540
1605
  "wheel",
1541
1606
  (e2) => {
1542
- node.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)("wheel", node, e2));
1607
+ node.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)("wheel", node, e2));
1543
1608
  },
1544
1609
  { passive: false }
1545
1610
  );
@@ -1570,7 +1635,7 @@ var Scene = (_class2 = class _Scene {
1570
1635
  lineElement.style.position = "absolute";
1571
1636
  lineElement.dir = "auto";
1572
1637
  lineElement.style.left = `${line.x}px`;
1573
- lineElement.style.top = `${line.y + line.baseline - _chunkGKLTTGBRjs.cssLineBoxBaseline.call(void 0, lineFont, lineHeight2)}px`;
1638
+ lineElement.style.top = `${line.y + line.baseline - _chunk2Z23LTH3js.cssLineBoxBaseline.call(void 0, lineFont, lineHeight2)}px`;
1574
1639
  lineElement.style.whiteSpace = "pre";
1575
1640
  if (lineFont) lineElement.style.font = lineFont;
1576
1641
  lineElement.style.lineHeight = `${lineHeight2}px`;
@@ -1622,7 +1687,7 @@ var Scene = (_class2 = class _Scene {
1622
1687
  const { a, b, c, d, e, f } = node.getWorldTransform();
1623
1688
  const contentX = _nullishCoalesce(projection.contentX, () => ( 0));
1624
1689
  const contentY = _nullishCoalesce(projection.contentY, () => ( 0));
1625
- const baselineOffset = lines && lines.length > 0 ? 0 : projection.baseline === void 0 ? 0 : projection.baseline - _chunkGKLTTGBRjs.cssLineBoxBaseline.call(void 0, font, _nullishCoalesce(projection.lineHeight, () => ( 16)));
1690
+ const baselineOffset = lines && lines.length > 0 ? 0 : projection.baseline === void 0 ? 0 : projection.baseline - _chunk2Z23LTH3js.cssLineBoxBaseline.call(void 0, font, _nullishCoalesce(projection.lineHeight, () => ( 16)));
1626
1691
  const localY = contentY + baselineOffset;
1627
1692
  el.style.left = `${e + a * contentX + c * localY}px`;
1628
1693
  el.style.top = `${f + b * contentX + d * localY}px`;
@@ -1686,15 +1751,15 @@ var Scene = (_class2 = class _Scene {
1686
1751
  for (let lineIndex = 0; lineIndex < grid.lines.length; lineIndex++) {
1687
1752
  const gridLine = grid.lines[lineIndex];
1688
1753
  const projectedLine = projectionLines[lineIndex];
1689
- const lineHeight = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _65 => _65.lineHeight]), () => ( grid.lineHeight));
1690
- const baseline = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _66 => _66.baseline]), () => ( grid.baseline));
1691
- const lineFont = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _67 => _67.font]), () => ( grid.font));
1754
+ const lineHeight = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _75 => _75.lineHeight]), () => ( grid.lineHeight));
1755
+ const baseline = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _76 => _76.baseline]), () => ( grid.baseline));
1756
+ const lineFont = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _77 => _77.font]), () => ( grid.font));
1692
1757
  const lineElement = document.createElement("span");
1693
1758
  lineElement.dir = "ltr";
1694
1759
  lineElement.dataset.vectoGridLine = `${lineIndex}`;
1695
1760
  lineElement.style.position = "absolute";
1696
- lineElement.style.left = `${_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _68 => _68.x]), () => ( 0))}px`;
1697
- lineElement.style.top = `${(_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _69 => _69.y]), () => ( lineIndex * grid.lineHeight))) + baseline - _chunkGKLTTGBRjs.cssLineBoxBaseline.call(void 0, lineFont, lineHeight)}px`;
1761
+ lineElement.style.left = `${_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _78 => _78.x]), () => ( 0))}px`;
1762
+ lineElement.style.top = `${(_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _79 => _79.y]), () => ( lineIndex * grid.lineHeight))) + baseline - _chunk2Z23LTH3js.cssLineBoxBaseline.call(void 0, lineFont, lineHeight)}px`;
1698
1763
  lineElement.style.width = `${gridLine.width}px`;
1699
1764
  lineElement.style.height = `${lineHeight}px`;
1700
1765
  lineElement.style.whiteSpace = "pre";
@@ -1790,7 +1855,7 @@ var Scene = (_class2 = class _Scene {
1790
1855
  if (previous !== void 0 && typeof cancelAnimationFrame === "function") {
1791
1856
  cancelAnimationFrame(previous);
1792
1857
  }
1793
- _optionalChain([this, 'access', _70 => _70.contentGridCalibrationProbes, 'access', _71 => _71.get, 'call', _72 => _72(entityId), 'optionalAccess', _73 => _73.remove, 'call', _74 => _74()]);
1858
+ _optionalChain([this, 'access', _80 => _80.contentGridCalibrationProbes, 'access', _81 => _81.get, 'call', _82 => _82(entityId), 'optionalAccess', _83 => _83.remove, 'call', _84 => _84()]);
1794
1859
  this.contentGridCalibrationProbes.delete(entityId);
1795
1860
  const calibrationStart = typeof performance !== "undefined" ? performance.now() : 0;
1796
1861
  const probe = document.createElement("div");
@@ -1820,7 +1885,7 @@ var Scene = (_class2 = class _Scene {
1820
1885
  const sourceLength = Number(_nullishCoalesce(target.dataset.vectoGridSourceLength, () => ( 0)));
1821
1886
  const targetWidth = Number(_nullishCoalesce(target.dataset.vectoGridAdvance, () => ( 0)));
1822
1887
  if (sourceLength <= 0 || targetWidth <= 0) continue;
1823
- const sourceText = _nullishCoalesce(_optionalChain([target, 'access', _75 => _75.textContent, 'optionalAccess', _76 => _76.slice, 'call', _77 => _77(0, sourceLength)]), () => ( ""));
1888
+ const sourceText = _nullishCoalesce(_optionalChain([target, 'access', _85 => _85.textContent, 'optionalAccess', _86 => _86.slice, 'call', _87 => _87(0, sourceLength)]), () => ( ""));
1824
1889
  if (!sourceText) continue;
1825
1890
  const measurementKey = JSON.stringify([
1826
1891
  target.style.font,
@@ -1970,12 +2035,12 @@ var Scene = (_class2 = class _Scene {
1970
2035
  syncOverlayGeometry() {
1971
2036
  const parent = this.canvas.parentElement;
1972
2037
  if (!parent) return;
1973
- const canvasRect = _optionalChain([this, 'access', _78 => _78.canvas, 'access', _79 => _79.getBoundingClientRect, 'optionalCall', _80 => _80()]);
1974
- const parentRect = _optionalChain([parent, 'access', _81 => _81.getBoundingClientRect, 'optionalCall', _82 => _82()]);
1975
- const cssWidth = _optionalChain([canvasRect, 'optionalAccess', _83 => _83.width]) || this.canvas.clientWidth || this.width;
1976
- const cssHeight = _optionalChain([canvasRect, 'optionalAccess', _84 => _84.height]) || this.canvas.clientHeight || this.height;
1977
- const left = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _85 => _85.left]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _86 => _86.left]), () => ( 0))) - (parent.clientLeft || 0) + parent.scrollLeft;
1978
- const top = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _87 => _87.top]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _88 => _88.top]), () => ( 0))) - (parent.clientTop || 0) + parent.scrollTop;
2038
+ const canvasRect = _optionalChain([this, 'access', _88 => _88.canvas, 'access', _89 => _89.getBoundingClientRect, 'optionalCall', _90 => _90()]);
2039
+ const parentRect = _optionalChain([parent, 'access', _91 => _91.getBoundingClientRect, 'optionalCall', _92 => _92()]);
2040
+ const cssWidth = _optionalChain([canvasRect, 'optionalAccess', _93 => _93.width]) || this.canvas.clientWidth || this.width;
2041
+ const cssHeight = _optionalChain([canvasRect, 'optionalAccess', _94 => _94.height]) || this.canvas.clientHeight || this.height;
2042
+ const left = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _95 => _95.left]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _96 => _96.left]), () => ( 0))) - (parent.clientLeft || 0) + parent.scrollLeft;
2043
+ const top = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _97 => _97.top]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _98 => _98.top]), () => ( 0))) - (parent.clientTop || 0) + parent.scrollTop;
1979
2044
  const scaleX = this.width > 0 ? cssWidth / this.width : 1;
1980
2045
  const scaleY = this.height > 0 ? cssHeight / this.height : 1;
1981
2046
  for (const root of [this.a11yRoot, this.portalRoot]) {
@@ -2100,7 +2165,7 @@ var Scene = (_class2 = class _Scene {
2100
2165
  * (and {@link respectReducedMotion} is on). `0` means uncapped.
2101
2166
  */
2102
2167
  effectiveMaxFPS() {
2103
- const reduced = this.respectReducedMotion && !!_optionalChain([this, 'access', _89 => _89.reducedMotionQuery, 'optionalAccess', _90 => _90.matches]);
2168
+ const reduced = this.respectReducedMotion && !!_optionalChain([this, 'access', _99 => _99.reducedMotionQuery, 'optionalAccess', _100 => _100.matches]);
2104
2169
  if (reduced)
2105
2170
  return this.maxFPS > 0 ? Math.min(this.maxFPS, REDUCED_MOTION_FPS) : REDUCED_MOTION_FPS;
2106
2171
  return this.maxFPS;
@@ -2278,7 +2343,7 @@ var Scene = (_class2 = class _Scene {
2278
2343
  }
2279
2344
  renderer.clear();
2280
2345
  if (isMainRenderer) {
2281
- _optionalChain([this, 'access', _91 => _91.pointRenderer, 'optionalAccess', _92 => _92.begin, 'call', _93 => _93()]);
2346
+ _optionalChain([this, 'access', _101 => _101.pointRenderer, 'optionalAccess', _102 => _102.begin, 'call', _103 => _103()]);
2282
2347
  }
2283
2348
  const vw = this.width;
2284
2349
  const vh = this.height;
@@ -2289,6 +2354,13 @@ var Scene = (_class2 = class _Scene {
2289
2354
  node.update(dt, time);
2290
2355
  if (!walkHadAnimation && node.hasPendingAnimations()) walkHadAnimation = true;
2291
2356
  if (!walkHadInteractive && node.interactive) walkHadInteractive = true;
2357
+ if (this._devActive && this._devFrameCount % 120 === 0) {
2358
+ if (node.update !== _chunk2Z23LTH3js.Entity.prototype.update && node.hasPendingAnimations === _chunk2Z23LTH3js.Entity.prototype.hasPendingAnimations) {
2359
+ this._devWarn(
2360
+ `Entity "${node.id}" overrides update() but not hasPendingAnimations(). Custom motion in update() without overriding hasPendingAnimations() causes the idle throttle to drop the animation to ~2fps. Override hasPendingAnimations() to return true while motion is in flight.`
2361
+ );
2362
+ }
2363
+ }
2292
2364
  }
2293
2365
  const cos = Math.cos(node.rotation);
2294
2366
  const sin = Math.sin(node.rotation);
@@ -2416,9 +2488,13 @@ var Scene = (_class2 = class _Scene {
2416
2488
  }
2417
2489
  renderer.flush();
2418
2490
  if (isMainRenderer) {
2419
- _optionalChain([this, 'access', _94 => _94.pointRenderer, 'optionalAccess', _95 => _95.flush, 'call', _96 => _96()]);
2491
+ _optionalChain([this, 'access', _104 => _104.pointRenderer, 'optionalAccess', _105 => _105.flush, 'call', _106 => _106()]);
2492
+ }
2493
+ _optionalChain([renderer, 'access', _107 => _107.present, 'optionalCall', _108 => _108()]);
2494
+ if (this._devActive) {
2495
+ this._devFrameCount++;
2496
+ this._devRunChecks();
2420
2497
  }
2421
- _optionalChain([renderer, 'access', _97 => _97.present, 'optionalCall', _98 => _98()]);
2422
2498
  }
2423
2499
  /**
2424
2500
  * Export the current scene state to a lightweight, flat SVG XML string.
@@ -2622,7 +2698,7 @@ var Scene = (_class2 = class _Scene {
2622
2698
  }
2623
2699
  return null;
2624
2700
  }
2625
- }, _class2.__initStatic(), _class2.__initStatic2(), _class2);
2701
+ }, _class2.__initStatic(), _class2.__initStatic2(), _class2.__initStatic3(), _class2);
2626
2702
 
2627
2703
  // src/components/TextEntity.ts
2628
2704
  var sharedMeasurer;
@@ -2630,20 +2706,20 @@ function defaultMeasurer() {
2630
2706
  if (sharedMeasurer === void 0) sharedMeasurer = _chunkBA5HUUDFjs.createCanvasMeasurer.call(void 0, "sans-serif");
2631
2707
  return sharedMeasurer;
2632
2708
  }
2633
- var TextEntity = (_class3 = class extends _chunkGKLTTGBRjs.Entity {
2709
+ var TextEntity = (_class3 = class extends _chunk2Z23LTH3js.Entity {
2634
2710
 
2635
2711
 
2636
2712
 
2637
2713
 
2638
- __init62() {this.nodes = []}
2714
+ __init63() {this.nodes = []}
2639
2715
 
2640
- __init63() {this.fillStyle = "#94a3b8"}
2641
- __init64() {this.strokeStyle = null}
2642
- __init65() {this.hoveredFillStyle = "#ffffff"}
2643
- __init66() {this.lineWidth = 1}
2644
- __init67() {this.isHovered = false}
2716
+ __init64() {this.fillStyle = "#94a3b8"}
2717
+ __init65() {this.strokeStyle = null}
2718
+ __init66() {this.hoveredFillStyle = "#ffffff"}
2719
+ __init67() {this.lineWidth = 1}
2720
+ __init68() {this.isHovered = false}
2645
2721
  constructor(text, atlas, maxWidth, fontSize = 24) {
2646
- super();_class3.prototype.__init62.call(this);_class3.prototype.__init63.call(this);_class3.prototype.__init64.call(this);_class3.prototype.__init65.call(this);_class3.prototype.__init66.call(this);_class3.prototype.__init67.call(this);;
2722
+ super();_class3.prototype.__init63.call(this);_class3.prototype.__init64.call(this);_class3.prototype.__init65.call(this);_class3.prototype.__init66.call(this);_class3.prototype.__init67.call(this);_class3.prototype.__init68.call(this);;
2647
2723
  this.text = text;
2648
2724
  this.atlas = atlas;
2649
2725
  this.fontSize = fontSize;
@@ -2756,17 +2832,17 @@ var TextEntity = (_class3 = class extends _chunkGKLTTGBRjs.Entity {
2756
2832
  }, _class3);
2757
2833
 
2758
2834
  // src/components/GridTextEntity.ts
2759
- var GridTextEntity = (_class4 = class extends _chunkGKLTTGBRjs.Entity {
2835
+ var GridTextEntity = (_class4 = class extends _chunk2Z23LTH3js.Entity {
2760
2836
 
2761
- __init68() {this.fillStyle = "#ffffff"}
2762
- __init69() {this.grid = []}
2837
+ __init69() {this.fillStyle = "#ffffff"}
2838
+ __init70() {this.grid = []}
2763
2839
  // Array of rows
2764
- __init70() {this.cols = 0}
2765
- __init71() {this.rows = 0}
2840
+ __init71() {this.cols = 0}
2841
+ __init72() {this.rows = 0}
2766
2842
 
2767
2843
 
2768
2844
  constructor(_atlas, fontSize = 10) {
2769
- super();_class4.prototype.__init68.call(this);_class4.prototype.__init69.call(this);_class4.prototype.__init70.call(this);_class4.prototype.__init71.call(this);;
2845
+ super();_class4.prototype.__init69.call(this);_class4.prototype.__init70.call(this);_class4.prototype.__init71.call(this);_class4.prototype.__init72.call(this);;
2770
2846
  this.fontSize = fontSize;
2771
2847
  this.charWidth = fontSize * 1;
2772
2848
  this.charHeight = fontSize * 1.1;
@@ -2775,7 +2851,7 @@ var GridTextEntity = (_class4 = class extends _chunkGKLTTGBRjs.Entity {
2775
2851
  updateGrid(ascii) {
2776
2852
  this.grid = ascii;
2777
2853
  this.rows = ascii.length;
2778
- this.cols = _optionalChain([ascii, 'access', _99 => _99[0], 'optionalAccess', _100 => _100.length]) || 0;
2854
+ this.cols = _optionalChain([ascii, 'access', _109 => _109[0], 'optionalAccess', _110 => _110.length]) || 0;
2779
2855
  }
2780
2856
  isPointInside(_globalX, _globalY) {
2781
2857
  return false;
@@ -2850,7 +2926,7 @@ function distSqToSegment(px, py, x1, y1, x2, y2) {
2850
2926
  const ey = py - cy;
2851
2927
  return ex * ex + ey * ey;
2852
2928
  }
2853
- var SplineEntity = (_class5 = class extends _chunkGKLTTGBRjs.Entity {
2929
+ var SplineEntity = (_class5 = class extends _chunk2Z23LTH3js.Entity {
2854
2930
 
2855
2931
 
2856
2932
 
@@ -2858,23 +2934,23 @@ var SplineEntity = (_class5 = class extends _chunkGKLTTGBRjs.Entity {
2858
2934
 
2859
2935
 
2860
2936
 
2861
- __init72() {this.offscreen = null}
2862
- __init73() {this.baked = false}
2937
+ __init73() {this.offscreen = null}
2938
+ __init74() {this.baked = false}
2863
2939
  /** Logical (CSS-pixel) size of the baked bitmap — the blit destination size. */
2864
- __init74() {this.bakedWidth = 0}
2865
- __init75() {this.bakedHeight = 0}
2940
+ __init75() {this.bakedWidth = 0}
2941
+ __init76() {this.bakedHeight = 0}
2866
2942
  /** Gradient strokes can't be baked to a solid-color bitmap; they render per-frame. */
2867
2943
 
2868
2944
  /** Lazily-flattened polylines (one Float32Array of [x,y,...] per segment) for hit-testing. */
2869
- __init76() {this.polylines = null}
2945
+ __init77() {this.polylines = null}
2870
2946
  /**
2871
2947
  * When `true`, the renderer draws a rounded-rect outline of the entity's
2872
2948
  * local bounds after painting the curves. Useful for drag feedback and
2873
2949
  * debugging hit areas. Defaults to `false`.
2874
2950
  */
2875
- __init77() {this.showBounds = false}
2951
+ __init78() {this.showBounds = false}
2876
2952
  constructor(doc, opts = {}) {
2877
- super();_class5.prototype.__init72.call(this);_class5.prototype.__init73.call(this);_class5.prototype.__init74.call(this);_class5.prototype.__init75.call(this);_class5.prototype.__init76.call(this);_class5.prototype.__init77.call(this);;
2953
+ super();_class5.prototype.__init73.call(this);_class5.prototype.__init74.call(this);_class5.prototype.__init75.call(this);_class5.prototype.__init76.call(this);_class5.prototype.__init77.call(this);_class5.prototype.__init78.call(this);;
2878
2954
  this.doc = doc;
2879
2955
  this.lineWidth = _nullishCoalesce(opts.lineWidth, () => ( 2));
2880
2956
  this.cache = _nullishCoalesce(opts.cache, () => ( true));
@@ -2885,7 +2961,7 @@ var SplineEntity = (_class5 = class extends _chunkGKLTTGBRjs.Entity {
2885
2961
  this.width = this.bounds.width;
2886
2962
  this.height = this.bounds.height;
2887
2963
  const isGradient = (c) => c !== null && !Array.isArray(c);
2888
- this.containsGradient = (_nullishCoalesce(_optionalChain([this, 'access', _101 => _101.doc, 'access', _102 => _102.equations, 'optionalAccess', _103 => _103.some, 'call', _104 => _104((eq) => isGradient(eq.color_rgb))]), () => ( false))) || (_nullishCoalesce(_optionalChain([this, 'access', _105 => _105.doc, 'access', _106 => _106.paths, 'optionalAccess', _107 => _107.some, 'call', _108 => _108((p) => isGradient(p.color_rgb))]), () => ( false)));
2964
+ this.containsGradient = (_nullishCoalesce(_optionalChain([this, 'access', _111 => _111.doc, 'access', _112 => _112.equations, 'optionalAccess', _113 => _113.some, 'call', _114 => _114((eq) => isGradient(eq.color_rgb))]), () => ( false))) || (_nullishCoalesce(_optionalChain([this, 'access', _115 => _115.doc, 'access', _116 => _116.paths, 'optionalAccess', _117 => _117.some, 'call', _118 => _118((p) => isGradient(p.color_rgb))]), () => ( false)));
2889
2965
  this.interactive = true;
2890
2966
  }
2891
2967
  computeBounds() {
@@ -3125,7 +3201,7 @@ async function loadSpline(url) {
3125
3201
  }
3126
3202
 
3127
3203
  // src/components/Rect.ts
3128
- var Rect = class extends _chunkGKLTTGBRjs.Entity {
3204
+ var Rect = class extends _chunk2Z23LTH3js.Entity {
3129
3205
 
3130
3206
 
3131
3207
 
@@ -3174,7 +3250,7 @@ var Rect = class extends _chunkGKLTTGBRjs.Entity {
3174
3250
  };
3175
3251
 
3176
3252
  // src/components/Circle.ts
3177
- var Circle = class extends _chunkGKLTTGBRjs.Entity {
3253
+ var Circle = class extends _chunk2Z23LTH3js.Entity {
3178
3254
 
3179
3255
 
3180
3256
 
@@ -3234,7 +3310,7 @@ var Circle = class extends _chunkGKLTTGBRjs.Entity {
3234
3310
  };
3235
3311
 
3236
3312
  // src/components/Group.ts
3237
- var Group = class extends _chunkGKLTTGBRjs.Entity {
3313
+ var Group = class extends _chunk2Z23LTH3js.Entity {
3238
3314
  constructor(...children) {
3239
3315
  super();
3240
3316
  if (children.length > 0) this.add(...children);
@@ -3249,9 +3325,9 @@ var Group = class extends _chunkGKLTTGBRjs.Entity {
3249
3325
  // src/math/SpatialHashGrid.ts
3250
3326
  var SpatialHashGrid = (_class6 = class {
3251
3327
 
3252
- __init78() {this.grid = /* @__PURE__ */ new Map()}
3253
- __init79() {this.entityCells = /* @__PURE__ */ new Map()}
3254
- constructor(cellSize = 64) {;_class6.prototype.__init78.call(this);_class6.prototype.__init79.call(this);
3328
+ __init79() {this.grid = /* @__PURE__ */ new Map()}
3329
+ __init80() {this.entityCells = /* @__PURE__ */ new Map()}
3330
+ constructor(cellSize = 64) {;_class6.prototype.__init79.call(this);_class6.prototype.__init80.call(this);
3255
3331
  this.cellSize = cellSize;
3256
3332
  }
3257
3333
  hash(cx, cy) {
@@ -3305,7 +3381,7 @@ var SpatialHashGrid = (_class6 = class {
3305
3381
  const keys = this.entityCells.get(id);
3306
3382
  if (!keys) return;
3307
3383
  for (const key of keys) {
3308
- _optionalChain([this, 'access', _109 => _109.grid, 'access', _110 => _110.get, 'call', _111 => _111(key), 'optionalAccess', _112 => _112.delete, 'call', _113 => _113(id)]);
3384
+ _optionalChain([this, 'access', _119 => _119.grid, 'access', _120 => _120.get, 'call', _121 => _121(key), 'optionalAccess', _122 => _122.delete, 'call', _123 => _123(id)]);
3309
3385
  }
3310
3386
  this.entityCells.delete(id);
3311
3387
  }
@@ -3341,20 +3417,20 @@ var SpatialHashGrid = (_class6 = class {
3341
3417
  }, _class6);
3342
3418
 
3343
3419
  // src/tree/DOMPortalEntity.ts
3344
- var DOMPortalEntity = (_class7 = class extends _chunkGKLTTGBRjs.Entity {
3420
+ var DOMPortalEntity = (_class7 = class extends _chunk2Z23LTH3js.Entity {
3345
3421
 
3346
- __init80() {this.isDOMPortal = true}
3347
- __init81() {this.domListeners = []}
3348
- __init82() {this.resizeObserver = null}
3349
- __init83() {this.cachedWidth = 100}
3350
- __init84() {this.cachedHeight = 100}
3351
- __init85() {this.lastWidth = ""}
3352
- __init86() {this.lastHeight = ""}
3353
- __init87() {this.lastTransform = ""}
3354
- __init88() {this.lastZIndex = ""}
3355
- __init89() {this.lastOpacity = ""}
3422
+ __init81() {this.isDOMPortal = true}
3423
+ __init82() {this.domListeners = []}
3424
+ __init83() {this.resizeObserver = null}
3425
+ __init84() {this.cachedWidth = 100}
3426
+ __init85() {this.cachedHeight = 100}
3427
+ __init86() {this.lastWidth = ""}
3428
+ __init87() {this.lastHeight = ""}
3429
+ __init88() {this.lastTransform = ""}
3430
+ __init89() {this.lastZIndex = ""}
3431
+ __init90() {this.lastOpacity = ""}
3356
3432
  constructor(domElement, width, height, id) {
3357
- super(id);_class7.prototype.__init80.call(this);_class7.prototype.__init81.call(this);_class7.prototype.__init82.call(this);_class7.prototype.__init83.call(this);_class7.prototype.__init84.call(this);_class7.prototype.__init85.call(this);_class7.prototype.__init86.call(this);_class7.prototype.__init87.call(this);_class7.prototype.__init88.call(this);_class7.prototype.__init89.call(this);;
3433
+ super(id);_class7.prototype.__init81.call(this);_class7.prototype.__init82.call(this);_class7.prototype.__init83.call(this);_class7.prototype.__init84.call(this);_class7.prototype.__init85.call(this);_class7.prototype.__init86.call(this);_class7.prototype.__init87.call(this);_class7.prototype.__init88.call(this);_class7.prototype.__init89.call(this);_class7.prototype.__init90.call(this);;
3358
3434
  this.domElement = domElement;
3359
3435
  this.width = _nullishCoalesce(width, () => ( 0));
3360
3436
  this.height = _nullishCoalesce(height, () => ( 0));
@@ -3383,7 +3459,7 @@ var DOMPortalEntity = (_class7 = class extends _chunkGKLTTGBRjs.Entity {
3383
3459
  ];
3384
3460
  for (const type of events) {
3385
3461
  const handler = (e) => {
3386
- this.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)(type, this, e));
3462
+ this.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)(type, this, e));
3387
3463
  };
3388
3464
  this.domElement.addEventListener(type, handler);
3389
3465
  this.domListeners.push({ type, handler, capture: false });
@@ -3394,7 +3470,7 @@ var DOMPortalEntity = (_class7 = class extends _chunkGKLTTGBRjs.Entity {
3394
3470
  ];
3395
3471
  for (const { native, vecto } of hoverEvents) {
3396
3472
  const handler = (e) => {
3397
- this.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)(vecto, this, e, false));
3473
+ this.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)(vecto, this, e, false));
3398
3474
  };
3399
3475
  this.domElement.addEventListener(native, handler);
3400
3476
  this.domListeners.push({ type: native, handler, capture: false });
@@ -3402,7 +3478,7 @@ var DOMPortalEntity = (_class7 = class extends _chunkGKLTTGBRjs.Entity {
3402
3478
  const focusEvents = ["focus", "blur"];
3403
3479
  for (const type of focusEvents) {
3404
3480
  const handler = (e) => {
3405
- this.dispatchEvent(new (0, _chunkGKLTTGBRjs.VectoJSEvent)(type, this, e, true));
3481
+ this.dispatchEvent(new (0, _chunk2Z23LTH3js.VectoJSEvent)(type, this, e, true));
3406
3482
  };
3407
3483
  this.domElement.addEventListener(type, handler, true);
3408
3484
  this.domListeners.push({ type, handler, capture: true });
@@ -3493,4 +3569,4 @@ Scene.registerWebGPUParticleSystemManager(_chunkORCPCIJ7js.WebGPUParticleSystemM
3493
3569
 
3494
3570
 
3495
3571
 
3496
- exports.ArabicShaper = _chunk4AR425ARjs.ArabicShaper; exports.BidiResolver = _chunk4AR425ARjs.BidiResolver; exports.CanvasRenderer = _chunkORCPCIJ7js.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Easing = _chunkGKLTTGBRjs.Easing; exports.Entity = _chunkGKLTTGBRjs.Entity; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.LayoutEngine = _chunkBA5HUUDFjs.LayoutEngine; exports.LayoutResultBuffer = _chunkBA5HUUDFjs.LayoutResultBuffer; exports.LayoutWorkerManager = _chunk4AR425ARjs.LayoutWorkerManager; exports.MSDFFont = _chunkGKLTTGBRjs.MSDFFont; exports.MSDFTextEntity = _chunkGKLTTGBRjs.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.SVGEntity = _chunkGKLTTGBRjs.SVGEntity; exports.SVGRenderer = _chunkORCPCIJ7js.SVGRenderer; exports.Scene = Scene; exports.SpatialHashGrid = SpatialHashGrid; exports.SplineEntity = SplineEntity; exports.SpringDriver = _chunkGKLTTGBRjs.SpringDriver; exports.SpringPhysics = _chunkGKLTTGBRjs.SpringPhysics; exports.TextEntity = TextEntity; exports.TweenDriver = _chunkGKLTTGBRjs.TweenDriver; exports.VectoJSEvent = _chunkGKLTTGBRjs.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkORCPCIJ7js.WebGPUParticleSystemManager; exports.clearCssLineBoxMetrics = _chunkGKLTTGBRjs.clearCssLineBoxMetrics; exports.computeLineSegments = _chunkBA5HUUDFjs.computeLineSegments; exports.createCanvasMeasurer = _chunkBA5HUUDFjs.createCanvasMeasurer; exports.createWebGLPointRenderer = _chunkORCPCIJ7js.createWebGLPointRenderer; exports.cssLineBoxBaseline = _chunkGKLTTGBRjs.cssLineBoxBaseline; exports.isSafeUrl = _chunkORCPCIJ7js.isSafeUrl; exports.isTweenConfig = _chunkGKLTTGBRjs.isTweenConfig; exports.loadSpline = loadSpline; exports.parseColorToRGBA = _chunkORCPCIJ7js.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.prepareContentGrid = _chunkGKLTTGBRjs.prepareContentGrid; exports.sanitizeUrl = _chunkORCPCIJ7js.sanitizeUrl;
3572
+ exports.ArabicShaper = _chunk4AR425ARjs.ArabicShaper; exports.BidiResolver = _chunk4AR425ARjs.BidiResolver; exports.CanvasRenderer = _chunkORCPCIJ7js.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Easing = _chunk2Z23LTH3js.Easing; exports.Entity = _chunk2Z23LTH3js.Entity; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.LayoutEngine = _chunkBA5HUUDFjs.LayoutEngine; exports.LayoutResultBuffer = _chunkBA5HUUDFjs.LayoutResultBuffer; exports.LayoutWorkerManager = _chunk4AR425ARjs.LayoutWorkerManager; exports.MSDFFont = _chunk2Z23LTH3js.MSDFFont; exports.MSDFTextEntity = _chunk2Z23LTH3js.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.SVGEntity = _chunk2Z23LTH3js.SVGEntity; exports.SVGRenderer = _chunkORCPCIJ7js.SVGRenderer; exports.Scene = Scene; exports.SpatialHashGrid = SpatialHashGrid; exports.SplineEntity = SplineEntity; exports.SpringDriver = _chunk2Z23LTH3js.SpringDriver; exports.SpringPhysics = _chunk2Z23LTH3js.SpringPhysics; exports.TextEntity = TextEntity; exports.TweenDriver = _chunk2Z23LTH3js.TweenDriver; exports.VectoJSEvent = _chunk2Z23LTH3js.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkORCPCIJ7js.WebGPUParticleSystemManager; exports.clearCssLineBoxMetrics = _chunk2Z23LTH3js.clearCssLineBoxMetrics; exports.computeLineSegments = _chunkBA5HUUDFjs.computeLineSegments; exports.createCanvasMeasurer = _chunkBA5HUUDFjs.createCanvasMeasurer; exports.createWebGLPointRenderer = _chunkORCPCIJ7js.createWebGLPointRenderer; exports.cssLineBoxBaseline = _chunk2Z23LTH3js.cssLineBoxBaseline; exports.isSafeUrl = _chunkORCPCIJ7js.isSafeUrl; exports.isTweenConfig = _chunk2Z23LTH3js.isTweenConfig; exports.loadSpline = loadSpline; exports.parseColorToRGBA = _chunkORCPCIJ7js.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.prepareContentGrid = _chunk2Z23LTH3js.prepareContentGrid; exports.sanitizeUrl = _chunkORCPCIJ7js.sanitizeUrl;
package/dist/index.mjs CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  cssLineBoxBaseline,
28
28
  isTweenConfig,
29
29
  prepareContentGrid
30
- } from "./chunk-J2P6QZJV.mjs";
30
+ } from "./chunk-XIEQHSBB.mjs";
31
31
  import {
32
32
  ArabicShaper,
33
33
  BidiResolver,
@@ -735,6 +735,67 @@ var Scene = class _Scene {
735
735
  pointerLeaveListener = null;
736
736
  hasWarnedZeroSize = false;
737
737
  fontLoadHandler = null;
738
+ // ── Dev-mode warning infrastructure ──────────────────────────────
739
+ //
740
+ // Enable with `Scene.devMode = true` or by setting `globalThis.__DEV__`.
741
+ // Auto-detected when `NODE_ENV === 'development'`.
742
+ //
743
+ // Checks run once every ~120 frames (~2s at 60fps) to keep overhead
744
+ // negligible even when dev mode is on.
745
+ /** Toggle development-mode runtime warnings globally. */
746
+ static devMode = false;
747
+ static _devModeDetected() {
748
+ if (_Scene.devMode) return true;
749
+ const gp = typeof globalThis !== "undefined" ? globalThis : void 0;
750
+ if (gp?.__DEV__) return true;
751
+ if (gp?.process?.env?.NODE_ENV === "development") return true;
752
+ return false;
753
+ }
754
+ _devActive;
755
+ _devFrameCount = 0;
756
+ _devWarn(message) {
757
+ if (!this._devActive) return;
758
+ console.warn(`[vectojs/dev] ${message}`);
759
+ }
760
+ /** @internal Periodic dev checks — called once per frame in dev mode. */
761
+ _devRunChecks() {
762
+ this._devFrameCount++;
763
+ if (this._devFrameCount % 120 !== 0) return;
764
+ if (this.a11yElements) {
765
+ let interactiveCount = 0;
766
+ const walk = (node) => {
767
+ if (node.interactive && node.width > 0) interactiveCount++;
768
+ for (const c of node.children) walk(c);
769
+ };
770
+ walk(this.root);
771
+ for (const c of this.overlayRoot.children) walk(c);
772
+ const shadowCount = this.a11yElements.size;
773
+ if (shadowCount > interactiveCount + 2) {
774
+ this._devWarn(
775
+ `a11yElements (${shadowCount}) exceeds interactive entities (${interactiveCount}). Call scene.detachA11y(entity) before removing interactive children from the tree, or their shadow nodes leak.`
776
+ );
777
+ }
778
+ }
779
+ let checked = 0;
780
+ const walkProjections = (node) => {
781
+ if (checked > 10) return;
782
+ const proj = node.getContentProjection?.();
783
+ if (proj?.text && proj.selectable !== false) {
784
+ const el = this.contentElements?.get(node.id);
785
+ if (el) {
786
+ const projectedText = el.textContent || "";
787
+ if (projectedText !== "" && projectedText !== proj.text) {
788
+ this._devWarn(
789
+ `Content projection mismatch for entity "${node.id}": projection says "${proj.text.slice(0, 60)}" but DOM shows "${projectedText.slice(0, 60)}". Ensure getContentProjection() output matches what drawSelf renders.`
790
+ );
791
+ }
792
+ }
793
+ }
794
+ checked++;
795
+ for (const c of node.children) walkProjections(c);
796
+ };
797
+ walkProjections(this.root);
798
+ }
738
799
  constructor(canvas, options = {}) {
739
800
  this.canvas = canvas;
740
801
  this.debugA11y = options.debugA11y ?? false;
@@ -757,6 +818,7 @@ var Scene = class _Scene {
757
818
  this.particleBackend = options.particleBackend ?? "auto";
758
819
  this.a11ySyncInterval = options.a11ySyncInterval ?? 0;
759
820
  this.contentProjectionEnabled = options.contentProjection ?? true;
821
+ this._devActive = _Scene._devModeDetected();
760
822
  this.reducedMotionQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
761
823
  this.root = new class RootEntity extends Entity {
762
824
  isPointInside() {
@@ -1273,6 +1335,9 @@ var Scene = class _Scene {
1273
1335
  el.addEventListener("click", (e) => {
1274
1336
  node.dispatchEvent(new VectoJSEvent("click", node, e));
1275
1337
  });
1338
+ el.addEventListener("dblclick", (e) => {
1339
+ node.dispatchEvent(new VectoJSEvent("dblclick", node, e));
1340
+ });
1276
1341
  el.addEventListener("mouseenter", (e) => {
1277
1342
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.2)";
1278
1343
  node.dispatchEvent(new VectoJSEvent("hover", node, e, false));
@@ -2289,6 +2354,13 @@ var Scene = class _Scene {
2289
2354
  node.update(dt, time);
2290
2355
  if (!walkHadAnimation && node.hasPendingAnimations()) walkHadAnimation = true;
2291
2356
  if (!walkHadInteractive && node.interactive) walkHadInteractive = true;
2357
+ if (this._devActive && this._devFrameCount % 120 === 0) {
2358
+ if (node.update !== Entity.prototype.update && node.hasPendingAnimations === Entity.prototype.hasPendingAnimations) {
2359
+ this._devWarn(
2360
+ `Entity "${node.id}" overrides update() but not hasPendingAnimations(). Custom motion in update() without overriding hasPendingAnimations() causes the idle throttle to drop the animation to ~2fps. Override hasPendingAnimations() to return true while motion is in flight.`
2361
+ );
2362
+ }
2363
+ }
2292
2364
  }
2293
2365
  const cos = Math.cos(node.rotation);
2294
2366
  const sin = Math.sin(node.rotation);
@@ -2419,6 +2491,10 @@ var Scene = class _Scene {
2419
2491
  this.pointRenderer?.flush();
2420
2492
  }
2421
2493
  renderer.present?.();
2494
+ if (this._devActive) {
2495
+ this._devFrameCount++;
2496
+ this._devRunChecks();
2497
+ }
2422
2498
  }
2423
2499
  /**
2424
2500
  * Export the current scene state to a lightweight, flat SVG XML string.
package/dist/text.js CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
 
7
7
 
8
- var _chunkGKLTTGBRjs = require('./chunk-GKLTTGBR.js');
8
+ var _chunk2Z23LTH3js = require('./chunk-2Z23LTH3.js');
9
9
 
10
10
 
11
11
 
@@ -19,4 +19,4 @@ var _chunk4AR425ARjs = require('./chunk-4AR425AR.js');
19
19
 
20
20
 
21
21
 
22
- exports.ArabicShaper = _chunk4AR425ARjs.ArabicShaper; exports.BidiResolver = _chunk4AR425ARjs.BidiResolver; exports.MSDFFont = _chunkGKLTTGBRjs.MSDFFont; exports.MSDFTextEntity = _chunkGKLTTGBRjs.MSDFTextEntity; exports.SVGEntity = _chunkGKLTTGBRjs.SVGEntity; exports.clearCssLineBoxMetrics = _chunkGKLTTGBRjs.clearCssLineBoxMetrics; exports.cssLineBoxBaseline = _chunkGKLTTGBRjs.cssLineBoxBaseline; exports.prepareContentGrid = _chunkGKLTTGBRjs.prepareContentGrid;
22
+ exports.ArabicShaper = _chunk4AR425ARjs.ArabicShaper; exports.BidiResolver = _chunk4AR425ARjs.BidiResolver; exports.MSDFFont = _chunk2Z23LTH3js.MSDFFont; exports.MSDFTextEntity = _chunk2Z23LTH3js.MSDFTextEntity; exports.SVGEntity = _chunk2Z23LTH3js.SVGEntity; exports.clearCssLineBoxMetrics = _chunk2Z23LTH3js.clearCssLineBoxMetrics; exports.cssLineBoxBaseline = _chunk2Z23LTH3js.cssLineBoxBaseline; exports.prepareContentGrid = _chunk2Z23LTH3js.prepareContentGrid;
package/dist/text.mjs CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  clearCssLineBoxMetrics,
6
6
  cssLineBoxBaseline,
7
7
  prepareContentGrid
8
- } from "./chunk-J2P6QZJV.mjs";
8
+ } from "./chunk-XIEQHSBB.mjs";
9
9
  import {
10
10
  ArabicShaper,
11
11
  BidiResolver
@@ -192,7 +192,7 @@ export interface A11yAttributes {
192
192
  /**
193
193
  * Union of all pointer/interaction events that can be emitted by an {@link Entity}.
194
194
  */
195
- export type VectoEvent = 'click' | 'hover' | 'pointerdown' | 'pointerup' | 'pointercancel' | 'pointermove' | 'pointerleave' | 'change' | 'focus' | 'blur' | 'wheel' | 'keydown' | 'keyup';
195
+ export type VectoEvent = 'click' | 'dblclick' | 'hover' | 'pointerdown' | 'pointerup' | 'pointercancel' | 'pointermove' | 'pointerleave' | 'change' | 'focus' | 'blur' | 'wheel' | 'keydown' | 'keyup';
196
196
  /** Options for {@link Entity.on} / {@link Entity.off}. */
197
197
  export interface ListenerOptions {
198
198
  /** Register the listener for the capture phase (root→target) instead of bubble. */
@@ -470,6 +470,15 @@ export declare abstract class Entity {
470
470
  * @param payload - Arbitrary data forwarded to each listener.
471
471
  */
472
472
  emit(event: VectoEvent, payload: any): void;
473
+ /**
474
+ * Programmatically focus the entity's projected a11y shadow element, if one
475
+ * exists. After `scene.add(entity)` the shadow element is typically created
476
+ * on the next a11y sync (within one animation frame), so this method retries
477
+ * once on the next rAF if the element isn't immediately available — matching
478
+ * the timing pattern the prior workaround described in findings.md achieved
479
+ * with `requestAnimationFrame(() => document.getElementById(id)?.focus())`.
480
+ */
481
+ focus(): void;
473
482
  /** Run one node's listeners for the event, honoring stopImmediatePropagation. */
474
483
  private fireListeners;
475
484
  /**
@@ -233,6 +233,14 @@ export declare class Scene {
233
233
  private pointerLeaveListener;
234
234
  private hasWarnedZeroSize;
235
235
  private fontLoadHandler;
236
+ /** Toggle development-mode runtime warnings globally. */
237
+ static devMode: boolean;
238
+ private static _devModeDetected;
239
+ private _devActive;
240
+ private _devFrameCount;
241
+ private _devWarn;
242
+ /** @internal Periodic dev checks — called once per frame in dev mode. */
243
+ private _devRunChecks;
236
244
  constructor(canvas: HTMLCanvasElement, options?: SceneOptions);
237
245
  private endContentSelectionDrag;
238
246
  private releaseContentSelectionForRebuild;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectojs/core",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },