@vectojs/core 1.20.0 → 1.22.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.
package/dist/index.js CHANGED
@@ -8,13 +8,14 @@
8
8
 
9
9
 
10
10
 
11
- var _chunkL4SWVP2Hjs = require('./chunk-L4SWVP2H.js');
12
11
 
12
+ var _chunkLHONR3GOjs = require('./chunk-LHONR3GO.js');
13
13
 
14
14
 
15
15
 
16
16
 
17
- var _chunkYLH7F4ZVjs = require('./chunk-YLH7F4ZV.js');
17
+
18
+ var _chunkAGP4VLF4js = require('./chunk-AGP4VLF4.js');
18
19
 
19
20
  // src/tree/Scene.ts
20
21
  var _animation = require('@vectojs/animation'); _createStarExport(_animation);
@@ -29,7 +30,7 @@ var PARTICLE_OFFSET_ORIGIN_X = 4;
29
30
  var PARTICLE_OFFSET_ORIGIN_Y = 5;
30
31
  var PARTICLE_OFFSET_SIZE = 6;
31
32
  var PARTICLE_OFFSET_LIFE = 7;
32
- var ComputeParticleEntity = (_class = class extends _chunkYLH7F4ZVjs.Entity {
33
+ var ComputeParticleEntity = (_class = class extends _chunkAGP4VLF4js.Entity {
33
34
 
34
35
 
35
36
 
@@ -1688,66 +1689,89 @@ var Scene = (_class7 = class _Scene {
1688
1689
  __init53() {this.contentGridCalibrationFrames = /* @__PURE__ */ new Map()}
1689
1690
  /** Detached, untransformed font probes used by the cold calibration pass. */
1690
1691
  __init54() {this.contentGridCalibrationProbes = /* @__PURE__ */ new Map()}
1692
+ /**
1693
+ * Monotonic stamp identifying the conditions grid cells were calibrated under.
1694
+ *
1695
+ * Calibration measures the difference between the advance the canvas grid assigns
1696
+ * a cluster and the width the browser lays it out at, then writes a per-cell
1697
+ * `scaleX`. That result stays valid until the font or the page scale changes, and
1698
+ * it lives on the cell element — so a cell carrying this stamp needs no further
1699
+ * work.
1700
+ *
1701
+ * The scan that feeds calibration was O(cells) on every revision bump: for a
1702
+ * streaming code block it re-derived a measurement key for every cell in the
1703
+ * block each frame in order to produce only ~20 distinct keys, costing about
1704
+ * 2.5 ms/frame after the `style.font` fix and still over half of `a11ySync`. Since
1705
+ * carrier reuse (#244) leaves untouched lines — and therefore their calibrated
1706
+ * transforms — in place, cells stamped with the current generation can simply be
1707
+ * skipped, making the scan O(new cells) instead.
1708
+ *
1709
+ * A plain incrementing integer rather than the descriptive calibration key,
1710
+ * because it goes into an attribute selector and must not need escaping.
1711
+ */
1712
+ __init55() {this.contentGridCalibrationGeneration = 0}
1713
+ /** The `(fontEpoch, pageScale)` pair the current generation corresponds to. */
1714
+ __init56() {this.contentGridCalibrationStamp = ""}
1691
1715
  /** Invalidates grid font calibration after browser font availability changes. */
1692
- __init55() {this.contentFontEpoch = 0}
1716
+ __init57() {this.contentFontEpoch = 0}
1693
1717
  /** Cached Canvas-to-client scale for the current font/viewport epoch. */
1694
- __init56() {this.contentMetricScaleEpoch = -1}
1695
- __init57() {this.contentMetricScaleX = 1}
1696
- __init58() {this.contentProjectionEnabled = true}
1718
+ __init58() {this.contentMetricScaleEpoch = -1}
1719
+ __init59() {this.contentMetricScaleX = 1}
1720
+ __init60() {this.contentProjectionEnabled = true}
1697
1721
  // Virtualization margin (px) for content projection; `undefined` → one
1698
1722
  // viewport height, resolved at sync time. `Infinity` = materialize everything.
1699
- __init59() {this.contentProjectionMargin = void 0}
1723
+ __init61() {this.contentProjectionMargin = void 0}
1700
1724
  /**
1701
1725
  * True while a text-selection drag that started on a projection's blank
1702
1726
  * region (no text node under the press) is being driven manually — the
1703
1727
  * browser has no native anchor for it, so mousemove extends the Selection
1704
1728
  * from the position we resolved ourselves.
1705
1729
  */
1706
- __init60() {this.blankRegionSelectionDrag = false}
1707
- __init61() {this.contentSelectionAnchor = null}
1708
- __init62() {this.contentSelectionEndListener = null}
1730
+ __init62() {this.blankRegionSelectionDrag = false}
1731
+ __init63() {this.contentSelectionAnchor = null}
1732
+ __init64() {this.contentSelectionEndListener = null}
1709
1733
  // Animation/interactive flags collected during the render walk (tree-walk
1710
1734
  // fusion): the loop reads last frame's answers instead of re-walking the
1711
1735
  // tree up to 4× per tick. Start true so the first tick stays conservative.
1712
- __init63() {this.frameHadAnimation = true}
1713
- __init64() {this.frameHadInteractive = true}
1736
+ __init65() {this.frameHadAnimation = true}
1737
+ __init66() {this.frameHadInteractive = true}
1714
1738
 
1715
1739
  /** Active `(resolution: Ndppx)` media query watching for a runtime DPR change
1716
1740
  * (window moved between monitors, browser zoom) so the canvas backing store
1717
1741
  * can be re-scaled — otherwise it stays rasterized at the old DPR and blurs.
1718
1742
  * A resolution media query only fires when leaving its exact value, so the
1719
1743
  * handler re-arms a fresh query for the new DPR each time. */
1720
- __init65() {this.dprMediaQuery = null}
1744
+ __init67() {this.dprMediaQuery = null}
1721
1745
  /** For embedded (`disableWindowResize`) scenes: observes the canvas element so
1722
1746
  * a CSS/layout-driven size change re-runs `resize()`. A window `resize`
1723
1747
  * listener never fires for these (the window isn't what changed), so without
1724
1748
  * this an embedded canvas stayed at its initial size forever. */
1725
- __init66() {this.canvasResizeObserver = null}
1726
- __init67() {this.dprChangeHandler = null}
1727
- __init68() {this.focusedA11yElement = null}
1749
+ __init68() {this.canvasResizeObserver = null}
1750
+ __init69() {this.dprChangeHandler = null}
1751
+ __init70() {this.focusedA11yElement = null}
1728
1752
  /** Last geometry `syncOverlayGeometry` wrote, so an unchanged frame can skip the
1729
1753
  * style writes entirely. Reset to `null` to force the next sync (a new overlay
1730
1754
  * layer was created and has never been positioned). */
1731
- __init69() {this._overlayGeometry = null}
1755
+ __init71() {this._overlayGeometry = null}
1732
1756
  /** Shadow elements the pointer is currently inside. Lets a removal that happens
1733
1757
  * mid-hover synthesize the `pointerleave` the browser never sends for a
1734
1758
  * detached element, so the entity doesn't keep its hover state. */
1735
- __init70() {this.hoveredA11yElements = /* @__PURE__ */ new WeakSet()}
1759
+ __init72() {this.hoveredA11yElements = /* @__PURE__ */ new WeakSet()}
1736
1760
  /** Persistent tabindex=-1 element in a11yRoot. When the focused a11y mirror is
1737
1761
  * pruned (virtualization/streaming/removal) while it holds focus, we move
1738
1762
  * focus here instead of letting the browser drop it to <body> — keeping the
1739
1763
  * screen-reader virtual cursor inside the scene's a11y region. */
1740
- __init71() {this.focusSentinel = null}
1741
- __init72() {this.caretBlinkTimer = null}
1742
- __init73() {this.a11yNeedsReorder = true}
1743
- __init74() {this.portalRoot = null}
1744
- __init75() {this.fullViewportElements = []}
1745
- __init76() {this.normalElements = []}
1746
- __init77() {this.activeIds = /* @__PURE__ */ new Set()}
1747
- __init78() {this.activePortalsThisFrame = /* @__PURE__ */ new Set()}
1748
- __init79() {this.activePortalsPrevFrame = /* @__PURE__ */ new Set()}
1749
- __init80() {this.portalEntities = /* @__PURE__ */ new Map()}
1750
- __init81() {this.renderOrderCounter = 0}
1764
+ __init73() {this.focusSentinel = null}
1765
+ __init74() {this.caretBlinkTimer = null}
1766
+ __init75() {this.a11yNeedsReorder = true}
1767
+ __init76() {this.portalRoot = null}
1768
+ __init77() {this.fullViewportElements = []}
1769
+ __init78() {this.normalElements = []}
1770
+ __init79() {this.activeIds = /* @__PURE__ */ new Set()}
1771
+ __init80() {this.activePortalsThisFrame = /* @__PURE__ */ new Set()}
1772
+ __init81() {this.activePortalsPrevFrame = /* @__PURE__ */ new Set()}
1773
+ __init82() {this.portalEntities = /* @__PURE__ */ new Map()}
1774
+ __init83() {this.renderOrderCounter = 0}
1751
1775
  /**
1752
1776
  * Monotonic render-frame counter, bumped once per authoritative `render()`
1753
1777
  * pass. Entities stamp their per-frame world-matrix cache with this value and
@@ -1756,7 +1780,7 @@ var Scene = (_class7 = class _Scene {
1756
1780
  * back to the ancestor walk. Public for the same reason `Entity._getTrig`/
1757
1781
  * `_setWorldCache` are: it is a cross-class render-internal contract.
1758
1782
  */
1759
- __init82() {this.currentFrame = 0}
1783
+ __init84() {this.currentFrame = 0}
1760
1784
  // ── WASM transform backend (invisible accelerator) ──────────────────────────
1761
1785
  // When `_transformBackend === 'wasm'`, the main render walk sources each
1762
1786
  // entity's world matrix from an SoA store composed by `_wasm` (see
@@ -1764,24 +1788,24 @@ var Scene = (_class7 = class _Scene {
1764
1788
  // fallback and the default: a null backend, a non-main renderer, or any entity
1765
1789
  // absent from the store all fall back to the JS composition, so WASM can only
1766
1790
  // ever change *how fast* a world matrix is produced, never *what* it is.
1767
- __init83() {this._wasm = null}
1768
- __init84() {this._transformBackend = "js"}
1791
+ __init85() {this._wasm = null}
1792
+ __init86() {this._transformBackend = "js"}
1769
1793
  // Resident store state (Stage 3). The store layout — slot assignment + sibling
1770
1794
  // runs — depends only on tree TOPOLOGY, so it is rebuilt only when the
1771
1795
  // structure changes (add/remove/reparent bump `_structureVersion`). Between
1772
1796
  // rebuilds the per-frame cost is: gather each entity's transform into the
1773
1797
  // resident wasm input view + run the kernel — no reallocation, no readback.
1774
- __init85() {this._treeStore = null}
1775
- __init86() {this._slotEntity = []}
1798
+ __init87() {this._treeStore = null}
1799
+ __init88() {this._slotEntity = []}
1776
1800
  // store slot -> entity (also validates slots)
1777
- __init87() {this._wasmInputs = null}
1778
- __init88() {this._wasmWorld = null}
1779
- __init89() {this._structureVersion = 0}
1780
- __init90() {this._storeStructureVersion = -1}
1801
+ __init89() {this._wasmInputs = null}
1802
+ __init90() {this._wasmWorld = null}
1803
+ __init91() {this._structureVersion = 0}
1804
+ __init92() {this._storeStructureVersion = -1}
1781
1805
  // Cached list of ComputeParticleEntity instances in the tree, keyed by the
1782
1806
  // structure version it was gathered at. Rebuilt only on a topology change.
1783
- __init91() {this._computeEntities = []}
1784
- __init92() {this._computeEntitiesVersion = -1}
1807
+ __init93() {this._computeEntities = []}
1808
+ __init94() {this._computeEntitiesVersion = -1}
1785
1809
  /** Invalidate the resident WASM store layout; the next wasm-mode frame rebuilds
1786
1810
  * it. Called by `Entity.add`/`remove` (topology changes only). */
1787
1811
  markStructureChanged() {
@@ -1863,7 +1887,7 @@ var Scene = (_class7 = class _Scene {
1863
1887
  * cached globally; the instance is per-Scene, which is the isolation that
1864
1888
  * actually matters.
1865
1889
  */
1866
- __init93() {this._wasmRuntime = null}
1890
+ __init95() {this._wasmRuntime = null}
1867
1891
  /**
1868
1892
  * Load (or reuse) this Scene's shared WASM runtime.
1869
1893
  *
@@ -1891,30 +1915,30 @@ var Scene = (_class7 = class _Scene {
1891
1915
  get wasmRuntime() {
1892
1916
  return this._wasmRuntime;
1893
1917
  }
1894
- __init94() {this._hitWasm = null}
1918
+ __init96() {this._hitWasm = null}
1895
1919
  // Cache key: which frame + structure version the grid was last (successfully,
1896
1920
  // non-overflowing) built for. findEntityAt is called ad-hoc (pointer
1897
1921
  // hover/click), not every frame, so the grid is refreshed lazily on demand
1898
1922
  // rather than proactively every render() — unlike the transform store, which
1899
1923
  // every frame's draw depends on.
1900
- __init95() {this._hitGridFrame = -1}
1901
- __init96() {this._hitGridOk = false}
1902
- __init97() {this._hitSlotEntity = []}
1903
- __init98() {this._hitBoundless = []}
1924
+ __init97() {this._hitGridFrame = -1}
1925
+ __init98() {this._hitGridOk = false}
1926
+ __init99() {this._hitSlotEntity = []}
1927
+ __init100() {this._hitBoundless = []}
1904
1928
  /** Reused buffer for the fused gather, so a pointer query allocates nothing. */
1905
- __init99() {this._hitGatherBuffer = null}
1929
+ __init101() {this._hitGatherBuffer = null}
1906
1930
  /**
1907
1931
  * Whether the last grid build sourced its AABBs from the WASM transform store
1908
1932
  * rather than recomputing them in JS. Diagnostic only — both paths must
1909
1933
  * produce the same entity for a given point.
1910
1934
  */
1911
- __init100() {this._hitFusedGather = false}
1935
+ __init102() {this._hitFusedGather = false}
1912
1936
  /**
1913
1937
  * Whether `compute_aabbs` has run against the current frame's world matrices.
1914
1938
  * The AABB pass is only meaningful after a `compose_*`, so the fused gather
1915
1939
  * must not read the views before then.
1916
1940
  */
1917
- __init101() {this._wasmAabbsFresh = false}
1941
+ __init103() {this._wasmAabbsFresh = false}
1918
1942
  /** Did the last hit-grid build use the fused (WASM-store) gather? */
1919
1943
  get hitGatherPath() {
1920
1944
  return this._hitFusedGather ? "fused" : "js";
@@ -2028,25 +2052,25 @@ var Scene = (_class7 = class _Scene {
2028
2052
  // EasingFn (which cannot cross into WASM) all fall through to it — WASM can
2029
2053
  // only ever change *how* a driver is advanced, never *what* value it lands
2030
2054
  // on.
2031
- __init102() {this._animWasm = null}
2055
+ __init104() {this._animWasm = null}
2032
2056
  // Entities with at least one active driver, added by Entity._spawnDriver.
2033
2057
  // Self-pruning: _tickBatchedDrivers drops an entry the first time it visits
2034
2058
  // an entity whose drivers have since all completed or been removed. This is
2035
2059
  // what lets the batch pass find its candidates in O(active drivers), not
2036
2060
  // O(tree size) — the exact mistake G3's first integrated benchmark made.
2037
- __init103() {this._activeDriverEntities = /* @__PURE__ */ new Set()}
2061
+ __init105() {this._activeDriverEntities = /* @__PURE__ */ new Set()}
2038
2062
  // Reused across frames instead of allocating a fresh array + N {entity,prop,
2039
2063
  // driver} objects every call — the integrated benchmark
2040
2064
  // (benchmarks/anim-wasm-scene) found that allocation churn was the
2041
2065
  // dominant integrated cost, not the wasm kernel itself. Parallel arrays,
2042
2066
  // truncated to the live count after each use so a stale tail slot never
2043
2067
  // pins a no-longer-active entity/driver in memory.
2044
- __init104() {this._springEntities = []}
2045
- __init105() {this._springProps = []}
2046
- __init106() {this._springDrivers = []}
2047
- __init107() {this._tweenEntities = []}
2048
- __init108() {this._tweenProps = []}
2049
- __init109() {this._tweenDrivers = []}
2068
+ __init106() {this._springEntities = []}
2069
+ __init107() {this._springProps = []}
2070
+ __init108() {this._springDrivers = []}
2071
+ __init109() {this._tweenEntities = []}
2072
+ __init110() {this._tweenProps = []}
2073
+ __init111() {this._tweenDrivers = []}
2050
2074
  /**
2051
2075
  * Minimum number of batchable (spring, or named-easing tween) active drivers
2052
2076
  * before a frame engages the WASM batch path at all; below it, every driver
@@ -2118,7 +2142,7 @@ var Scene = (_class7 = class _Scene {
2118
2142
  * Setting {@link animDriverGateCount} overwrites all three, so existing code
2119
2143
  * that tuned the single knob keeps working unchanged.
2120
2144
  */
2121
- __init110() {this._animBatchedLastFrame = false}
2145
+ __init112() {this._animBatchedLastFrame = false}
2122
2146
  /**
2123
2147
  * Whether the WASM batch path actually ran on the most recent frame.
2124
2148
  *
@@ -2130,7 +2154,7 @@ var Scene = (_class7 = class _Scene {
2130
2154
  get animBatchedLastFrame() {
2131
2155
  return this._animBatchedLastFrame;
2132
2156
  }
2133
- __init111() {this.animGate = {
2157
+ __init113() {this.animGate = {
2134
2158
  spring: 128,
2135
2159
  tween: 256,
2136
2160
  mixed: 128
@@ -2168,7 +2192,7 @@ var Scene = (_class7 = class _Scene {
2168
2192
  // (benchmarks/particle-wasm). f32 (matches the WGSL shader), bit-identical to
2169
2193
  // a JS f32 reference oracle; updateCPU (f64) stays the permanent fallback when
2170
2194
  // no backend is installed or a scene runs on WebGPU.
2171
- __init112() {this._particleWasm = null}
2195
+ __init114() {this._particleWasm = null}
2172
2196
  /** Which backend runs the CPU particle simulation. Reflects only whether a
2173
2197
  * backend is installed (the WebGPU compute path, when active, is used first
2174
2198
  * regardless). */
@@ -2418,46 +2442,67 @@ var Scene = (_class7 = class _Scene {
2418
2442
  * sync, so retaining the order prevents a newly opened overlay from spending
2419
2443
  * its first frame below previously projected controls.
2420
2444
  */
2421
- __init113() {this.a11yRenderOrders = /* @__PURE__ */ new Map()}
2445
+ __init115() {this.a11yRenderOrders = /* @__PURE__ */ new Map()}
2422
2446
  // Optional WebGL point-cloud layer (see SceneOptions.pointBackend).
2423
- __init114() {this.pointRenderer = null}
2424
- __init115() {this.glCanvas = null}
2425
- __init116() {this.glContextLostHandler = null}
2426
- __init117() {this.glContextRestoredHandler = null}
2447
+ __init116() {this.pointRenderer = null}
2448
+ __init117() {this.glCanvas = null}
2449
+ __init118() {this.glContextLostHandler = null}
2450
+ __init119() {this.glContextRestoredHandler = null}
2427
2451
 
2428
2452
 
2429
2453
 
2430
- __init118() {this.disableWindowResize = false}
2454
+ __init120() {this.disableWindowResize = false}
2431
2455
  /** See {@link SceneOptions.maxDPR}. `undefined` = uncapped (real DPR). */
2432
2456
 
2433
2457
  // WebGPU properties
2434
- __init119() {this.destroyed = false}
2435
- __init120() {this.device = null}
2436
- __init121() {this.deviceLost = false}
2437
- __init122() {this.particleBackend = "auto"}
2438
- __init123() {this._webgpuDisabled = false}
2458
+ __init121() {this.destroyed = false}
2459
+ __init122() {this.device = null}
2460
+ __init123() {this.deviceLost = false}
2461
+ __init124() {this.particleBackend = "auto"}
2462
+ __init125() {this._webgpuDisabled = false}
2439
2463
  get webgpuDisabled() {
2440
2464
  return this._webgpuDisabled || this.particleBackend === "cpu";
2441
2465
  }
2466
+ /**
2467
+ * Draw accounting for the WebGL point layer, or null when that layer is not in
2468
+ * use.
2469
+ *
2470
+ * Null and all-zero mean different things: null is "this backend is not
2471
+ * running", zero is "it ran and drew nothing". A readout that conflates them
2472
+ * sends someone looking for a performance problem in a backend that was never
2473
+ * active.
2474
+ */
2475
+ get webglDrawStats() {
2476
+ return _nullishCoalesce(_optionalChain([this, 'access', _27 => _27.pointRenderer, 'optionalAccess', _28 => _28.stats, 'optionalCall', _29 => _29()]), () => ( null));
2477
+ }
2478
+ /**
2479
+ * Whether a WebGPU device is currently live for particle compute.
2480
+ *
2481
+ * The WebGPU path only activates when a `ComputeParticleEntity` is present, so
2482
+ * most scenes never touch it.
2483
+ */
2484
+ get webgpuActive() {
2485
+ return this.device !== null && !this.deviceLost;
2486
+ }
2442
2487
  set webgpuDisabled(value) {
2443
2488
  this._webgpuDisabled = value;
2444
2489
  }
2445
- __init124() {this.recoveryTimerId = null}
2446
- __init125() {this.manager = null}
2447
- __init126() {this.initializingWebGPU = false}
2448
- __init127() {this.gpuCanvas = null}
2449
- __init128() {this.gpuContext = null}
2490
+ __init126() {this.recoveryTimerId = null}
2491
+ __init127() {this.manager = null}
2492
+ __init128() {this.initializingWebGPU = false}
2493
+ __init129() {this.gpuCanvas = null}
2494
+ __init130() {this.gpuContext = null}
2450
2495
  /** True while the GPU canvas holds a presented particle frame (needs clearing when they leave). */
2451
- __init129() {this.gpuHasContent = false}
2452
- __init130() {this.mouseX = -9999}
2453
- __init131() {this.mouseY = -9999}
2454
- __init132() {this.pointerMoveListener = null}
2455
- __init133() {this.pointerLeaveListener = null}
2496
+ __init131() {this.gpuHasContent = false}
2497
+ __init132() {this.mouseX = -9999}
2498
+ __init133() {this.mouseY = -9999}
2499
+ __init134() {this.pointerMoveListener = null}
2500
+ __init135() {this.pointerLeaveListener = null}
2456
2501
  /** Element the pointer listeners are bound to (parent container if present,
2457
2502
  * else the canvas). Stored so `destroy()` detaches from the same element. */
2458
- __init134() {this.pointerEventTarget = null}
2459
- __init135() {this.hasWarnedZeroSize = false}
2460
- __init136() {this.fontLoadHandler = null}
2503
+ __init136() {this.pointerEventTarget = null}
2504
+ __init137() {this.hasWarnedZeroSize = false}
2505
+ __init138() {this.fontLoadHandler = null}
2461
2506
  // ── Dev-mode warning infrastructure ──────────────────────────────
2462
2507
  //
2463
2508
  // Enable with `Scene.devMode = true` or by setting `globalThis.__DEV__`.
@@ -2470,12 +2515,12 @@ var Scene = (_class7 = class _Scene {
2470
2515
  static _devModeDetected() {
2471
2516
  if (_Scene.devMode) return true;
2472
2517
  const gp = typeof globalThis !== "undefined" ? globalThis : void 0;
2473
- if (_optionalChain([gp, 'optionalAccess', _27 => _27.__DEV__])) return true;
2474
- if (_optionalChain([gp, 'optionalAccess', _28 => _28.process, 'optionalAccess', _29 => _29.env, 'optionalAccess', _30 => _30.NODE_ENV]) === "development") return true;
2518
+ if (_optionalChain([gp, 'optionalAccess', _30 => _30.__DEV__])) return true;
2519
+ if (_optionalChain([gp, 'optionalAccess', _31 => _31.process, 'optionalAccess', _32 => _32.env, 'optionalAccess', _33 => _33.NODE_ENV]) === "development") return true;
2475
2520
  return false;
2476
2521
  }
2477
2522
 
2478
- __init137() {this._devFrameCount = 0}
2523
+ __init139() {this._devFrameCount = 0}
2479
2524
  _devWarn(message) {
2480
2525
  if (!this._devActive) return;
2481
2526
  console.warn(`[vectojs/dev] ${message}`);
@@ -2502,9 +2547,9 @@ var Scene = (_class7 = class _Scene {
2502
2547
  let checked = 0;
2503
2548
  const walkProjections = (node) => {
2504
2549
  if (checked > 10) return;
2505
- const proj = _optionalChain([node, 'access', _31 => _31.getContentProjection, 'optionalCall', _32 => _32()]);
2506
- if (_optionalChain([proj, 'optionalAccess', _33 => _33.text]) && proj.selectable !== false) {
2507
- const el = _optionalChain([this, 'access', _34 => _34.contentElements, 'optionalAccess', _35 => _35.get, 'call', _36 => _36(node.id)]);
2550
+ const proj = _optionalChain([node, 'access', _34 => _34.getContentProjection, 'optionalCall', _35 => _35()]);
2551
+ if (_optionalChain([proj, 'optionalAccess', _36 => _36.text]) && proj.selectable !== false) {
2552
+ const el = _optionalChain([this, 'access', _37 => _37.contentElements, 'optionalAccess', _38 => _38.get, 'call', _39 => _39(node.id)]);
2508
2553
  if (el) {
2509
2554
  const projectedText = el.textContent || "";
2510
2555
  if (projectedText !== "" && projectedText !== proj.text) {
@@ -2519,14 +2564,14 @@ var Scene = (_class7 = class _Scene {
2519
2564
  };
2520
2565
  walkProjections(this.root);
2521
2566
  }
2522
- constructor(canvas, options = {}) {;_class7.prototype.__init25.call(this);_class7.prototype.__init26.call(this);_class7.prototype.__init27.call(this);_class7.prototype.__init28.call(this);_class7.prototype.__init29.call(this);_class7.prototype.__init30.call(this);_class7.prototype.__init31.call(this);_class7.prototype.__init32.call(this);_class7.prototype.__init33.call(this);_class7.prototype.__init34.call(this);_class7.prototype.__init35.call(this);_class7.prototype.__init36.call(this);_class7.prototype.__init37.call(this);_class7.prototype.__init38.call(this);_class7.prototype.__init39.call(this);_class7.prototype.__init40.call(this);_class7.prototype.__init41.call(this);_class7.prototype.__init42.call(this);_class7.prototype.__init43.call(this);_class7.prototype.__init44.call(this);_class7.prototype.__init45.call(this);_class7.prototype.__init46.call(this);_class7.prototype.__init47.call(this);_class7.prototype.__init48.call(this);_class7.prototype.__init49.call(this);_class7.prototype.__init50.call(this);_class7.prototype.__init51.call(this);_class7.prototype.__init52.call(this);_class7.prototype.__init53.call(this);_class7.prototype.__init54.call(this);_class7.prototype.__init55.call(this);_class7.prototype.__init56.call(this);_class7.prototype.__init57.call(this);_class7.prototype.__init58.call(this);_class7.prototype.__init59.call(this);_class7.prototype.__init60.call(this);_class7.prototype.__init61.call(this);_class7.prototype.__init62.call(this);_class7.prototype.__init63.call(this);_class7.prototype.__init64.call(this);_class7.prototype.__init65.call(this);_class7.prototype.__init66.call(this);_class7.prototype.__init67.call(this);_class7.prototype.__init68.call(this);_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);_class7.prototype.__init79.call(this);_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);_class7.prototype.__init90.call(this);_class7.prototype.__init91.call(this);_class7.prototype.__init92.call(this);_class7.prototype.__init93.call(this);_class7.prototype.__init94.call(this);_class7.prototype.__init95.call(this);_class7.prototype.__init96.call(this);_class7.prototype.__init97.call(this);_class7.prototype.__init98.call(this);_class7.prototype.__init99.call(this);_class7.prototype.__init100.call(this);_class7.prototype.__init101.call(this);_class7.prototype.__init102.call(this);_class7.prototype.__init103.call(this);_class7.prototype.__init104.call(this);_class7.prototype.__init105.call(this);_class7.prototype.__init106.call(this);_class7.prototype.__init107.call(this);_class7.prototype.__init108.call(this);_class7.prototype.__init109.call(this);_class7.prototype.__init110.call(this);_class7.prototype.__init111.call(this);_class7.prototype.__init112.call(this);_class7.prototype.__init113.call(this);_class7.prototype.__init114.call(this);_class7.prototype.__init115.call(this);_class7.prototype.__init116.call(this);_class7.prototype.__init117.call(this);_class7.prototype.__init118.call(this);_class7.prototype.__init119.call(this);_class7.prototype.__init120.call(this);_class7.prototype.__init121.call(this);_class7.prototype.__init122.call(this);_class7.prototype.__init123.call(this);_class7.prototype.__init124.call(this);_class7.prototype.__init125.call(this);_class7.prototype.__init126.call(this);_class7.prototype.__init127.call(this);_class7.prototype.__init128.call(this);_class7.prototype.__init129.call(this);_class7.prototype.__init130.call(this);_class7.prototype.__init131.call(this);_class7.prototype.__init132.call(this);_class7.prototype.__init133.call(this);_class7.prototype.__init134.call(this);_class7.prototype.__init135.call(this);_class7.prototype.__init136.call(this);_class7.prototype.__init137.call(this);
2567
+ constructor(canvas, options = {}) {;_class7.prototype.__init25.call(this);_class7.prototype.__init26.call(this);_class7.prototype.__init27.call(this);_class7.prototype.__init28.call(this);_class7.prototype.__init29.call(this);_class7.prototype.__init30.call(this);_class7.prototype.__init31.call(this);_class7.prototype.__init32.call(this);_class7.prototype.__init33.call(this);_class7.prototype.__init34.call(this);_class7.prototype.__init35.call(this);_class7.prototype.__init36.call(this);_class7.prototype.__init37.call(this);_class7.prototype.__init38.call(this);_class7.prototype.__init39.call(this);_class7.prototype.__init40.call(this);_class7.prototype.__init41.call(this);_class7.prototype.__init42.call(this);_class7.prototype.__init43.call(this);_class7.prototype.__init44.call(this);_class7.prototype.__init45.call(this);_class7.prototype.__init46.call(this);_class7.prototype.__init47.call(this);_class7.prototype.__init48.call(this);_class7.prototype.__init49.call(this);_class7.prototype.__init50.call(this);_class7.prototype.__init51.call(this);_class7.prototype.__init52.call(this);_class7.prototype.__init53.call(this);_class7.prototype.__init54.call(this);_class7.prototype.__init55.call(this);_class7.prototype.__init56.call(this);_class7.prototype.__init57.call(this);_class7.prototype.__init58.call(this);_class7.prototype.__init59.call(this);_class7.prototype.__init60.call(this);_class7.prototype.__init61.call(this);_class7.prototype.__init62.call(this);_class7.prototype.__init63.call(this);_class7.prototype.__init64.call(this);_class7.prototype.__init65.call(this);_class7.prototype.__init66.call(this);_class7.prototype.__init67.call(this);_class7.prototype.__init68.call(this);_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);_class7.prototype.__init79.call(this);_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);_class7.prototype.__init90.call(this);_class7.prototype.__init91.call(this);_class7.prototype.__init92.call(this);_class7.prototype.__init93.call(this);_class7.prototype.__init94.call(this);_class7.prototype.__init95.call(this);_class7.prototype.__init96.call(this);_class7.prototype.__init97.call(this);_class7.prototype.__init98.call(this);_class7.prototype.__init99.call(this);_class7.prototype.__init100.call(this);_class7.prototype.__init101.call(this);_class7.prototype.__init102.call(this);_class7.prototype.__init103.call(this);_class7.prototype.__init104.call(this);_class7.prototype.__init105.call(this);_class7.prototype.__init106.call(this);_class7.prototype.__init107.call(this);_class7.prototype.__init108.call(this);_class7.prototype.__init109.call(this);_class7.prototype.__init110.call(this);_class7.prototype.__init111.call(this);_class7.prototype.__init112.call(this);_class7.prototype.__init113.call(this);_class7.prototype.__init114.call(this);_class7.prototype.__init115.call(this);_class7.prototype.__init116.call(this);_class7.prototype.__init117.call(this);_class7.prototype.__init118.call(this);_class7.prototype.__init119.call(this);_class7.prototype.__init120.call(this);_class7.prototype.__init121.call(this);_class7.prototype.__init122.call(this);_class7.prototype.__init123.call(this);_class7.prototype.__init124.call(this);_class7.prototype.__init125.call(this);_class7.prototype.__init126.call(this);_class7.prototype.__init127.call(this);_class7.prototype.__init128.call(this);_class7.prototype.__init129.call(this);_class7.prototype.__init130.call(this);_class7.prototype.__init131.call(this);_class7.prototype.__init132.call(this);_class7.prototype.__init133.call(this);_class7.prototype.__init134.call(this);_class7.prototype.__init135.call(this);_class7.prototype.__init136.call(this);_class7.prototype.__init137.call(this);_class7.prototype.__init138.call(this);_class7.prototype.__init139.call(this);
2523
2568
  this.canvas = canvas;
2524
2569
  this.debugA11y = _nullishCoalesce(options.debugA11y, () => ( false));
2525
2570
  this.disableWindowResize = _nullishCoalesce(options.disableWindowResize, () => ( false));
2526
2571
  this.maxDPR = options.maxDPR;
2527
2572
  if (this.disableWindowResize) {
2528
- const styleWidth = parseInlinePx(_optionalChain([canvas, 'access', _37 => _37.style, 'optionalAccess', _38 => _38.width]));
2529
- const styleHeight = parseInlinePx(_optionalChain([canvas, 'access', _39 => _39.style, 'optionalAccess', _40 => _40.height]));
2573
+ const styleWidth = parseInlinePx(_optionalChain([canvas, 'access', _40 => _40.style, 'optionalAccess', _41 => _41.width]));
2574
+ const styleHeight = parseInlinePx(_optionalChain([canvas, 'access', _42 => _42.style, 'optionalAccess', _43 => _43.height]));
2530
2575
  this.width = _nullishCoalesce(styleWidth, () => ( (canvas.width || canvas.clientWidth || 0)));
2531
2576
  this.height = _nullishCoalesce(styleHeight, () => ( (canvas.height || canvas.clientHeight || 0)));
2532
2577
  } else {
@@ -2534,7 +2579,7 @@ var Scene = (_class7 = class _Scene {
2534
2579
  this.height = typeof window !== "undefined" ? window.innerHeight : canvas.clientHeight || canvas.height || 600;
2535
2580
  }
2536
2581
  const globalProcess = typeof globalThis !== "undefined" ? globalThis.process : void 0;
2537
- const isTest = globalProcess && (_optionalChain([globalProcess, 'access', _41 => _41.env, 'optionalAccess', _42 => _42.NODE_ENV]) === "test" || _optionalChain([globalProcess, 'access', _43 => _43.env, 'optionalAccess', _44 => _44.VITEST]) === "true");
2582
+ const isTest = globalProcess && (_optionalChain([globalProcess, 'access', _44 => _44.env, 'optionalAccess', _45 => _45.NODE_ENV]) === "test" || _optionalChain([globalProcess, 'access', _46 => _46.env, 'optionalAccess', _47 => _47.VITEST]) === "true");
2538
2583
  this.maxFPS = _nullishCoalesce(options.maxFPS, () => ( (isTest ? 0 : 60)));
2539
2584
  this.respectReducedMotion = _nullishCoalesce(options.respectReducedMotion, () => ( true));
2540
2585
  this.autoThrottle = _nullishCoalesce(options.autoThrottle, () => ( true));
@@ -2548,9 +2593,9 @@ var Scene = (_class7 = class _Scene {
2548
2593
  if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
2549
2594
  this.forcedColorsQuery = window.matchMedia("(forced-colors: active)");
2550
2595
  this.forcedColorsChangeHandler = () => this.markDirty();
2551
- _optionalChain([this, 'access', _45 => _45.forcedColorsQuery, 'access', _46 => _46.addEventListener, 'optionalCall', _47 => _47("change", this.forcedColorsChangeHandler)]);
2596
+ _optionalChain([this, 'access', _48 => _48.forcedColorsQuery, 'access', _49 => _49.addEventListener, 'optionalCall', _50 => _50("change", this.forcedColorsChangeHandler)]);
2552
2597
  }
2553
- this.root = new class RootEntity extends _chunkYLH7F4ZVjs.Entity {
2598
+ this.root = new class RootEntity extends _chunkAGP4VLF4js.Entity {
2554
2599
  isPointInside() {
2555
2600
  return false;
2556
2601
  }
@@ -2559,7 +2604,7 @@ var Scene = (_class7 = class _Scene {
2559
2604
  }
2560
2605
  }("root");
2561
2606
  this.root._scene = this;
2562
- this.overlayRoot = new class OverlayRoot extends _chunkYLH7F4ZVjs.Entity {
2607
+ this.overlayRoot = new class OverlayRoot extends _chunkAGP4VLF4js.Entity {
2563
2608
  isPointInside() {
2564
2609
  return false;
2565
2610
  }
@@ -2570,15 +2615,15 @@ var Scene = (_class7 = class _Scene {
2570
2615
  if (options.renderer) {
2571
2616
  this.renderer = options.renderer;
2572
2617
  } else {
2573
- this.renderer = new (0, _chunkL4SWVP2Hjs.CanvasRenderer)(
2618
+ this.renderer = new (0, _chunkLHONR3GOjs.CanvasRenderer)(
2574
2619
  canvas,
2575
2620
  this.disableWindowResize ? { width: this.width, height: this.height } : void 0,
2576
2621
  this.maxDPR
2577
2622
  );
2578
2623
  }
2579
- _optionalChain([this, 'access', _48 => _48.renderer, 'access', _49 => _49.onContextRestored, 'optionalCall', _50 => _50(() => {
2624
+ _optionalChain([this, 'access', _51 => _51.renderer, 'access', _52 => _52.onContextRestored, 'optionalCall', _53 => _53(() => {
2580
2625
  this.markDirty();
2581
- if (_optionalChain([this, 'access', _51 => _51.renderer, 'access', _52 => _52.isContextLost, 'optionalCall', _53 => _53()]) !== true) this.render(this.renderer);
2626
+ if (_optionalChain([this, 'access', _54 => _54.renderer, 'access', _55 => _55.isContextLost, 'optionalCall', _56 => _56()]) !== true) this.render(this.renderer);
2582
2627
  })]);
2583
2628
  if (typeof document !== "undefined") {
2584
2629
  this.a11yRoot = document.createElement("div");
@@ -2747,7 +2792,7 @@ var Scene = (_class7 = class _Scene {
2747
2792
  watchDevicePixelRatio() {
2748
2793
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
2749
2794
  if (this.dprMediaQuery && this.dprChangeHandler) {
2750
- _optionalChain([this, 'access', _54 => _54.dprMediaQuery, 'access', _55 => _55.removeEventListener, 'optionalCall', _56 => _56("change", this.dprChangeHandler)]);
2795
+ _optionalChain([this, 'access', _57 => _57.dprMediaQuery, 'access', _58 => _58.removeEventListener, 'optionalCall', _59 => _59("change", this.dprChangeHandler)]);
2751
2796
  }
2752
2797
  const dpr = window.devicePixelRatio || 1;
2753
2798
  const query = window.matchMedia(`(resolution: ${dpr}dppx)`);
@@ -2755,7 +2800,7 @@ var Scene = (_class7 = class _Scene {
2755
2800
  this.resize(this.width, this.height);
2756
2801
  this.watchDevicePixelRatio();
2757
2802
  };
2758
- _optionalChain([query, 'access', _57 => _57.addEventListener, 'optionalCall', _58 => _58("change", handler)]);
2803
+ _optionalChain([query, 'access', _60 => _60.addEventListener, 'optionalCall', _61 => _61("change", handler)]);
2759
2804
  this.dprMediaQuery = query;
2760
2805
  this.dprChangeHandler = handler;
2761
2806
  }
@@ -2775,7 +2820,7 @@ var Scene = (_class7 = class _Scene {
2775
2820
  if (typeof gl.addEventListener !== "function") return;
2776
2821
  this.glContextLostHandler = (e) => {
2777
2822
  e.preventDefault();
2778
- _optionalChain([this, 'access', _59 => _59.pointRenderer, 'optionalAccess', _60 => _60.destroy, 'call', _61 => _61()]);
2823
+ _optionalChain([this, 'access', _62 => _62.pointRenderer, 'optionalAccess', _63 => _63.destroy, 'call', _64 => _64()]);
2779
2824
  this.pointRenderer = null;
2780
2825
  };
2781
2826
  this.glContextRestoredHandler = () => {
@@ -2796,12 +2841,35 @@ var Scene = (_class7 = class _Scene {
2796
2841
  this.contentSelectionAnchor = null;
2797
2842
  if (this.a11yRoot) this.a11yRoot.style.pointerEvents = "none";
2798
2843
  }
2844
+ /**
2845
+ * Index of the carrier line currently holding a selection inside `el`, or
2846
+ * `null`.
2847
+ *
2848
+ * Lets a partial re-materialization decide whether the user's selection is even
2849
+ * affected. Checks the tracked anchor first (it survives a drag) and falls back
2850
+ * to the live DOM selection.
2851
+ */
2852
+ contentGridSelectionLine(el) {
2853
+ const candidates = [_optionalChain([this, 'access', _65 => _65.contentSelectionAnchor, 'optionalAccess', _66 => _66.node])];
2854
+ if (typeof window !== "undefined" && typeof window.getSelection === "function") {
2855
+ const selection = window.getSelection();
2856
+ candidates.push(_optionalChain([selection, 'optionalAccess', _67 => _67.anchorNode]), _optionalChain([selection, 'optionalAccess', _68 => _68.focusNode]));
2857
+ }
2858
+ for (const candidate of candidates) {
2859
+ if (!candidate || !el.contains(candidate)) continue;
2860
+ let cursor = candidate;
2861
+ while (cursor && cursor.parentNode !== el) cursor = cursor.parentNode;
2862
+ const lineIndex = _optionalChain([cursor, 'optionalAccess', _69 => _69.dataset, 'optionalAccess', _70 => _70.vectoGridLine]);
2863
+ if (lineIndex !== void 0) return Number(lineIndex);
2864
+ }
2865
+ return null;
2866
+ }
2799
2867
  releaseContentSelectionForRebuild(el) {
2800
2868
  const selection = typeof window !== "undefined" && typeof window.getSelection === "function" ? window.getSelection() : null;
2801
- const ownsSelection = this.contentSelectionAnchor && el.contains(this.contentSelectionAnchor.node) || (_optionalChain([selection, 'optionalAccess', _62 => _62.anchorNode]) ? el.contains(selection.anchorNode) : false) || (_optionalChain([selection, 'optionalAccess', _63 => _63.focusNode]) ? el.contains(selection.focusNode) : false);
2869
+ const ownsSelection = this.contentSelectionAnchor && el.contains(this.contentSelectionAnchor.node) || (_optionalChain([selection, 'optionalAccess', _71 => _71.anchorNode]) ? el.contains(selection.anchorNode) : false) || (_optionalChain([selection, 'optionalAccess', _72 => _72.focusNode]) ? el.contains(selection.focusNode) : false);
2802
2870
  if (!ownsSelection) return;
2803
2871
  this.endContentSelectionDrag();
2804
- _optionalChain([selection, 'optionalAccess', _64 => _64.removeAllRanges, 'call', _65 => _65()]);
2872
+ _optionalChain([selection, 'optionalAccess', _73 => _73.removeAllRanges, 'call', _74 => _74()]);
2805
2873
  }
2806
2874
  /**
2807
2875
  * Rebuild a content-projection element's DOM (`rebuild`) while preserving a
@@ -2860,7 +2928,7 @@ var Scene = (_class7 = class _Scene {
2860
2928
  }
2861
2929
  /** Convert browser viewport coordinates into this Scene's logical coordinates. */
2862
2930
  clientToScene(clientX, clientY) {
2863
- const rect = _optionalChain([this, 'access', _66 => _66.canvas, 'access', _67 => _67.getBoundingClientRect, 'optionalCall', _68 => _68()]);
2931
+ const rect = _optionalChain([this, 'access', _75 => _75.canvas, 'access', _76 => _76.getBoundingClientRect, 'optionalCall', _77 => _77()]);
2864
2932
  if (!rect) return { x: clientX, y: clientY };
2865
2933
  const cssWidth = rect.width || this.canvas.clientWidth || this.width;
2866
2934
  const cssHeight = rect.height || this.canvas.clientHeight || this.height;
@@ -2881,13 +2949,24 @@ var Scene = (_class7 = class _Scene {
2881
2949
  this.registerActiveDriverSubtree(entity);
2882
2950
  return this;
2883
2951
  }
2884
- clearContentGridState(entityId, el) {
2952
+ /**
2953
+ * Reset per-grid calibration and bookkeeping before a (re)materialization.
2954
+ *
2955
+ * @param entityId - Owning entity, keyed into the calibration maps.
2956
+ * @param el - The projection element.
2957
+ * @param releaseSelection - Whether to drop a selection this element owns.
2958
+ * Pass `false` when carrier lines are being reused: the selection's DOM nodes
2959
+ * survive the pass, so tearing it down would wipe a user's selection on every
2960
+ * streamed chunk — the exact bug `preserveContentSelectionAcrossRebuild`
2961
+ * exists to prevent on the non-grid path.
2962
+ */
2963
+ clearContentGridState(entityId, el, releaseSelection = true) {
2885
2964
  const calibrationFrame = this.contentGridCalibrationFrames.get(entityId);
2886
2965
  if (calibrationFrame !== void 0 && typeof cancelAnimationFrame === "function") {
2887
2966
  cancelAnimationFrame(calibrationFrame);
2888
2967
  }
2889
2968
  this.contentGridCalibrationFrames.delete(entityId);
2890
- _optionalChain([this, 'access', _69 => _69.contentGridCalibrationProbes, 'access', _70 => _70.get, 'call', _71 => _71(entityId), 'optionalAccess', _72 => _72.remove, 'call', _73 => _73()]);
2969
+ _optionalChain([this, 'access', _78 => _78.contentGridCalibrationProbes, 'access', _79 => _79.get, 'call', _80 => _80(entityId), 'optionalAccess', _81 => _81.remove, 'call', _82 => _82()]);
2891
2970
  this.contentGridCalibrationProbes.delete(entityId);
2892
2971
  delete el.dataset.vectoGridCalibrationPending;
2893
2972
  delete el.dataset.vectoGridCalibration;
@@ -2897,7 +2976,7 @@ var Scene = (_class7 = class _Scene {
2897
2976
  delete el.dataset.vectoGridMaterializeMs;
2898
2977
  delete el.dataset.vectoGridCalibrationSamples;
2899
2978
  delete el.dataset.vectoGridCalibrationMs;
2900
- this.releaseContentSelectionForRebuild(el);
2979
+ if (releaseSelection) this.releaseContentSelectionForRebuild(el);
2901
2980
  }
2902
2981
  /**
2903
2982
  * Drop any projected elements under `node` without touching the entity tree.
@@ -2939,7 +3018,7 @@ var Scene = (_class7 = class _Scene {
2939
3018
  }
2940
3019
  if (this.hoveredA11yElements.has(el)) {
2941
3020
  this.hoveredA11yElements.delete(el);
2942
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointerleave", node, void 0, false));
3021
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("pointerleave", node, void 0, false));
2943
3022
  }
2944
3023
  this.preserveFocusOnRemoval(el);
2945
3024
  el.remove();
@@ -3041,12 +3120,12 @@ var Scene = (_class7 = class _Scene {
3041
3120
  this.canvasResizeObserver = null;
3042
3121
  }
3043
3122
  if (this.dprMediaQuery && this.dprChangeHandler) {
3044
- _optionalChain([this, 'access', _74 => _74.dprMediaQuery, 'access', _75 => _75.removeEventListener, 'optionalCall', _76 => _76("change", this.dprChangeHandler)]);
3123
+ _optionalChain([this, 'access', _83 => _83.dprMediaQuery, 'access', _84 => _84.removeEventListener, 'optionalCall', _85 => _85("change", this.dprChangeHandler)]);
3045
3124
  this.dprMediaQuery = null;
3046
3125
  this.dprChangeHandler = null;
3047
3126
  }
3048
3127
  if (this.forcedColorsQuery && this.forcedColorsChangeHandler) {
3049
- _optionalChain([this, 'access', _77 => _77.forcedColorsQuery, 'access', _78 => _78.removeEventListener, 'optionalCall', _79 => _79("change", this.forcedColorsChangeHandler)]);
3128
+ _optionalChain([this, 'access', _86 => _86.forcedColorsQuery, 'access', _87 => _87.removeEventListener, 'optionalCall', _88 => _88("change", this.forcedColorsChangeHandler)]);
3050
3129
  this.forcedColorsQuery = null;
3051
3130
  this.forcedColorsChangeHandler = null;
3052
3131
  }
@@ -3064,9 +3143,9 @@ var Scene = (_class7 = class _Scene {
3064
3143
  }
3065
3144
  this.pointerEventTarget = null;
3066
3145
  }
3067
- _optionalChain([this, 'access', _80 => _80.a11yRoot, 'optionalAccess', _81 => _81.remove, 'call', _82 => _82()]);
3146
+ _optionalChain([this, 'access', _89 => _89.a11yRoot, 'optionalAccess', _90 => _90.remove, 'call', _91 => _91()]);
3068
3147
  this.focusSentinel = null;
3069
- _optionalChain([this, 'access', _83 => _83.portalRoot, 'optionalAccess', _84 => _84.remove, 'call', _85 => _85()]);
3148
+ _optionalChain([this, 'access', _92 => _92.portalRoot, 'optionalAccess', _93 => _93.remove, 'call', _94 => _94()]);
3070
3149
  this.a11yElements.clear();
3071
3150
  for (const el of this.contentElements.values()) el.remove();
3072
3151
  this.contentElements.clear();
@@ -3089,10 +3168,10 @@ var Scene = (_class7 = class _Scene {
3089
3168
  }
3090
3169
  this.glContextLostHandler = null;
3091
3170
  this.glContextRestoredHandler = null;
3092
- _optionalChain([this, 'access', _86 => _86.pointRenderer, 'optionalAccess', _87 => _87.destroy, 'call', _88 => _88()]);
3093
- _optionalChain([this, 'access', _89 => _89.renderer, 'access', _90 => _90.dispose, 'optionalCall', _91 => _91()]);
3094
- _optionalChain([this, 'access', _92 => _92.glCanvas, 'optionalAccess', _93 => _93.remove, 'call', _94 => _94()]);
3095
- _optionalChain([this, 'access', _95 => _95.gpuCanvas, 'optionalAccess', _96 => _96.remove, 'call', _97 => _97()]);
3171
+ _optionalChain([this, 'access', _95 => _95.pointRenderer, 'optionalAccess', _96 => _96.destroy, 'call', _97 => _97()]);
3172
+ _optionalChain([this, 'access', _98 => _98.renderer, 'access', _99 => _99.dispose, 'optionalCall', _100 => _100()]);
3173
+ _optionalChain([this, 'access', _101 => _101.glCanvas, 'optionalAccess', _102 => _102.remove, 'call', _103 => _103()]);
3174
+ _optionalChain([this, 'access', _104 => _104.gpuCanvas, 'optionalAccess', _105 => _105.remove, 'call', _106 => _106()]);
3096
3175
  this.gpuCanvas = null;
3097
3176
  this.gpuContext = null;
3098
3177
  if (this.recoveryTimerId) {
@@ -3104,7 +3183,7 @@ var Scene = (_class7 = class _Scene {
3104
3183
  this.manager = null;
3105
3184
  }
3106
3185
  if (this.device) {
3107
- _optionalChain([this, 'access', _98 => _98.device, 'access', _99 => _99.destroy, 'optionalCall', _100 => _100()]);
3186
+ _optionalChain([this, 'access', _107 => _107.device, 'access', _108 => _108.destroy, 'optionalCall', _109 => _109()]);
3108
3187
  this.device = null;
3109
3188
  }
3110
3189
  }
@@ -3227,6 +3306,26 @@ var Scene = (_class7 = class _Scene {
3227
3306
  get overlayRootEntity() {
3228
3307
  return this.overlayRoot;
3229
3308
  }
3309
+ /**
3310
+ * Advance and render exactly one frame, synchronously.
3311
+ *
3312
+ * This renders UNCONDITIONALLY: it consults neither {@link renderMode} nor
3313
+ * {@link dirty}, and it does not apply the `always`-mode idle auto-throttle.
3314
+ * That is deliberate — a deterministic driver (video export, a test, a
3315
+ * fixed-step benchmark) asks for a frame because it wants that frame, not a
3316
+ * scheduler opinion about whether it is needed.
3317
+ *
3318
+ * The consequence is a measurement footgun worth stating explicitly: a
3319
+ * benchmark that drives frames through `step()` CANNOT observe frame skipping,
3320
+ * so `always` and `onDemand` produce byte-identical draw counts through this
3321
+ * path. An investigation into whether `onDemand` skips redundant repaints once
3322
+ * concluded "it does not" on exactly that basis; on the real rAF loop the same
3323
+ * workload rendered ~1.0 frames per content change. To measure anything about
3324
+ * scheduling, use {@link start} and let `requestAnimationFrame` drive.
3325
+ *
3326
+ * @param dt Seconds to advance. Not clamped by `MAX_FRAME_DT` — the caller
3327
+ * chooses the step, since determinism is the point.
3328
+ */
3230
3329
  step(dt) {
3231
3330
  const time = this.lastTime + dt;
3232
3331
  this.lastTime = time;
@@ -3245,6 +3344,24 @@ var Scene = (_class7 = class _Scene {
3245
3344
  this.dirty = true;
3246
3345
  if (this._dirtyTracking && source) this.recordDirtyReason(source);
3247
3346
  }
3347
+ /**
3348
+ * Increments whenever the tree's shape changes: add, remove or reparent.
3349
+ *
3350
+ * Already maintained for the resident WASM transform store (see
3351
+ * {@link markStructureChanged}, called from `Entity.add`/`remove`), and exposed
3352
+ * here because a cache of the tree's shape — a DevTools tree model, a serialized
3353
+ * snapshot — is valid exactly as long as this value is unchanged. Comparing it is
3354
+ * O(1) against re-walking the tree, which is what it replaces: DevTools rebuilt
3355
+ * both trees on a fixed 500 ms interval, a constant cost proportional to entity
3356
+ * count, purely because it had no way to ask whether the shape had changed.
3357
+ *
3358
+ * Property changes do NOT bump it. Moving or restyling an entity leaves the
3359
+ * shape intact, so a consumer that also cares about values must read those
3360
+ * directly rather than rebuilding a tree.
3361
+ */
3362
+ get structureVersion() {
3363
+ return this._structureVersion;
3364
+ }
3248
3365
  /**
3249
3366
  * Record who marked the scene dirty and why.
3250
3367
  *
@@ -3371,6 +3488,7 @@ var Scene = (_class7 = class _Scene {
3371
3488
  this.pruneA11ySubtree(node);
3372
3489
  return;
3373
3490
  }
3491
+ const nodeStart = this._phaseTiming ? performance.now() : 0;
3374
3492
  if (this.shouldProjectA11y(node)) {
3375
3493
  let el = this.a11yElements.get(node.id);
3376
3494
  const attrs = node.getA11yAttributes();
@@ -3412,20 +3530,20 @@ var Scene = (_class7 = class _Scene {
3412
3530
  el.style.background = "transparent";
3413
3531
  }
3414
3532
  el.addEventListener("click", (e) => {
3415
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("click", node, e));
3533
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("click", node, e));
3416
3534
  });
3417
3535
  el.addEventListener("dblclick", (e) => {
3418
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("dblclick", node, e));
3536
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("dblclick", node, e));
3419
3537
  });
3420
3538
  el.addEventListener("mouseenter", (e) => {
3421
3539
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.2)";
3422
3540
  this.hoveredA11yElements.add(el);
3423
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("hover", node, e, false));
3541
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("hover", node, e, false));
3424
3542
  });
3425
3543
  el.addEventListener("mouseleave", (e) => {
3426
3544
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.05)";
3427
3545
  this.hoveredA11yElements.delete(el);
3428
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointerleave", node, e, false));
3546
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("pointerleave", node, e, false));
3429
3547
  });
3430
3548
  const capEl = el;
3431
3549
  const releasePointer = (event) => {
@@ -3441,32 +3559,32 @@ var Scene = (_class7 = class _Scene {
3441
3559
  };
3442
3560
  el.addEventListener("pointerdown", (e) => {
3443
3561
  if (typeof capEl.setPointerCapture === "function") capEl.setPointerCapture(e.pointerId);
3444
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointerdown", node, e));
3562
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("pointerdown", node, e));
3445
3563
  });
3446
3564
  el.addEventListener("pointerup", (e) => {
3447
3565
  releasePointer(e);
3448
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointerup", node, e));
3566
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("pointerup", node, e));
3449
3567
  });
3450
3568
  el.addEventListener("pointercancel", (e) => {
3451
3569
  releasePointer(e);
3452
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointercancel", node, e));
3570
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("pointercancel", node, e));
3453
3571
  });
3454
3572
  el.addEventListener(
3455
3573
  "pointermove",
3456
- (e) => node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointermove", node, e))
3574
+ (e) => node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("pointermove", node, e))
3457
3575
  );
3458
3576
  el.addEventListener(
3459
3577
  "wheel",
3460
3578
  (e) => {
3461
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("wheel", node, e));
3579
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("wheel", node, e));
3462
3580
  },
3463
3581
  { passive: false }
3464
3582
  );
3465
3583
  el.addEventListener("keydown", (e) => {
3466
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("keydown", node, e));
3584
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("keydown", node, e));
3467
3585
  });
3468
3586
  el.addEventListener("keyup", (e) => {
3469
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("keyup", node, e));
3587
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("keyup", node, e));
3470
3588
  });
3471
3589
  if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
3472
3590
  const input = el;
@@ -3497,7 +3615,7 @@ var Scene = (_class7 = class _Scene {
3497
3615
  el.addEventListener("compositionupdate", (e) => {
3498
3616
  const data = _nullishCoalesce(e.data, () => ( ""));
3499
3617
  composition = {
3500
- start: _nullishCoalesce(_optionalChain([composition, 'optionalAccess', _101 => _101.start]), () => ( 0)),
3618
+ start: _nullishCoalesce(_optionalChain([composition, 'optionalAccess', _110 => _110.start]), () => ( 0)),
3501
3619
  length: data.length
3502
3620
  };
3503
3621
  forward();
@@ -3532,7 +3650,7 @@ var Scene = (_class7 = class _Scene {
3532
3650
  el.addEventListener("keydown", (e) => {
3533
3651
  if (e.key === "Enter" || e.key === " ") {
3534
3652
  e.preventDefault();
3535
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("click", node, e));
3653
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("click", node, e));
3536
3654
  }
3537
3655
  });
3538
3656
  }
@@ -3570,7 +3688,7 @@ var Scene = (_class7 = class _Scene {
3570
3688
  this.syncOptionalAttribute(
3571
3689
  el,
3572
3690
  "href",
3573
- attrs.href === void 0 ? void 0 : _chunkL4SWVP2Hjs.sanitizeUrl.call(void 0, attrs.href)
3691
+ attrs.href === void 0 ? void 0 : _chunkLHONR3GOjs.sanitizeUrl.call(void 0, attrs.href)
3574
3692
  );
3575
3693
  this.syncOptionalAttribute(el, "target", attrs.target);
3576
3694
  }
@@ -3713,7 +3831,14 @@ var Scene = (_class7 = class _Scene {
3713
3831
  if (el.style.display !== display) el.style.display = display;
3714
3832
  }
3715
3833
  }
3716
- this.syncContentProjection(node);
3834
+ if (this._phaseTiming) {
3835
+ const projectionStart = performance.now();
3836
+ this.syncContentProjection(node);
3837
+ this._recordPhase("contentProjection", performance.now() - projectionStart);
3838
+ this._recordPhase("a11yNodes", projectionStart - nodeStart);
3839
+ } else {
3840
+ this.syncContentProjection(node);
3841
+ }
3717
3842
  for (const child of node.children) this.syncA11y(child);
3718
3843
  if (node === this.root) {
3719
3844
  for (const overlay of this.overlayRoot.children) this.syncA11y(overlay);
@@ -3814,7 +3939,7 @@ var Scene = (_class7 = class _Scene {
3814
3939
  el.addEventListener(
3815
3940
  "wheel",
3816
3941
  (e2) => {
3817
- node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("wheel", node, e2));
3942
+ node.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)("wheel", node, e2));
3818
3943
  },
3819
3944
  { passive: false }
3820
3945
  );
@@ -3827,7 +3952,9 @@ var Scene = (_class7 = class _Scene {
3827
3952
  this.clearContentGridState(node.id, el);
3828
3953
  }
3829
3954
  if (projection.grid) {
3955
+ const gridSyncStart = this._phaseTiming ? performance.now() : 0;
3830
3956
  this.syncContentGridProjection(node, el, projection, projection.grid);
3957
+ if (this._phaseTiming) this._recordPhase("gridSync", performance.now() - gridSyncStart);
3831
3958
  } else if (lines && lines.length > 0) {
3832
3959
  const signature = JSON.stringify({
3833
3960
  lines,
@@ -3933,21 +4060,38 @@ var Scene = (_class7 = class _Scene {
3933
4060
  const signature = `${grid.revision}`;
3934
4061
  if (el.dataset.vectoContentGrid !== signature) {
3935
4062
  const materializeStart = typeof performance !== "undefined" ? performance.now() : 0;
3936
- this.clearContentGridState(node.id, el);
3937
- el.replaceChildren();
4063
+ this.clearContentGridState(node.id, el, false);
3938
4064
  const projectionLines = _nullishCoalesce(projection.lines, () => ( []));
4065
+ const selectionLine = this.contentGridSelectionLine(el);
4066
+ let rebuiltSelectionLine = false;
4067
+ const existingLines = el.children;
3939
4068
  for (let lineIndex = 0; lineIndex < grid.lines.length; lineIndex++) {
3940
4069
  const gridLine = grid.lines[lineIndex];
3941
4070
  const projectedLine = projectionLines[lineIndex];
3942
- const lineHeight = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _102 => _102.lineHeight]), () => ( grid.lineHeight));
3943
- const baseline = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _103 => _103.baseline]), () => ( grid.baseline));
3944
- const lineFont = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _104 => _104.font]), () => ( grid.font));
4071
+ const lineHeight = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _111 => _111.lineHeight]), () => ( grid.lineHeight));
4072
+ const baseline = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _112 => _112.baseline]), () => ( grid.baseline));
4073
+ const lineFont = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _113 => _113.font]), () => ( grid.font));
4074
+ const lineSignature = contentGridLineSignature(
4075
+ grid,
4076
+ gridLine,
4077
+ projectedLine,
4078
+ lineHeight,
4079
+ baseline,
4080
+ lineFont,
4081
+ lineIndex === 0
4082
+ );
4083
+ const reusable = existingLines[lineIndex];
4084
+ if (reusable !== void 0 && reusable.dataset.vectoGridLineSig === lineSignature && reusable.dataset.vectoGridLine === `${lineIndex}`) {
4085
+ continue;
4086
+ }
4087
+ if (selectionLine !== null && selectionLine === lineIndex) rebuiltSelectionLine = true;
3945
4088
  const lineElement = document.createElement("span");
4089
+ lineElement.dataset.vectoGridLineSig = lineSignature;
3946
4090
  lineElement.dir = "ltr";
3947
4091
  lineElement.dataset.vectoGridLine = `${lineIndex}`;
3948
4092
  lineElement.style.position = "absolute";
3949
- lineElement.style.left = `${_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _105 => _105.x]), () => ( 0))}px`;
3950
- lineElement.style.top = `${(_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _106 => _106.y]), () => ( lineIndex * grid.lineHeight))) + baseline - _text.cssLineBoxBaseline.call(void 0, lineFont, lineHeight)}px`;
4093
+ lineElement.style.left = `${_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _114 => _114.x]), () => ( 0))}px`;
4094
+ lineElement.style.top = `${(_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _115 => _115.y]), () => ( lineIndex * grid.lineHeight))) + baseline - _text.cssLineBoxBaseline.call(void 0, lineFont, lineHeight)}px`;
3951
4095
  lineElement.style.width = `${gridLine.width}px`;
3952
4096
  lineElement.style.height = `${lineHeight}px`;
3953
4097
  lineElement.style.whiteSpace = "pre";
@@ -3984,6 +4128,8 @@ var Scene = (_class7 = class _Scene {
3984
4128
  cellElement.style.font = lineFont;
3985
4129
  cellElement.style.lineHeight = `${lineHeight}px`;
3986
4130
  cellElement.style.transformOrigin = "0 50%";
4131
+ cellElement.dataset.vectoGridFont = lineFont;
4132
+ cellElement.dataset.vectoGridLineHeight = `${lineHeight}px`;
3987
4133
  lineElement.appendChild(cellElement);
3988
4134
  logicalX += cell.advance;
3989
4135
  }
@@ -4007,13 +4153,24 @@ var Scene = (_class7 = class _Scene {
4007
4153
  lineElement.appendChild(marker);
4008
4154
  }
4009
4155
  }
4010
- el.appendChild(lineElement);
4156
+ const occupant = el.children[lineIndex];
4157
+ if (occupant) el.replaceChild(lineElement, occupant);
4158
+ else el.appendChild(lineElement);
4011
4159
  }
4160
+ while (el.children.length > grid.lines.length) {
4161
+ if (selectionLine !== null && selectionLine >= grid.lines.length) {
4162
+ rebuiltSelectionLine = true;
4163
+ }
4164
+ _optionalChain([el, 'access', _116 => _116.lastElementChild, 'optionalAccess', _117 => _117.remove, 'call', _118 => _118()]);
4165
+ }
4166
+ if (rebuiltSelectionLine) this.releaseContentSelectionForRebuild(el);
4012
4167
  el.dataset.vectoProjectionLines = signature;
4013
4168
  el.dataset.vectoContentGrid = signature;
4014
4169
  el.dataset.vectoGridCarriers = `${el.querySelectorAll("[data-vecto-grid-cell]").length}`;
4015
4170
  if (typeof performance !== "undefined") {
4016
- el.dataset.vectoGridMaterializeMs = `${performance.now() - materializeStart}`;
4171
+ const materializeMs = performance.now() - materializeStart;
4172
+ el.dataset.vectoGridMaterializeMs = `${materializeMs}`;
4173
+ if (this._phaseTiming) this._recordPhase("gridMaterialize", materializeMs);
4017
4174
  }
4018
4175
  delete el.dataset.vectoGridCalibration;
4019
4176
  delete el.dataset.vectoGridReady;
@@ -4021,7 +4178,11 @@ var Scene = (_class7 = class _Scene {
4021
4178
  const pageScaleX = this.getContentMetricScaleX();
4022
4179
  const calibrationKey = `${signature}:${this.contentFontEpoch}:${pageScaleX.toFixed(4)}`;
4023
4180
  if (el.dataset.vectoGridCalibration !== calibrationKey) {
4181
+ const calibStart = this._phaseTiming ? performance.now() : 0;
4024
4182
  this.scheduleContentGridCalibration(node.id, el, calibrationKey, pageScaleX);
4183
+ if (this._phaseTiming) {
4184
+ this._recordPhase("gridCalibrateSchedule", performance.now() - calibStart);
4185
+ }
4025
4186
  }
4026
4187
  }
4027
4188
  getContentMetricScaleX() {
@@ -4039,11 +4200,32 @@ var Scene = (_class7 = class _Scene {
4039
4200
  scheduleContentGridCalibration(entityId, el, calibrationKey, pageScaleX) {
4040
4201
  if (typeof requestAnimationFrame !== "function") return;
4041
4202
  if (el.dataset.vectoGridCalibrationPending === calibrationKey) return;
4203
+ const stamp = `${this.contentFontEpoch}:${pageScaleX.toFixed(4)}`;
4204
+ if (this.contentGridCalibrationStamp !== stamp) {
4205
+ this.contentGridCalibrationStamp = stamp;
4206
+ this.contentGridCalibrationGeneration++;
4207
+ }
4208
+ const generation = `${this.contentGridCalibrationGeneration}`;
4209
+ const pendingCells = el.querySelectorAll(
4210
+ `[data-vecto-grid-cell]:not([data-vecto-grid-calib="${generation}"])`
4211
+ );
4212
+ if (pendingCells.length === 0) {
4213
+ el.dataset.vectoGridCalibrationSamples = "0";
4214
+ delete el.dataset.vectoGridCalibrationPending;
4215
+ const readyFrame = requestAnimationFrame(() => {
4216
+ this.contentGridCalibrationFrames.delete(entityId);
4217
+ if (!el.isConnected) return;
4218
+ el.dataset.vectoGridCalibration = calibrationKey;
4219
+ el.dataset.vectoGridReady = "true";
4220
+ });
4221
+ this.contentGridCalibrationFrames.set(entityId, readyFrame);
4222
+ return;
4223
+ }
4042
4224
  const previous = this.contentGridCalibrationFrames.get(entityId);
4043
4225
  if (previous !== void 0 && typeof cancelAnimationFrame === "function") {
4044
4226
  cancelAnimationFrame(previous);
4045
4227
  }
4046
- _optionalChain([this, 'access', _107 => _107.contentGridCalibrationProbes, 'access', _108 => _108.get, 'call', _109 => _109(entityId), 'optionalAccess', _110 => _110.remove, 'call', _111 => _111()]);
4228
+ _optionalChain([this, 'access', _119 => _119.contentGridCalibrationProbes, 'access', _120 => _120.get, 'call', _121 => _121(entityId), 'optionalAccess', _122 => _122.remove, 'call', _123 => _123()]);
4047
4229
  this.contentGridCalibrationProbes.delete(entityId);
4048
4230
  const calibrationStart = typeof performance !== "undefined" ? performance.now() : 0;
4049
4231
  const probe = document.createElement("div");
@@ -4069,18 +4251,22 @@ var Scene = (_class7 = class _Scene {
4069
4251
  probe.append(probeOrigin, probeX);
4070
4252
  const measurements = [];
4071
4253
  const measurementsByKey = /* @__PURE__ */ new Map();
4072
- for (const target of el.querySelectorAll("[data-vecto-grid-cell]")) {
4254
+ const scanStart = this._phaseTiming ? performance.now() : 0;
4255
+ for (const target of pendingCells) {
4073
4256
  const sourceLength = Number(_nullishCoalesce(target.dataset.vectoGridSourceLength, () => ( 0)));
4074
4257
  const targetWidth = Number(_nullishCoalesce(target.dataset.vectoGridAdvance, () => ( 0)));
4075
- if (sourceLength <= 0 || targetWidth <= 0) continue;
4076
- const sourceText = _nullishCoalesce(_optionalChain([target, 'access', _112 => _112.textContent, 'optionalAccess', _113 => _113.slice, 'call', _114 => _114(0, sourceLength)]), () => ( ""));
4077
- if (!sourceText) continue;
4078
- const measurementKey = JSON.stringify([
4079
- target.style.font,
4080
- target.style.lineHeight,
4081
- targetWidth,
4082
- sourceText
4083
- ]);
4258
+ if (sourceLength <= 0 || targetWidth <= 0) {
4259
+ target.dataset.vectoGridCalib = generation;
4260
+ continue;
4261
+ }
4262
+ const sourceText = _nullishCoalesce(_optionalChain([target, 'access', _124 => _124.textContent, 'optionalAccess', _125 => _125.slice, 'call', _126 => _126(0, sourceLength)]), () => ( ""));
4263
+ if (!sourceText) {
4264
+ target.dataset.vectoGridCalib = generation;
4265
+ continue;
4266
+ }
4267
+ const cellFont = _nullishCoalesce(target.dataset.vectoGridFont, () => ( ""));
4268
+ const cellLineHeight = _nullishCoalesce(target.dataset.vectoGridLineHeight, () => ( ""));
4269
+ const measurementKey = JSON.stringify([cellFont, cellLineHeight, targetWidth, sourceText]);
4084
4270
  const shared = measurementsByKey.get(measurementKey);
4085
4271
  if (shared) {
4086
4272
  shared.targets.push(target);
@@ -4092,8 +4278,8 @@ var Scene = (_class7 = class _Scene {
4092
4278
  carrier.style.left = "0";
4093
4279
  carrier.style.top = "0";
4094
4280
  carrier.style.whiteSpace = "pre";
4095
- carrier.style.font = target.style.font;
4096
- carrier.style.lineHeight = target.style.lineHeight;
4281
+ carrier.style.font = cellFont;
4282
+ carrier.style.lineHeight = cellLineHeight;
4097
4283
  carrier.style.fontVariantLigatures = "none";
4098
4284
  carrier.style.fontKerning = "none";
4099
4285
  const source = document.createTextNode(sourceText);
@@ -4108,7 +4294,17 @@ var Scene = (_class7 = class _Scene {
4108
4294
  measurements.push(measurement);
4109
4295
  measurementsByKey.set(measurementKey, measurement);
4110
4296
  }
4297
+ if (this._phaseTiming) this._recordPhase("calibScan", performance.now() - scanStart);
4298
+ if (measurements.length === 0) {
4299
+ el.dataset.vectoGridCalibration = calibrationKey;
4300
+ el.dataset.vectoGridReady = "true";
4301
+ el.dataset.vectoGridCalibrationSamples = "0";
4302
+ delete el.dataset.vectoGridCalibrationPending;
4303
+ return;
4304
+ }
4305
+ const appendStart = this._phaseTiming ? performance.now() : 0;
4111
4306
  (_nullishCoalesce(_nullishCoalesce(this.a11yRoot, () => ( document.body)), () => ( document.documentElement))).appendChild(probe);
4307
+ if (this._phaseTiming) this._recordPhase("calibProbeBuild", performance.now() - appendStart);
4112
4308
  el.dataset.vectoGridCalibrationSamples = `${measurements.length}`;
4113
4309
  this.contentGridCalibrationProbes.set(entityId, probe);
4114
4310
  el.dataset.vectoGridCalibrationPending = calibrationKey;
@@ -4152,6 +4348,7 @@ var Scene = (_class7 = class _Scene {
4152
4348
  }
4153
4349
  for (const { element, scale } of updates) {
4154
4350
  element.style.transform = Math.abs(scale - 1) <= 1e-3 ? "" : `scaleX(${scale})`;
4351
+ element.dataset.vectoGridCalib = generation;
4155
4352
  }
4156
4353
  el.dataset.vectoGridCalibration = calibrationKey;
4157
4354
  el.dataset.vectoGridReady = "true";
@@ -4273,12 +4470,12 @@ var Scene = (_class7 = class _Scene {
4273
4470
  syncOverlayGeometry() {
4274
4471
  const parent = this.canvas.parentElement;
4275
4472
  if (!parent) return;
4276
- const canvasRect = _optionalChain([this, 'access', _115 => _115.canvas, 'access', _116 => _116.getBoundingClientRect, 'optionalCall', _117 => _117()]);
4277
- const parentRect = _optionalChain([parent, 'access', _118 => _118.getBoundingClientRect, 'optionalCall', _119 => _119()]);
4278
- const cssWidth = _optionalChain([canvasRect, 'optionalAccess', _120 => _120.width]) || this.canvas.clientWidth || this.width;
4279
- const cssHeight = _optionalChain([canvasRect, 'optionalAccess', _121 => _121.height]) || this.canvas.clientHeight || this.height;
4280
- const left = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _122 => _122.left]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _123 => _123.left]), () => ( 0))) - (parent.clientLeft || 0) + parent.scrollLeft;
4281
- const top = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _124 => _124.top]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _125 => _125.top]), () => ( 0))) - (parent.clientTop || 0) + parent.scrollTop;
4473
+ const canvasRect = _optionalChain([this, 'access', _127 => _127.canvas, 'access', _128 => _128.getBoundingClientRect, 'optionalCall', _129 => _129()]);
4474
+ const parentRect = _optionalChain([parent, 'access', _130 => _130.getBoundingClientRect, 'optionalCall', _131 => _131()]);
4475
+ const cssWidth = _optionalChain([canvasRect, 'optionalAccess', _132 => _132.width]) || this.canvas.clientWidth || this.width;
4476
+ const cssHeight = _optionalChain([canvasRect, 'optionalAccess', _133 => _133.height]) || this.canvas.clientHeight || this.height;
4477
+ const left = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _134 => _134.left]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _135 => _135.left]), () => ( 0))) - (parent.clientLeft || 0) + parent.scrollLeft;
4478
+ const top = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _136 => _136.top]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _137 => _137.top]), () => ( 0))) - (parent.clientTop || 0) + parent.scrollTop;
4282
4479
  const scaleX = this.width > 0 ? cssWidth / this.width : 1;
4283
4480
  const scaleY = this.height > 0 ? cssHeight / this.height : 1;
4284
4481
  const prev = this._overlayGeometry;
@@ -4417,7 +4614,7 @@ var Scene = (_class7 = class _Scene {
4417
4614
  * (and {@link respectReducedMotion} is on). `0` means uncapped.
4418
4615
  */
4419
4616
  effectiveMaxFPS() {
4420
- const reduced = this.respectReducedMotion && !!_optionalChain([this, 'access', _126 => _126.reducedMotionQuery, 'optionalAccess', _127 => _127.matches]);
4617
+ const reduced = this.respectReducedMotion && !!_optionalChain([this, 'access', _138 => _138.reducedMotionQuery, 'optionalAccess', _139 => _139.matches]);
4421
4618
  if (reduced)
4422
4619
  return this.maxFPS > 0 ? Math.min(this.maxFPS, REDUCED_MOTION_FPS) : REDUCED_MOTION_FPS;
4423
4620
  return this.maxFPS;
@@ -4490,7 +4687,7 @@ var Scene = (_class7 = class _Scene {
4490
4687
  * @param time - Current absolute time in milliseconds (default 0).
4491
4688
  */
4492
4689
  render(renderer, dt = 0, time = 0) {
4493
- if (_optionalChain([renderer, 'access', _128 => _128.isContextLost, 'optionalCall', _129 => _129()])) return;
4690
+ if (_optionalChain([renderer, 'access', _140 => _140.isContextLost, 'optionalCall', _141 => _141()])) return;
4494
4691
  const isMainRenderer = renderer === this.renderer;
4495
4692
  if (isMainRenderer && this.a11yRoot && this.canvas.parentElement) {
4496
4693
  const parentStyle = this.canvas.parentElement.style;
@@ -4616,14 +4813,14 @@ var Scene = (_class7 = class _Scene {
4616
4813
  }
4617
4814
  renderer.clear();
4618
4815
  if (isMainRenderer) {
4619
- _optionalChain([this, 'access', _130 => _130.pointRenderer, 'optionalAccess', _131 => _131.begin, 'call', _132 => _132()]);
4816
+ _optionalChain([this, 'access', _142 => _142.pointRenderer, 'optionalAccess', _143 => _143.begin, 'call', _144 => _144()]);
4620
4817
  }
4621
4818
  const vw = this.width;
4622
4819
  const vh = this.height;
4623
4820
  let walkHadAnimation = false;
4624
4821
  let walkHadInteractive = false;
4625
4822
  const runUpdate = (node) => {
4626
- const overridesUpdate = node.update !== _chunkYLH7F4ZVjs.Entity.prototype.update;
4823
+ const overridesUpdate = node.update !== _chunkAGP4VLF4js.Entity.prototype.update;
4627
4824
  let pending = node.hasPendingAnimations();
4628
4825
  if (pending || overridesUpdate) {
4629
4826
  node.update(dt, time);
@@ -4632,7 +4829,7 @@ var Scene = (_class7 = class _Scene {
4632
4829
  if (pending) walkHadAnimation = true;
4633
4830
  if (!walkHadInteractive && node.interactive) walkHadInteractive = true;
4634
4831
  if (this._devActive && this._devFrameCount % 120 === 0) {
4635
- if (overridesUpdate && node.hasPendingAnimations === _chunkYLH7F4ZVjs.Entity.prototype.hasPendingAnimations) {
4832
+ if (overridesUpdate && node.hasPendingAnimations === _chunkAGP4VLF4js.Entity.prototype.hasPendingAnimations) {
4636
4833
  this._devWarn(
4637
4834
  `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.`
4638
4835
  );
@@ -4813,9 +5010,9 @@ var Scene = (_class7 = class _Scene {
4813
5010
  const flushT0 = this._phaseTiming ? performance.now() : 0;
4814
5011
  renderer.flush();
4815
5012
  if (isMainRenderer) {
4816
- _optionalChain([this, 'access', _133 => _133.pointRenderer, 'optionalAccess', _134 => _134.flush, 'call', _135 => _135()]);
5013
+ _optionalChain([this, 'access', _145 => _145.pointRenderer, 'optionalAccess', _146 => _146.flush, 'call', _147 => _147()]);
4817
5014
  }
4818
- _optionalChain([renderer, 'access', _136 => _136.present, 'optionalCall', _137 => _137()]);
5015
+ _optionalChain([renderer, 'access', _148 => _148.present, 'optionalCall', _149 => _149()]);
4819
5016
  if (this._phaseTiming) this._recordPhase("flush", performance.now() - flushT0);
4820
5017
  if (this._devActive) {
4821
5018
  this._devFrameCount++;
@@ -4826,7 +5023,7 @@ var Scene = (_class7 = class _Scene {
4826
5023
  * Export the current scene state to a lightweight, flat SVG XML string.
4827
5024
  */
4828
5025
  toSVG() {
4829
- const renderer = new (0, _chunkL4SWVP2Hjs.SVGRenderer)(this.width, this.height);
5026
+ const renderer = new (0, _chunkLHONR3GOjs.SVGRenderer)(this.width, this.height);
4830
5027
  this.render(renderer, 0, 0);
4831
5028
  return renderer.toXMLString();
4832
5029
  }
@@ -5092,6 +5289,41 @@ function intersectBounds(a, b) {
5092
5289
  function pointInBounds(b, x, y) {
5093
5290
  return x >= b.x && x <= b.x + b.width && y >= b.y && y <= b.y + b.height;
5094
5291
  }
5292
+ function contentGridLineSignature(grid, line, projected, lineHeight, baseline, font, isFirstLine) {
5293
+ const parts = [
5294
+ // Line box: position, size, and the font that resolves its baseline.
5295
+ `${_nullishCoalesce(_optionalChain([projected, 'optionalAccess', _150 => _150.x]), () => ( 0))}`,
5296
+ `${_nullishCoalesce(_optionalChain([projected, 'optionalAccess', _151 => _151.y]), () => ( ""))}`,
5297
+ `${lineHeight}`,
5298
+ `${baseline}`,
5299
+ font,
5300
+ `${line.width}`,
5301
+ // The trailing hard break belongs to this line and lands in the DOM text.
5302
+ grid.source.slice(line.sourceEnd, line.nextSourceStart),
5303
+ // The basis markers are appended only to line 0, so a line moving to or from
5304
+ // index 0 changes its DOM even when nothing else does.
5305
+ isFirstLine ? "1" : "0"
5306
+ ];
5307
+ if (line.cells.length === 0) {
5308
+ parts.push("empty");
5309
+ } else {
5310
+ for (const cell of line.cells) {
5311
+ parts.push(
5312
+ `${cell.sourceStart}`,
5313
+ `${cell.sourceEnd}`,
5314
+ `${cell.x}`,
5315
+ `${cell.advance}`,
5316
+ `${cell.level}`,
5317
+ cell.sourceCaretOffsets.join("."),
5318
+ // Source text, not `cell.glyph`: the carrier holds the original characters
5319
+ // (the shaped glyph is the canvas's business), so a change in shaping alone
5320
+ // must not invalidate a carrier, and a change in source must.
5321
+ grid.source.slice(cell.sourceStart, cell.sourceEnd)
5322
+ );
5323
+ }
5324
+ }
5325
+ return parts.join("");
5326
+ }
5095
5327
 
5096
5328
  // src/components/TextEntity.ts
5097
5329
 
@@ -5103,20 +5335,20 @@ function defaultMeasurer() {
5103
5335
  if (sharedMeasurer === void 0) sharedMeasurer = _layout.createCanvasMeasurer.call(void 0, "sans-serif");
5104
5336
  return sharedMeasurer;
5105
5337
  }
5106
- var TextEntity = (_class8 = class extends _chunkYLH7F4ZVjs.Entity {
5338
+ var TextEntity = (_class8 = class extends _chunkAGP4VLF4js.Entity {
5107
5339
 
5108
5340
 
5109
5341
 
5110
5342
 
5111
- __init138() {this.nodes = []}
5343
+ __init140() {this.nodes = []}
5112
5344
 
5113
- __init139() {this.fillStyle = "#94a3b8"}
5114
- __init140() {this.strokeStyle = null}
5115
- __init141() {this.hoveredFillStyle = "#ffffff"}
5116
- __init142() {this.lineWidth = 1}
5117
- __init143() {this.isHovered = false}
5345
+ __init141() {this.fillStyle = "#94a3b8"}
5346
+ __init142() {this.strokeStyle = null}
5347
+ __init143() {this.hoveredFillStyle = "#ffffff"}
5348
+ __init144() {this.lineWidth = 1}
5349
+ __init145() {this.isHovered = false}
5118
5350
  constructor(text, atlas, maxWidth, fontSize = 24) {
5119
- super();_class8.prototype.__init138.call(this);_class8.prototype.__init139.call(this);_class8.prototype.__init140.call(this);_class8.prototype.__init141.call(this);_class8.prototype.__init142.call(this);_class8.prototype.__init143.call(this);;
5351
+ super();_class8.prototype.__init140.call(this);_class8.prototype.__init141.call(this);_class8.prototype.__init142.call(this);_class8.prototype.__init143.call(this);_class8.prototype.__init144.call(this);_class8.prototype.__init145.call(this);;
5120
5352
  this.text = text;
5121
5353
  this.atlas = atlas;
5122
5354
  this.fontSize = fontSize;
@@ -5229,17 +5461,17 @@ var TextEntity = (_class8 = class extends _chunkYLH7F4ZVjs.Entity {
5229
5461
  }, _class8);
5230
5462
 
5231
5463
  // src/components/GridTextEntity.ts
5232
- var GridTextEntity = (_class9 = class extends _chunkYLH7F4ZVjs.Entity {
5464
+ var GridTextEntity = (_class9 = class extends _chunkAGP4VLF4js.Entity {
5233
5465
 
5234
- __init144() {this.fillStyle = "#ffffff"}
5235
- __init145() {this.grid = []}
5466
+ __init146() {this.fillStyle = "#ffffff"}
5467
+ __init147() {this.grid = []}
5236
5468
  // Array of rows
5237
- __init146() {this.cols = 0}
5238
- __init147() {this.rows = 0}
5469
+ __init148() {this.cols = 0}
5470
+ __init149() {this.rows = 0}
5239
5471
 
5240
5472
 
5241
5473
  constructor(_atlas, fontSize = 10) {
5242
- super();_class9.prototype.__init144.call(this);_class9.prototype.__init145.call(this);_class9.prototype.__init146.call(this);_class9.prototype.__init147.call(this);;
5474
+ super();_class9.prototype.__init146.call(this);_class9.prototype.__init147.call(this);_class9.prototype.__init148.call(this);_class9.prototype.__init149.call(this);;
5243
5475
  this.fontSize = fontSize;
5244
5476
  this.charWidth = fontSize * 1;
5245
5477
  this.charHeight = fontSize * 1.1;
@@ -5248,7 +5480,7 @@ var GridTextEntity = (_class9 = class extends _chunkYLH7F4ZVjs.Entity {
5248
5480
  updateGrid(ascii) {
5249
5481
  this.grid = ascii;
5250
5482
  this.rows = ascii.length;
5251
- this.cols = _optionalChain([ascii, 'access', _138 => _138[0], 'optionalAccess', _139 => _139.length]) || 0;
5483
+ this.cols = _optionalChain([ascii, 'access', _152 => _152[0], 'optionalAccess', _153 => _153.length]) || 0;
5252
5484
  }
5253
5485
  isPointInside(_globalX, _globalY) {
5254
5486
  return false;
@@ -5323,7 +5555,7 @@ function distSqToSegment(px, py, x1, y1, x2, y2) {
5323
5555
  const ey = py - cy;
5324
5556
  return ex * ex + ey * ey;
5325
5557
  }
5326
- var SplineEntity = (_class10 = class extends _chunkYLH7F4ZVjs.Entity {
5558
+ var SplineEntity = (_class10 = class extends _chunkAGP4VLF4js.Entity {
5327
5559
 
5328
5560
 
5329
5561
 
@@ -5331,23 +5563,23 @@ var SplineEntity = (_class10 = class extends _chunkYLH7F4ZVjs.Entity {
5331
5563
 
5332
5564
 
5333
5565
 
5334
- __init148() {this.offscreen = null}
5335
- __init149() {this.baked = false}
5566
+ __init150() {this.offscreen = null}
5567
+ __init151() {this.baked = false}
5336
5568
  /** Logical (CSS-pixel) size of the baked bitmap — the blit destination size. */
5337
- __init150() {this.bakedWidth = 0}
5338
- __init151() {this.bakedHeight = 0}
5569
+ __init152() {this.bakedWidth = 0}
5570
+ __init153() {this.bakedHeight = 0}
5339
5571
  /** Gradient strokes can't be baked to a solid-color bitmap; they render per-frame. */
5340
5572
 
5341
5573
  /** Lazily-flattened polylines (one Float32Array of [x,y,...] per segment) for hit-testing. */
5342
- __init152() {this.polylines = null}
5574
+ __init154() {this.polylines = null}
5343
5575
  /**
5344
5576
  * When `true`, the renderer draws a rounded-rect outline of the entity's
5345
5577
  * local bounds after painting the curves. Useful for drag feedback and
5346
5578
  * debugging hit areas. Defaults to `false`.
5347
5579
  */
5348
- __init153() {this.showBounds = false}
5580
+ __init155() {this.showBounds = false}
5349
5581
  constructor(doc, opts = {}) {
5350
- super();_class10.prototype.__init148.call(this);_class10.prototype.__init149.call(this);_class10.prototype.__init150.call(this);_class10.prototype.__init151.call(this);_class10.prototype.__init152.call(this);_class10.prototype.__init153.call(this);;
5582
+ super();_class10.prototype.__init150.call(this);_class10.prototype.__init151.call(this);_class10.prototype.__init152.call(this);_class10.prototype.__init153.call(this);_class10.prototype.__init154.call(this);_class10.prototype.__init155.call(this);;
5351
5583
  this.doc = doc;
5352
5584
  this.lineWidth = _nullishCoalesce(opts.lineWidth, () => ( 2));
5353
5585
  this.cache = _nullishCoalesce(opts.cache, () => ( true));
@@ -5358,7 +5590,7 @@ var SplineEntity = (_class10 = class extends _chunkYLH7F4ZVjs.Entity {
5358
5590
  this.width = this.bounds.width;
5359
5591
  this.height = this.bounds.height;
5360
5592
  const isGradient = (c) => c !== null && !Array.isArray(c);
5361
- this.containsGradient = (_nullishCoalesce(_optionalChain([this, 'access', _140 => _140.doc, 'access', _141 => _141.equations, 'optionalAccess', _142 => _142.some, 'call', _143 => _143((eq) => isGradient(eq.color_rgb))]), () => ( false))) || (_nullishCoalesce(_optionalChain([this, 'access', _144 => _144.doc, 'access', _145 => _145.paths, 'optionalAccess', _146 => _146.some, 'call', _147 => _147((p) => isGradient(p.color_rgb))]), () => ( false)));
5593
+ this.containsGradient = (_nullishCoalesce(_optionalChain([this, 'access', _154 => _154.doc, 'access', _155 => _155.equations, 'optionalAccess', _156 => _156.some, 'call', _157 => _157((eq) => isGradient(eq.color_rgb))]), () => ( false))) || (_nullishCoalesce(_optionalChain([this, 'access', _158 => _158.doc, 'access', _159 => _159.paths, 'optionalAccess', _160 => _160.some, 'call', _161 => _161((p) => isGradient(p.color_rgb))]), () => ( false)));
5362
5594
  this.interactive = true;
5363
5595
  }
5364
5596
  computeBounds() {
@@ -5598,7 +5830,7 @@ async function loadSpline(url) {
5598
5830
  }
5599
5831
 
5600
5832
  // src/components/Rect.ts
5601
- var Rect = class extends _chunkYLH7F4ZVjs.Entity {
5833
+ var Rect = class extends _chunkAGP4VLF4js.Entity {
5602
5834
 
5603
5835
 
5604
5836
 
@@ -5647,7 +5879,7 @@ var Rect = class extends _chunkYLH7F4ZVjs.Entity {
5647
5879
  };
5648
5880
 
5649
5881
  // src/components/Circle.ts
5650
- var Circle = class extends _chunkYLH7F4ZVjs.Entity {
5882
+ var Circle = class extends _chunkAGP4VLF4js.Entity {
5651
5883
 
5652
5884
 
5653
5885
 
@@ -5707,7 +5939,7 @@ var Circle = class extends _chunkYLH7F4ZVjs.Entity {
5707
5939
  };
5708
5940
 
5709
5941
  // src/components/Group.ts
5710
- var Group = class extends _chunkYLH7F4ZVjs.Entity {
5942
+ var Group = class extends _chunkAGP4VLF4js.Entity {
5711
5943
  constructor(...children) {
5712
5944
  super();
5713
5945
  if (children.length > 0) this.add(...children);
@@ -5726,21 +5958,21 @@ var _math = require('@vectojs/math'); _createStarExport(_math);
5726
5958
 
5727
5959
 
5728
5960
  // src/tree/DOMPortalEntity.ts
5729
- var DOMPortalEntity = (_class11 = class extends _chunkYLH7F4ZVjs.Entity {
5961
+ var DOMPortalEntity = (_class11 = class extends _chunkAGP4VLF4js.Entity {
5730
5962
 
5731
- __init154() {this.isDOMPortal = true}
5732
- __init155() {this.domListeners = []}
5733
- __init156() {this.resizeObserver = null}
5734
- __init157() {this.domBound = false}
5735
- __init158() {this.cachedWidth = 100}
5736
- __init159() {this.cachedHeight = 100}
5737
- __init160() {this.lastWidth = ""}
5738
- __init161() {this.lastHeight = ""}
5739
- __init162() {this.lastTransform = ""}
5740
- __init163() {this.lastZIndex = ""}
5741
- __init164() {this.lastOpacity = ""}
5963
+ __init156() {this.isDOMPortal = true}
5964
+ __init157() {this.domListeners = []}
5965
+ __init158() {this.resizeObserver = null}
5966
+ __init159() {this.domBound = false}
5967
+ __init160() {this.cachedWidth = 100}
5968
+ __init161() {this.cachedHeight = 100}
5969
+ __init162() {this.lastWidth = ""}
5970
+ __init163() {this.lastHeight = ""}
5971
+ __init164() {this.lastTransform = ""}
5972
+ __init165() {this.lastZIndex = ""}
5973
+ __init166() {this.lastOpacity = ""}
5742
5974
  constructor(domElement, width, height, id) {
5743
- super(id);_class11.prototype.__init154.call(this);_class11.prototype.__init155.call(this);_class11.prototype.__init156.call(this);_class11.prototype.__init157.call(this);_class11.prototype.__init158.call(this);_class11.prototype.__init159.call(this);_class11.prototype.__init160.call(this);_class11.prototype.__init161.call(this);_class11.prototype.__init162.call(this);_class11.prototype.__init163.call(this);_class11.prototype.__init164.call(this);;
5975
+ super(id);_class11.prototype.__init156.call(this);_class11.prototype.__init157.call(this);_class11.prototype.__init158.call(this);_class11.prototype.__init159.call(this);_class11.prototype.__init160.call(this);_class11.prototype.__init161.call(this);_class11.prototype.__init162.call(this);_class11.prototype.__init163.call(this);_class11.prototype.__init164.call(this);_class11.prototype.__init165.call(this);_class11.prototype.__init166.call(this);;
5744
5976
  this.domElement = domElement;
5745
5977
  this.width = _nullishCoalesce(width, () => ( 0));
5746
5978
  this.height = _nullishCoalesce(height, () => ( 0));
@@ -5782,7 +6014,7 @@ var DOMPortalEntity = (_class11 = class extends _chunkYLH7F4ZVjs.Entity {
5782
6014
  ];
5783
6015
  for (const type of events) {
5784
6016
  const handler = (e) => {
5785
- this.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)(type, this, e));
6017
+ this.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)(type, this, e));
5786
6018
  };
5787
6019
  this.domElement.addEventListener(type, handler);
5788
6020
  this.domListeners.push({ type, handler, capture: false });
@@ -5793,7 +6025,7 @@ var DOMPortalEntity = (_class11 = class extends _chunkYLH7F4ZVjs.Entity {
5793
6025
  ];
5794
6026
  for (const { native, vecto } of hoverEvents) {
5795
6027
  const handler = (e) => {
5796
- this.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)(vecto, this, e, false));
6028
+ this.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)(vecto, this, e, false));
5797
6029
  };
5798
6030
  this.domElement.addEventListener(native, handler);
5799
6031
  this.domListeners.push({ type: native, handler, capture: false });
@@ -5801,7 +6033,7 @@ var DOMPortalEntity = (_class11 = class extends _chunkYLH7F4ZVjs.Entity {
5801
6033
  const focusEvents = ["focus", "blur"];
5802
6034
  for (const type of focusEvents) {
5803
6035
  const handler = (e) => {
5804
- this.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)(type, this, e, true));
6036
+ this.dispatchEvent(new (0, _chunkAGP4VLF4js.VectoJSEvent)(type, this, e, true));
5805
6037
  };
5806
6038
  this.domElement.addEventListener(type, handler, true);
5807
6039
  this.domListeners.push({ type, handler, capture: true });
@@ -5852,8 +6084,9 @@ var DOMPortalEntity = (_class11 = class extends _chunkYLH7F4ZVjs.Entity {
5852
6084
  }, _class11);
5853
6085
 
5854
6086
  // src/index.ts
5855
- Scene.registerWebGLPointRendererCreator(_chunkL4SWVP2Hjs.createWebGLPointRenderer);
5856
- Scene.registerWebGPUParticleSystemManager(_chunkL4SWVP2Hjs.WebGPUParticleSystemManager);
6087
+ Scene.registerWebGLPointRendererCreator(_chunkLHONR3GOjs.createWebGLPointRenderer);
6088
+ Scene.registerWebGPUParticleSystemManager(_chunkLHONR3GOjs.WebGPUParticleSystemManager);
6089
+
5857
6090
 
5858
6091
 
5859
6092
 
@@ -5888,4 +6121,4 @@ Scene.registerWebGPUParticleSystemManager(_chunkL4SWVP2Hjs.WebGPUParticleSystemM
5888
6121
 
5889
6122
 
5890
6123
 
5891
- exports.CanvasRenderer = _chunkL4SWVP2Hjs.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Entity = _chunkYLH7F4ZVjs.Entity; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.MSDFTextEntity = _chunkYLH7F4ZVjs.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 = _chunkYLH7F4ZVjs.SVGEntity; exports.SVGRenderer = _chunkL4SWVP2Hjs.SVGRenderer; exports.Scene = Scene; exports.SplineEntity = SplineEntity; exports.TextEntity = TextEntity; exports.TextRasterCache = _chunkL4SWVP2Hjs.TextRasterCache; exports.VectoJSEvent = _chunkYLH7F4ZVjs.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkL4SWVP2Hjs.WebGPUParticleSystemManager; exports.createWebGLPointRenderer = _chunkL4SWVP2Hjs.createWebGLPointRenderer; exports.isSafeUrl = _chunkL4SWVP2Hjs.isSafeUrl; exports.loadSpline = loadSpline; exports.parseColorToRGBA = _chunkL4SWVP2Hjs.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkL4SWVP2Hjs.sanitizeUrl;
6124
+ exports.CanvasRenderer = _chunkLHONR3GOjs.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Entity = _chunkAGP4VLF4js.Entity; exports.GlyphRasterAtlas = _chunkLHONR3GOjs.GlyphRasterAtlas; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.MSDFTextEntity = _chunkAGP4VLF4js.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 = _chunkAGP4VLF4js.SVGEntity; exports.SVGRenderer = _chunkLHONR3GOjs.SVGRenderer; exports.Scene = Scene; exports.SplineEntity = SplineEntity; exports.TextEntity = TextEntity; exports.TextRasterCache = _chunkLHONR3GOjs.TextRasterCache; exports.VectoJSEvent = _chunkAGP4VLF4js.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkLHONR3GOjs.WebGPUParticleSystemManager; exports.createWebGLPointRenderer = _chunkLHONR3GOjs.createWebGLPointRenderer; exports.isSafeUrl = _chunkLHONR3GOjs.isSafeUrl; exports.loadSpline = loadSpline; exports.parseColorToRGBA = _chunkLHONR3GOjs.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkLHONR3GOjs.sanitizeUrl;