@vectojs/core 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
 
5
5
 
6
- var _chunkBWLNEJJWjs = require('./chunk-BWLNEJJW.js');
6
+ var _chunkXLZDOFSBjs = require('./chunk-XLZDOFSB.js');
7
7
 
8
8
 
9
9
 
@@ -12,7 +12,7 @@ var _chunkBWLNEJJWjs = require('./chunk-BWLNEJJW.js');
12
12
 
13
13
 
14
14
 
15
- var _chunkGTQRCY6Wjs = require('./chunk-GTQRCY6W.js');
15
+ var _chunkBPMNCGU7js = require('./chunk-BPMNCGU7.js');
16
16
 
17
17
 
18
18
 
@@ -24,7 +24,7 @@ var _chunkGTQRCY6Wjs = require('./chunk-GTQRCY6W.js');
24
24
 
25
25
 
26
26
 
27
- var _chunkDWMQYHNCjs = require('./chunk-DWMQYHNC.js');
27
+ var _chunkU4UYRERWjs = require('./chunk-U4UYRERW.js');
28
28
 
29
29
 
30
30
 
@@ -41,7 +41,7 @@ var PARTICLE_OFFSET_ORIGIN_X = 4;
41
41
  var PARTICLE_OFFSET_ORIGIN_Y = 5;
42
42
  var PARTICLE_OFFSET_SIZE = 6;
43
43
  var PARTICLE_OFFSET_LIFE = 7;
44
- var ComputeParticleEntity = (_class = class extends _chunkDWMQYHNCjs.Entity {
44
+ var ComputeParticleEntity = (_class = class extends _chunkU4UYRERWjs.Entity {
45
45
 
46
46
 
47
47
 
@@ -358,50 +358,55 @@ var Scene = (_class2 = class _Scene {
358
358
  /** DOM nodes mirroring static text content, keyed by entity id. */
359
359
  __init19() {this.contentElements = /* @__PURE__ */ new Map()}
360
360
  __init20() {this.contentProjectionEnabled = true}
361
+ // Animation/interactive flags collected during the render walk (tree-walk
362
+ // fusion): the loop reads last frame's answers instead of re-walking the
363
+ // tree up to 4× per tick. Start true so the first tick stays conservative.
364
+ __init21() {this.frameHadAnimation = true}
365
+ __init22() {this.frameHadInteractive = true}
361
366
 
362
- __init21() {this.focusedA11yElement = null}
363
- __init22() {this.caretBlinkTimer = null}
364
- __init23() {this.a11yNeedsReorder = true}
365
- __init24() {this.portalRoot = null}
366
- __init25() {this.fullViewportElements = []}
367
- __init26() {this.normalElements = []}
368
- __init27() {this.activeIds = /* @__PURE__ */ new Set()}
369
- __init28() {this.activePortalsThisFrame = /* @__PURE__ */ new Set()}
370
- __init29() {this.activePortalsPrevFrame = /* @__PURE__ */ new Set()}
371
- __init30() {this.portalEntities = /* @__PURE__ */ new Map()}
372
- __init31() {this.renderOrderCounter = 0}
367
+ __init23() {this.focusedA11yElement = null}
368
+ __init24() {this.caretBlinkTimer = null}
369
+ __init25() {this.a11yNeedsReorder = true}
370
+ __init26() {this.portalRoot = null}
371
+ __init27() {this.fullViewportElements = []}
372
+ __init28() {this.normalElements = []}
373
+ __init29() {this.activeIds = /* @__PURE__ */ new Set()}
374
+ __init30() {this.activePortalsThisFrame = /* @__PURE__ */ new Set()}
375
+ __init31() {this.activePortalsPrevFrame = /* @__PURE__ */ new Set()}
376
+ __init32() {this.portalEntities = /* @__PURE__ */ new Map()}
377
+ __init33() {this.renderOrderCounter = 0}
373
378
  // Optional WebGL point-cloud layer (see SceneOptions.pointBackend).
374
- __init32() {this.pointRenderer = null}
375
- __init33() {this.glCanvas = null}
379
+ __init34() {this.pointRenderer = null}
380
+ __init35() {this.glCanvas = null}
376
381
 
377
382
 
378
383
 
379
- __init34() {this.disableWindowResize = false}
384
+ __init36() {this.disableWindowResize = false}
380
385
  // WebGPU properties
381
- __init35() {this.destroyed = false}
382
- __init36() {this.device = null}
383
- __init37() {this.deviceLost = false}
384
- __init38() {this.particleBackend = "auto"}
385
- __init39() {this._webgpuDisabled = false}
386
+ __init37() {this.destroyed = false}
387
+ __init38() {this.device = null}
388
+ __init39() {this.deviceLost = false}
389
+ __init40() {this.particleBackend = "auto"}
390
+ __init41() {this._webgpuDisabled = false}
386
391
  get webgpuDisabled() {
387
392
  return this._webgpuDisabled || this.particleBackend === "cpu";
388
393
  }
389
394
  set webgpuDisabled(value) {
390
395
  this._webgpuDisabled = value;
391
396
  }
392
- __init40() {this.recoveryTimerId = null}
393
- __init41() {this.manager = null}
394
- __init42() {this.initializingWebGPU = false}
395
- __init43() {this.gpuCanvas = null}
396
- __init44() {this.gpuContext = null}
397
+ __init42() {this.recoveryTimerId = null}
398
+ __init43() {this.manager = null}
399
+ __init44() {this.initializingWebGPU = false}
400
+ __init45() {this.gpuCanvas = null}
401
+ __init46() {this.gpuContext = null}
397
402
  /** True while the GPU canvas holds a presented particle frame (needs clearing when they leave). */
398
- __init45() {this.gpuHasContent = false}
399
- __init46() {this.mouseX = -9999}
400
- __init47() {this.mouseY = -9999}
401
- __init48() {this.pointerMoveListener = null}
402
- __init49() {this.pointerLeaveListener = null}
403
- __init50() {this.hasWarnedZeroSize = false}
404
- 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);
403
+ __init47() {this.gpuHasContent = false}
404
+ __init48() {this.mouseX = -9999}
405
+ __init49() {this.mouseY = -9999}
406
+ __init50() {this.pointerMoveListener = null}
407
+ __init51() {this.pointerLeaveListener = null}
408
+ __init52() {this.hasWarnedZeroSize = false}
409
+ 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);
405
410
  this.canvas = canvas;
406
411
  this.debugA11y = _nullishCoalesce(options.debugA11y, () => ( false));
407
412
  this.disableWindowResize = _nullishCoalesce(options.disableWindowResize, () => ( false));
@@ -423,7 +428,7 @@ var Scene = (_class2 = class _Scene {
423
428
  this.a11ySyncInterval = _nullishCoalesce(options.a11ySyncInterval, () => ( 0));
424
429
  this.contentProjectionEnabled = _nullishCoalesce(options.contentProjection, () => ( true));
425
430
  this.reducedMotionQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
426
- this.root = new class RootEntity extends _chunkDWMQYHNCjs.Entity {
431
+ this.root = new class RootEntity extends _chunkU4UYRERWjs.Entity {
427
432
  isPointInside() {
428
433
  return false;
429
434
  }
@@ -432,7 +437,7 @@ var Scene = (_class2 = class _Scene {
432
437
  }
433
438
  }("root");
434
439
  this.root._scene = this;
435
- this.overlayRoot = new class OverlayRoot extends _chunkDWMQYHNCjs.Entity {
440
+ this.overlayRoot = new class OverlayRoot extends _chunkU4UYRERWjs.Entity {
436
441
  isPointInside() {
437
442
  return false;
438
443
  }
@@ -443,7 +448,7 @@ var Scene = (_class2 = class _Scene {
443
448
  if (options.renderer) {
444
449
  this.renderer = options.renderer;
445
450
  } else {
446
- this.renderer = new (0, _chunkGTQRCY6Wjs.CanvasRenderer)(
451
+ this.renderer = new (0, _chunkBPMNCGU7js.CanvasRenderer)(
447
452
  canvas,
448
453
  this.disableWindowResize ? { width: this.width, height: this.height } : void 0
449
454
  );
@@ -711,6 +716,18 @@ var Scene = (_class2 = class _Scene {
711
716
  * Essential for deterministic rendering (e.g. video export).
712
717
  * Note: You should call `scene.stop()` before using this to avoid conflict with the rAF loop.
713
718
  */
719
+ /**
720
+ * The scene-graph root entity. Exposed read-only for tooling — the devtools
721
+ * inspector walks it to build the Virtual Math Tree view. Mutate the graph
722
+ * through {@link add}/{@link remove}, not by editing this node directly.
723
+ */
724
+ get rootEntity() {
725
+ return this.root;
726
+ }
727
+ /** The overlay layer root (see {@link showOverlay}), read-only for tooling. */
728
+ get overlayRootEntity() {
729
+ return this.overlayRoot;
730
+ }
714
731
  step(dt) {
715
732
  const time = this.lastTime + dt;
716
733
  this.lastTime = time;
@@ -727,21 +744,7 @@ var Scene = (_class2 = class _Scene {
727
744
  this.dirty = true;
728
745
  }
729
746
  /** True when any node in the subtree has a pending animation. */
730
- hasAnyPendingAnimation(node) {
731
- if (node.hasPendingAnimations()) return true;
732
- for (const child of node.children) {
733
- if (this.hasAnyPendingAnimation(child)) return true;
734
- }
735
- return false;
736
- }
737
747
  /** True when any node in the subtree is interactive (drives a11y sync). */
738
- hasAnyInteractive(node) {
739
- if (node.interactive) return true;
740
- for (const child of node.children) {
741
- if (this.hasAnyInteractive(child)) return true;
742
- }
743
- return false;
744
- }
745
748
  syncA11y(node) {
746
749
  if (!this.a11yRoot) return;
747
750
  if (node.isDOMPortal) {
@@ -787,42 +790,42 @@ var Scene = (_class2 = class _Scene {
787
790
  el.style.background = "transparent";
788
791
  }
789
792
  el.addEventListener("click", (e) => {
790
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("click", node, e));
793
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("click", node, e));
791
794
  });
792
795
  el.addEventListener("mouseenter", (e) => {
793
796
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.2)";
794
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("hover", node, e, false));
797
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("hover", node, e, false));
795
798
  });
796
799
  el.addEventListener("mouseleave", (e) => {
797
800
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.05)";
798
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("pointerleave", node, e, false));
801
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("pointerleave", node, e, false));
799
802
  });
800
803
  const capEl = el;
801
804
  el.addEventListener("pointerdown", (e) => {
802
805
  if (typeof capEl.setPointerCapture === "function") capEl.setPointerCapture(e.pointerId);
803
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("pointerdown", node, e));
806
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("pointerdown", node, e));
804
807
  });
805
808
  el.addEventListener("pointerup", (e) => {
806
809
  if (typeof capEl.releasePointerCapture === "function")
807
810
  capEl.releasePointerCapture(e.pointerId);
808
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("pointerup", node, e));
811
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("pointerup", node, e));
809
812
  });
810
813
  el.addEventListener(
811
814
  "pointermove",
812
- (e) => node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("pointermove", node, e))
815
+ (e) => node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("pointermove", node, e))
813
816
  );
814
817
  el.addEventListener(
815
818
  "wheel",
816
819
  (e) => {
817
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("wheel", node, e));
820
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("wheel", node, e));
818
821
  },
819
822
  { passive: false }
820
823
  );
821
824
  el.addEventListener("keydown", (e) => {
822
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("keydown", node, e));
825
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("keydown", node, e));
823
826
  });
824
827
  el.addEventListener("keyup", (e) => {
825
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("keyup", node, e));
828
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("keyup", node, e));
826
829
  });
827
830
  if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
828
831
  const input = el;
@@ -895,7 +898,7 @@ var Scene = (_class2 = class _Scene {
895
898
  el.addEventListener("keydown", (e) => {
896
899
  if (e.key === "Enter" || e.key === " ") {
897
900
  e.preventDefault();
898
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("click", node, e));
901
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("click", node, e));
899
902
  }
900
903
  });
901
904
  }
@@ -920,7 +923,7 @@ var Scene = (_class2 = class _Scene {
920
923
  if (el.placeholder !== attrs.placeholder) el.placeholder = attrs.placeholder;
921
924
  }
922
925
  if (attrs.href !== void 0 && el instanceof HTMLAnchorElement) {
923
- const safeHref = _chunkGTQRCY6Wjs.sanitizeUrl.call(void 0, attrs.href);
926
+ const safeHref = _chunkBPMNCGU7js.sanitizeUrl.call(void 0, attrs.href);
924
927
  if (el.getAttribute("href") !== safeHref) el.setAttribute("href", safeHref);
925
928
  }
926
929
  if (el instanceof HTMLImageElement) {
@@ -1029,7 +1032,7 @@ var Scene = (_class2 = class _Scene {
1029
1032
  el.addEventListener(
1030
1033
  "wheel",
1031
1034
  (e2) => {
1032
- node.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)("wheel", node, e2));
1035
+ node.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)("wheel", node, e2));
1033
1036
  },
1034
1037
  { passive: false }
1035
1038
  );
@@ -1276,7 +1279,7 @@ var Scene = (_class2 = class _Scene {
1276
1279
  loop(time) {
1277
1280
  if (!this.isRunning) return;
1278
1281
  let cap = this.effectiveMaxFPS();
1279
- const isIdle = !this.dirty && !this.hasAnyPendingAnimation(this.root) && !this.hasAnyPendingAnimation(this.overlayRoot);
1282
+ const isIdle = !this.dirty && !this.frameHadAnimation;
1280
1283
  if (isIdle && this.autoThrottle && this.renderMode === "always" && this.maxFPS > 0) {
1281
1284
  cap = Math.min(cap, 2);
1282
1285
  }
@@ -1292,8 +1295,8 @@ var Scene = (_class2 = class _Scene {
1292
1295
  }
1293
1296
  this.dirty = false;
1294
1297
  this.render(this.renderer, dt, time);
1295
- const hasActiveAnimation = this.hasAnyPendingAnimation(this.root) || this.hasAnyPendingAnimation(this.overlayRoot);
1296
- const hasInteractive = this.hasAnyInteractive(this.root) || this.hasAnyInteractive(this.overlayRoot);
1298
+ const hasActiveAnimation = this.frameHadAnimation;
1299
+ const hasInteractive = this.frameHadInteractive;
1297
1300
  const wantsContentSync = this.contentProjectionEnabled;
1298
1301
  const shouldSyncInterval = this.a11ySyncInterval <= 0 || time - this.lastA11ySync >= this.a11ySyncInterval;
1299
1302
  if ((hasInteractive || this.a11yElements.size > 0 || wantsContentSync) && (shouldSyncInterval || this.a11yPendingSyncAfterAnimation)) {
@@ -1450,8 +1453,14 @@ var Scene = (_class2 = class _Scene {
1450
1453
  }
1451
1454
  const vw = this.width;
1452
1455
  const vh = this.height;
1456
+ let walkHadAnimation = false;
1457
+ let walkHadInteractive = false;
1453
1458
  const renderNode = (node, pa, pb, pc, pd, pe, pf, parentOpacity) => {
1454
- if (isMainRenderer) node.update(dt, time);
1459
+ if (isMainRenderer) {
1460
+ node.update(dt, time);
1461
+ if (!walkHadAnimation && node.hasPendingAnimations()) walkHadAnimation = true;
1462
+ if (!walkHadInteractive && node.interactive) walkHadInteractive = true;
1463
+ }
1455
1464
  const cos = Math.cos(node.rotation);
1456
1465
  const sin = Math.sin(node.rotation);
1457
1466
  const te = pa * node.x + pc * node.y + pe;
@@ -1571,7 +1580,11 @@ var Scene = (_class2 = class _Scene {
1571
1580
  for (const overlay of this.overlayRoot.children) {
1572
1581
  renderNode(overlay, 1, 0, 0, 1, 0, 0, 1);
1573
1582
  }
1574
- if (isMainRenderer) this.reconcilePortals();
1583
+ if (isMainRenderer) {
1584
+ this.frameHadAnimation = walkHadAnimation;
1585
+ this.frameHadInteractive = walkHadInteractive;
1586
+ this.reconcilePortals();
1587
+ }
1575
1588
  renderer.flush();
1576
1589
  if (isMainRenderer) {
1577
1590
  _optionalChain([this, 'access', _64 => _64.pointRenderer, 'optionalAccess', _65 => _65.flush, 'call', _66 => _66()]);
@@ -1582,7 +1595,7 @@ var Scene = (_class2 = class _Scene {
1582
1595
  * Export the current scene state to a lightweight, flat SVG XML string.
1583
1596
  */
1584
1597
  toSVG() {
1585
- const renderer = new (0, _chunkGTQRCY6Wjs.SVGRenderer)(this.width, this.height);
1598
+ const renderer = new (0, _chunkBPMNCGU7js.SVGRenderer)(this.width, this.height);
1586
1599
  this.render(renderer, 0, 0);
1587
1600
  return renderer.toXMLString();
1588
1601
  }
@@ -1776,27 +1789,27 @@ var Scene = (_class2 = class _Scene {
1776
1789
  // src/components/TextEntity.ts
1777
1790
  var sharedMeasurer;
1778
1791
  function defaultMeasurer() {
1779
- if (sharedMeasurer === void 0) sharedMeasurer = _chunkBWLNEJJWjs.createCanvasMeasurer.call(void 0, "sans-serif");
1792
+ if (sharedMeasurer === void 0) sharedMeasurer = _chunkXLZDOFSBjs.createCanvasMeasurer.call(void 0, "sans-serif");
1780
1793
  return sharedMeasurer;
1781
1794
  }
1782
- var TextEntity = (_class3 = class extends _chunkDWMQYHNCjs.Entity {
1795
+ var TextEntity = (_class3 = class extends _chunkU4UYRERWjs.Entity {
1783
1796
 
1784
1797
 
1785
1798
 
1786
1799
 
1787
- __init51() {this.nodes = []}
1800
+ __init53() {this.nodes = []}
1788
1801
 
1789
- __init52() {this.fillStyle = "#94a3b8"}
1790
- __init53() {this.strokeStyle = null}
1791
- __init54() {this.hoveredFillStyle = "#ffffff"}
1792
- __init55() {this.lineWidth = 1}
1793
- __init56() {this.isHovered = false}
1802
+ __init54() {this.fillStyle = "#94a3b8"}
1803
+ __init55() {this.strokeStyle = null}
1804
+ __init56() {this.hoveredFillStyle = "#ffffff"}
1805
+ __init57() {this.lineWidth = 1}
1806
+ __init58() {this.isHovered = false}
1794
1807
  constructor(text, atlas, maxWidth, fontSize = 24) {
1795
- super();_class3.prototype.__init51.call(this);_class3.prototype.__init52.call(this);_class3.prototype.__init53.call(this);_class3.prototype.__init54.call(this);_class3.prototype.__init55.call(this);_class3.prototype.__init56.call(this);;
1808
+ super();_class3.prototype.__init53.call(this);_class3.prototype.__init54.call(this);_class3.prototype.__init55.call(this);_class3.prototype.__init56.call(this);_class3.prototype.__init57.call(this);_class3.prototype.__init58.call(this);;
1796
1809
  this.text = text;
1797
1810
  this.atlas = atlas;
1798
1811
  this.fontSize = fontSize;
1799
- this.layout = new (0, _chunkBWLNEJJWjs.LayoutEngine)(maxWidth, 1e4, defaultMeasurer());
1812
+ this.layout = new (0, _chunkXLZDOFSBjs.LayoutEngine)(maxWidth, 1e4, defaultMeasurer());
1800
1813
  this.prepared = this.layout.prepare(this.text, this.atlas, this.fontSize);
1801
1814
  this.applyLayout();
1802
1815
  this.interactive = true;
@@ -1835,6 +1848,26 @@ var TextEntity = (_class3 = class extends _chunkDWMQYHNCjs.Entity {
1835
1848
  this.applyLayout();
1836
1849
  return this;
1837
1850
  }
1851
+ /**
1852
+ * Set horizontal alignment (`'justify'` stretches wrapped lines flush to
1853
+ * the wrap width; the last line stays ragged) and reflow.
1854
+ */
1855
+ setTextAlign(align) {
1856
+ this.layout.textAlign = align;
1857
+ this.applyLayout();
1858
+ return this;
1859
+ }
1860
+ /**
1861
+ * Plug a hyphenator (word → parts). Break opportunities are baked in during
1862
+ * the cold pass, so this re-prepares the current text. Soft hyphens
1863
+ * (U+00AD) in the text work without one.
1864
+ */
1865
+ setHyphenator(fn) {
1866
+ this.layout.hyphenate = fn;
1867
+ this.prepared = this.layout.prepare(this.text, this.atlas, this.fontSize);
1868
+ this.applyLayout();
1869
+ return this;
1870
+ }
1838
1871
  /** Hot pass: place the cached {@link PreparedText} and refresh the a11y box. */
1839
1872
  applyLayout() {
1840
1873
  const result = this.layout.layoutPrepared(this.prepared);
@@ -1885,17 +1918,17 @@ var TextEntity = (_class3 = class extends _chunkDWMQYHNCjs.Entity {
1885
1918
  }, _class3);
1886
1919
 
1887
1920
  // src/components/GridTextEntity.ts
1888
- var GridTextEntity = (_class4 = class extends _chunkDWMQYHNCjs.Entity {
1921
+ var GridTextEntity = (_class4 = class extends _chunkU4UYRERWjs.Entity {
1889
1922
 
1890
- __init57() {this.fillStyle = "#ffffff"}
1891
- __init58() {this.grid = []}
1923
+ __init59() {this.fillStyle = "#ffffff"}
1924
+ __init60() {this.grid = []}
1892
1925
  // Array of rows
1893
- __init59() {this.cols = 0}
1894
- __init60() {this.rows = 0}
1926
+ __init61() {this.cols = 0}
1927
+ __init62() {this.rows = 0}
1895
1928
 
1896
1929
 
1897
1930
  constructor(_atlas, fontSize = 10) {
1898
- super();_class4.prototype.__init57.call(this);_class4.prototype.__init58.call(this);_class4.prototype.__init59.call(this);_class4.prototype.__init60.call(this);;
1931
+ super();_class4.prototype.__init59.call(this);_class4.prototype.__init60.call(this);_class4.prototype.__init61.call(this);_class4.prototype.__init62.call(this);;
1899
1932
  this.fontSize = fontSize;
1900
1933
  this.charWidth = fontSize * 1;
1901
1934
  this.charHeight = fontSize * 1.1;
@@ -1979,7 +2012,7 @@ function distSqToSegment(px, py, x1, y1, x2, y2) {
1979
2012
  const ey = py - cy;
1980
2013
  return ex * ex + ey * ey;
1981
2014
  }
1982
- var SplineEntity = (_class5 = class extends _chunkDWMQYHNCjs.Entity {
2015
+ var SplineEntity = (_class5 = class extends _chunkU4UYRERWjs.Entity {
1983
2016
 
1984
2017
 
1985
2018
 
@@ -1987,23 +2020,23 @@ var SplineEntity = (_class5 = class extends _chunkDWMQYHNCjs.Entity {
1987
2020
 
1988
2021
 
1989
2022
 
1990
- __init61() {this.offscreen = null}
1991
- __init62() {this.baked = false}
2023
+ __init63() {this.offscreen = null}
2024
+ __init64() {this.baked = false}
1992
2025
  /** Logical (CSS-pixel) size of the baked bitmap — the blit destination size. */
1993
- __init63() {this.bakedWidth = 0}
1994
- __init64() {this.bakedHeight = 0}
2026
+ __init65() {this.bakedWidth = 0}
2027
+ __init66() {this.bakedHeight = 0}
1995
2028
  /** Gradient strokes can't be baked to a solid-color bitmap; they render per-frame. */
1996
2029
 
1997
2030
  /** Lazily-flattened polylines (one Float32Array of [x,y,...] per segment) for hit-testing. */
1998
- __init65() {this.polylines = null}
2031
+ __init67() {this.polylines = null}
1999
2032
  /**
2000
2033
  * When `true`, the renderer draws a rounded-rect outline of the entity's
2001
2034
  * local bounds after painting the curves. Useful for drag feedback and
2002
2035
  * debugging hit areas. Defaults to `false`.
2003
2036
  */
2004
- __init66() {this.showBounds = false}
2037
+ __init68() {this.showBounds = false}
2005
2038
  constructor(doc, opts = {}) {
2006
- super();_class5.prototype.__init61.call(this);_class5.prototype.__init62.call(this);_class5.prototype.__init63.call(this);_class5.prototype.__init64.call(this);_class5.prototype.__init65.call(this);_class5.prototype.__init66.call(this);;
2039
+ super();_class5.prototype.__init63.call(this);_class5.prototype.__init64.call(this);_class5.prototype.__init65.call(this);_class5.prototype.__init66.call(this);_class5.prototype.__init67.call(this);_class5.prototype.__init68.call(this);;
2007
2040
  this.doc = doc;
2008
2041
  this.lineWidth = _nullishCoalesce(opts.lineWidth, () => ( 2));
2009
2042
  this.cache = _nullishCoalesce(opts.cache, () => ( true));
@@ -2256,9 +2289,9 @@ async function loadSpline(url) {
2256
2289
  // src/math/SpatialHashGrid.ts
2257
2290
  var SpatialHashGrid = (_class6 = class {
2258
2291
 
2259
- __init67() {this.grid = /* @__PURE__ */ new Map()}
2260
- __init68() {this.entityCells = /* @__PURE__ */ new Map()}
2261
- constructor(cellSize = 64) {;_class6.prototype.__init67.call(this);_class6.prototype.__init68.call(this);
2292
+ __init69() {this.grid = /* @__PURE__ */ new Map()}
2293
+ __init70() {this.entityCells = /* @__PURE__ */ new Map()}
2294
+ constructor(cellSize = 64) {;_class6.prototype.__init69.call(this);_class6.prototype.__init70.call(this);
2262
2295
  this.cellSize = cellSize;
2263
2296
  }
2264
2297
  hash(cx, cy) {
@@ -2348,20 +2381,20 @@ var SpatialHashGrid = (_class6 = class {
2348
2381
  }, _class6);
2349
2382
 
2350
2383
  // src/tree/DOMPortalEntity.ts
2351
- var DOMPortalEntity = (_class7 = class extends _chunkDWMQYHNCjs.Entity {
2384
+ var DOMPortalEntity = (_class7 = class extends _chunkU4UYRERWjs.Entity {
2352
2385
 
2353
- __init69() {this.isDOMPortal = true}
2354
- __init70() {this.domListeners = []}
2355
- __init71() {this.resizeObserver = null}
2356
- __init72() {this.cachedWidth = 100}
2357
- __init73() {this.cachedHeight = 100}
2358
- __init74() {this.lastWidth = ""}
2359
- __init75() {this.lastHeight = ""}
2360
- __init76() {this.lastTransform = ""}
2361
- __init77() {this.lastZIndex = ""}
2362
- __init78() {this.lastOpacity = ""}
2386
+ __init71() {this.isDOMPortal = true}
2387
+ __init72() {this.domListeners = []}
2388
+ __init73() {this.resizeObserver = null}
2389
+ __init74() {this.cachedWidth = 100}
2390
+ __init75() {this.cachedHeight = 100}
2391
+ __init76() {this.lastWidth = ""}
2392
+ __init77() {this.lastHeight = ""}
2393
+ __init78() {this.lastTransform = ""}
2394
+ __init79() {this.lastZIndex = ""}
2395
+ __init80() {this.lastOpacity = ""}
2363
2396
  constructor(domElement, width, height, id) {
2364
- super(id);_class7.prototype.__init69.call(this);_class7.prototype.__init70.call(this);_class7.prototype.__init71.call(this);_class7.prototype.__init72.call(this);_class7.prototype.__init73.call(this);_class7.prototype.__init74.call(this);_class7.prototype.__init75.call(this);_class7.prototype.__init76.call(this);_class7.prototype.__init77.call(this);_class7.prototype.__init78.call(this);;
2397
+ super(id);_class7.prototype.__init71.call(this);_class7.prototype.__init72.call(this);_class7.prototype.__init73.call(this);_class7.prototype.__init74.call(this);_class7.prototype.__init75.call(this);_class7.prototype.__init76.call(this);_class7.prototype.__init77.call(this);_class7.prototype.__init78.call(this);_class7.prototype.__init79.call(this);_class7.prototype.__init80.call(this);;
2365
2398
  this.domElement = domElement;
2366
2399
  this.width = _nullishCoalesce(width, () => ( 0));
2367
2400
  this.height = _nullishCoalesce(height, () => ( 0));
@@ -2383,7 +2416,7 @@ var DOMPortalEntity = (_class7 = class extends _chunkDWMQYHNCjs.Entity {
2383
2416
  const events = ["click", "pointerdown", "pointerup", "pointermove", "wheel"];
2384
2417
  for (const type of events) {
2385
2418
  const handler = (e) => {
2386
- this.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)(type, this, e));
2419
+ this.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)(type, this, e));
2387
2420
  };
2388
2421
  this.domElement.addEventListener(type, handler);
2389
2422
  this.domListeners.push({ type, handler, capture: false });
@@ -2394,7 +2427,7 @@ var DOMPortalEntity = (_class7 = class extends _chunkDWMQYHNCjs.Entity {
2394
2427
  ];
2395
2428
  for (const { native, vecto } of hoverEvents) {
2396
2429
  const handler = (e) => {
2397
- this.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)(vecto, this, e, false));
2430
+ this.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)(vecto, this, e, false));
2398
2431
  };
2399
2432
  this.domElement.addEventListener(native, handler);
2400
2433
  this.domListeners.push({ type: native, handler, capture: false });
@@ -2402,7 +2435,7 @@ var DOMPortalEntity = (_class7 = class extends _chunkDWMQYHNCjs.Entity {
2402
2435
  const focusEvents = ["focus", "blur"];
2403
2436
  for (const type of focusEvents) {
2404
2437
  const handler = (e) => {
2405
- this.dispatchEvent(new (0, _chunkDWMQYHNCjs.VectoJSEvent)(type, this, e, true));
2438
+ this.dispatchEvent(new (0, _chunkU4UYRERWjs.VectoJSEvent)(type, this, e, true));
2406
2439
  };
2407
2440
  this.domElement.addEventListener(type, handler, true);
2408
2441
  this.domListeners.push({ type, handler, capture: true });
@@ -2441,8 +2474,8 @@ var DOMPortalEntity = (_class7 = class extends _chunkDWMQYHNCjs.Entity {
2441
2474
  }, _class7);
2442
2475
 
2443
2476
  // src/index.ts
2444
- Scene.registerWebGLPointRendererCreator(_chunkGTQRCY6Wjs.createWebGLPointRenderer);
2445
- Scene.registerWebGPUParticleSystemManager(_chunkGTQRCY6Wjs.WebGPUParticleSystemManager);
2477
+ Scene.registerWebGLPointRendererCreator(_chunkBPMNCGU7js.createWebGLPointRenderer);
2478
+ Scene.registerWebGPUParticleSystemManager(_chunkBPMNCGU7js.WebGPUParticleSystemManager);
2446
2479
 
2447
2480
 
2448
2481
 
@@ -2487,4 +2520,4 @@ Scene.registerWebGPUParticleSystemManager(_chunkGTQRCY6Wjs.WebGPUParticleSystemM
2487
2520
 
2488
2521
 
2489
2522
 
2490
- exports.ArabicShaper = _chunkCTZQOM5Zjs.ArabicShaper; exports.BidiResolver = _chunkCTZQOM5Zjs.BidiResolver; exports.CanvasRenderer = _chunkGTQRCY6Wjs.CanvasRenderer; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Easing = _chunkDWMQYHNCjs.Easing; exports.Entity = _chunkDWMQYHNCjs.Entity; exports.GridTextEntity = GridTextEntity; exports.LayoutEngine = _chunkBWLNEJJWjs.LayoutEngine; exports.LayoutResultBuffer = _chunkBWLNEJJWjs.LayoutResultBuffer; exports.LayoutWorkerManager = _chunkCTZQOM5Zjs.LayoutWorkerManager; exports.MSDFFont = _chunkDWMQYHNCjs.MSDFFont; exports.MSDFTextEntity = _chunkDWMQYHNCjs.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.SVGEntity = _chunkDWMQYHNCjs.SVGEntity; exports.SVGRenderer = _chunkGTQRCY6Wjs.SVGRenderer; exports.Scene = Scene; exports.SpatialHashGrid = SpatialHashGrid; exports.SplineEntity = SplineEntity; exports.SpringDriver = _chunkDWMQYHNCjs.SpringDriver; exports.SpringPhysics = _chunkDWMQYHNCjs.SpringPhysics; exports.TextEntity = TextEntity; exports.TweenDriver = _chunkDWMQYHNCjs.TweenDriver; exports.VectoJSEvent = _chunkDWMQYHNCjs.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkGTQRCY6Wjs.WebGPUParticleSystemManager; exports.computeLineSegments = _chunkBWLNEJJWjs.computeLineSegments; exports.createCanvasMeasurer = _chunkBWLNEJJWjs.createCanvasMeasurer; exports.createWebGLPointRenderer = _chunkGTQRCY6Wjs.createWebGLPointRenderer; exports.isSafeUrl = _chunkGTQRCY6Wjs.isSafeUrl; exports.isTweenConfig = _chunkDWMQYHNCjs.isTweenConfig; exports.loadSpline = loadSpline; exports.parseColorToRGBA = _chunkGTQRCY6Wjs.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkGTQRCY6Wjs.sanitizeUrl;
2523
+ exports.ArabicShaper = _chunkCTZQOM5Zjs.ArabicShaper; exports.BidiResolver = _chunkCTZQOM5Zjs.BidiResolver; exports.CanvasRenderer = _chunkBPMNCGU7js.CanvasRenderer; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Easing = _chunkU4UYRERWjs.Easing; exports.Entity = _chunkU4UYRERWjs.Entity; exports.GridTextEntity = GridTextEntity; exports.LayoutEngine = _chunkXLZDOFSBjs.LayoutEngine; exports.LayoutResultBuffer = _chunkXLZDOFSBjs.LayoutResultBuffer; exports.LayoutWorkerManager = _chunkCTZQOM5Zjs.LayoutWorkerManager; exports.MSDFFont = _chunkU4UYRERWjs.MSDFFont; exports.MSDFTextEntity = _chunkU4UYRERWjs.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.SVGEntity = _chunkU4UYRERWjs.SVGEntity; exports.SVGRenderer = _chunkBPMNCGU7js.SVGRenderer; exports.Scene = Scene; exports.SpatialHashGrid = SpatialHashGrid; exports.SplineEntity = SplineEntity; exports.SpringDriver = _chunkU4UYRERWjs.SpringDriver; exports.SpringPhysics = _chunkU4UYRERWjs.SpringPhysics; exports.TextEntity = TextEntity; exports.TweenDriver = _chunkU4UYRERWjs.TweenDriver; exports.VectoJSEvent = _chunkU4UYRERWjs.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkBPMNCGU7js.WebGPUParticleSystemManager; exports.computeLineSegments = _chunkXLZDOFSBjs.computeLineSegments; exports.createCanvasMeasurer = _chunkXLZDOFSBjs.createCanvasMeasurer; exports.createWebGLPointRenderer = _chunkBPMNCGU7js.createWebGLPointRenderer; exports.isSafeUrl = _chunkBPMNCGU7js.isSafeUrl; exports.isTweenConfig = _chunkU4UYRERWjs.isTweenConfig; exports.loadSpline = loadSpline; exports.parseColorToRGBA = _chunkBPMNCGU7js.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkBPMNCGU7js.sanitizeUrl;