@vectojs/core 1.18.0 → 1.20.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
@@ -14,7 +14,7 @@ var _chunkL4SWVP2Hjs = require('./chunk-L4SWVP2H.js');
14
14
 
15
15
 
16
16
 
17
- var _chunkIA3KW4CGjs = require('./chunk-IA3KW4CG.js');
17
+ var _chunkYLH7F4ZVjs = require('./chunk-YLH7F4ZV.js');
18
18
 
19
19
  // src/tree/Scene.ts
20
20
  var _animation = require('@vectojs/animation'); _createStarExport(_animation);
@@ -29,7 +29,7 @@ var PARTICLE_OFFSET_ORIGIN_X = 4;
29
29
  var PARTICLE_OFFSET_ORIGIN_Y = 5;
30
30
  var PARTICLE_OFFSET_SIZE = 6;
31
31
  var PARTICLE_OFFSET_LIFE = 7;
32
- var ComputeParticleEntity = (_class = class extends _chunkIA3KW4CGjs.Entity {
32
+ var ComputeParticleEntity = (_class = class extends _chunkYLH7F4ZVjs.Entity {
33
33
 
34
34
 
35
35
 
@@ -1539,32 +1539,96 @@ var Scene = (_class7 = class _Scene {
1539
1539
  __init29() {this.renderMode = "always"}
1540
1540
  /** Cap on distinct recorded dirty reasons (see `recordDirtyReason`). */
1541
1541
  static __initStatic4() {this.MAX_DIRTY_REASONS = 200}
1542
- __init30() {this._dirtyTracking = false}
1543
- __init31() {this._dirtyReasons = /* @__PURE__ */ new Map()}
1544
- __init32() {this.dirty = true}
1542
+ __init30() {this._phaseTiming = false}
1543
+ __init31() {this._phaseTotals = /* @__PURE__ */ new Map()}
1544
+ /**
1545
+ * Start or stop per-phase render timing.
1546
+ *
1547
+ * Off by default, and the probes compile to a single boolean test when off:
1548
+ * these sit on the frame path, so the disabled cost has to be nothing. Enable,
1549
+ * run the scene, then read {@link renderPhases}.
1550
+ *
1551
+ * Exists because a frame total cannot tell you where the time went. The
1552
+ * markdown streaming benchmark put render at 85-99% of an append's cost, and
1553
+ * there was no way to decompose that number further — which is exactly the
1554
+ * position that led to two wrong optimisation guesses earlier
1555
+ * (`CodeBlock` reuse, hit-grid fusion), both of which measured as no change.
1556
+ */
1557
+ setPhaseTiming(enabled) {
1558
+ this._phaseTiming = enabled;
1559
+ if (!enabled) this.clearRenderPhases();
1560
+ }
1561
+ /** Whether per-phase render timing is being recorded. */
1562
+ get phaseTiming() {
1563
+ return this._phaseTiming;
1564
+ }
1565
+ /**
1566
+ * Accumulate one phase sample.
1567
+ *
1568
+ * Totals rather than a per-frame log: the question is always "which phase owns
1569
+ * the frame", and a log of thousands of samples answers it less directly while
1570
+ * costing far more memory. `maxMs` is kept because a phase that is cheap on
1571
+ * average but spikes is a different problem from one that is uniformly slow.
1572
+ */
1573
+ _recordPhase(phase, ms) {
1574
+ const existing = this._phaseTotals.get(phase);
1575
+ if (existing) {
1576
+ existing.totalMs += ms;
1577
+ existing.calls++;
1578
+ if (ms > existing.maxMs) existing.maxMs = ms;
1579
+ return;
1580
+ }
1581
+ this._phaseTotals.set(phase, { totalMs: ms, calls: 1, maxMs: ms });
1582
+ }
1583
+ /**
1584
+ * Recorded phase timings, most expensive first, with each phase's share of the
1585
+ * measured total.
1586
+ *
1587
+ * `share` is the number that matters: a phase at 4% cannot be worth optimising
1588
+ * however inefficient it looks in isolation.
1589
+ */
1590
+ get renderPhases() {
1591
+ const entries = [...this._phaseTotals.entries()];
1592
+ const denominator = entries.filter(([phase]) => phase !== "render").reduce((sum, [, v]) => sum + v.totalMs, 0);
1593
+ return entries.map(([phase, v]) => ({
1594
+ phase,
1595
+ totalMs: +v.totalMs.toFixed(3),
1596
+ calls: v.calls,
1597
+ avgMs: +(v.totalMs / Math.max(1, v.calls)).toFixed(4),
1598
+ maxMs: +v.maxMs.toFixed(3),
1599
+ share: phase === "render" ? null : +(100 * v.totalMs / Math.max(1e-9, denominator)).toFixed(1)
1600
+ })).sort((a, b) => b.totalMs - a.totalMs);
1601
+ }
1602
+ /** Drop recorded phase timings, keeping timing enabled. */
1603
+ clearRenderPhases() {
1604
+ this._phaseTotals.clear();
1605
+ }
1606
+ __init32() {this._dirtyTracking = false}
1607
+ __init33() {this._dirtyReasons = /* @__PURE__ */ new Map()}
1608
+ __init34() {this.dirty = true}
1545
1609
  /** Whether to throttle rendering to 2 FPS when the scene is static to save power. */
1546
- __init33() {this.autoThrottle = true}
1610
+ __init35() {this.autoThrottle = true}
1547
1611
  // --- Frame telemetry (read via `frameStats`) ---------------------------
1548
1612
  /** Wall-clock ms spent inside the last `render()` call. */
1549
- __init34() {this._lastFrameMs = 0}
1613
+ __init36() {this._lastFrameMs = 0}
1550
1614
  /** Rolling exponential average of rendered-frame intervals, in ms. */
1551
- __init35() {this._avgFrameIntervalMs = 0}
1615
+ __init37() {this._avgFrameIntervalMs = 0}
1552
1616
  /** dt (ms) handed to the last rendered frame. */
1553
- __init36() {this._lastDt = 0}
1617
+ __init38() {this._lastDt = 0}
1554
1618
  /** Count of frames actually rendered since the loop started. */
1555
- __init37() {this._renderedFrames = 0}
1619
+ __init39() {this._renderedFrames = 0}
1556
1620
  /** Count of rAF ticks skipped (idle / capped) since the loop started. */
1557
- __init38() {this._skippedFrames = 0}
1621
+ __init40() {this._skippedFrames = 0}
1558
1622
  /** `time` of the previous *rendered* frame, for interval measurement. */
1559
- __init39() {this._lastRenderTick = 0}
1623
+ __init41() {this._lastRenderTick = 0}
1560
1624
  /**
1561
1625
  * Frame-rate cap (power saving). `0` = uncapped (native refresh). When set,
1562
1626
  * the loop renders at most `maxFPS` times per second; animations still run,
1563
1627
  * just less often. See {@link SceneOptions.maxFPS}.
1564
1628
  */
1565
- __init40() {this.maxFPS = 60}
1629
+ __init42() {this.maxFPS = 60}
1566
1630
  /** Whether the OS prefers-reduced-motion setting auto-caps the loop. */
1567
- __init41() {this.respectReducedMotion = true}
1631
+ __init43() {this.respectReducedMotion = true}
1568
1632
  /**
1569
1633
  * Reading direction for accessibility tab/traversal order (`'ltr'` default,
1570
1634
  * `'rtl'`). Controls the inline sort within a visual row in
@@ -1580,15 +1644,15 @@ var Scene = (_class7 = class _Scene {
1580
1644
  this.a11yNeedsReorder = true;
1581
1645
  }
1582
1646
  }
1583
- __init42() {this._readingDirection = "ltr"}
1647
+ __init44() {this._readingDirection = "ltr"}
1584
1648
  /** Cached media-query list; `.matches` is read live each frame. */
1585
- __init43() {this.reducedMotionQuery = null}
1649
+ __init45() {this.reducedMotionQuery = null}
1586
1650
  /** Cached `(forced-colors: active)` query (Windows High Contrast etc.). A
1587
1651
  * canvas gets NO automatic forced-colors treatment from the browser (it's
1588
1652
  * opaque pixels), so components must read {@link forcedColors} and repaint
1589
1653
  * with system colors themselves; a change listener repaints idle scenes. */
1590
- __init44() {this.forcedColorsQuery = null}
1591
- __init45() {this.forcedColorsChangeHandler = null}
1654
+ __init46() {this.forcedColorsQuery = null}
1655
+ __init47() {this.forcedColorsChangeHandler = null}
1592
1656
  /** True when the OS asks for reduced motion and we respect it. Read by the animation drivers. */
1593
1657
  get prefersReducedMotion() {
1594
1658
  return this.respectReducedMotion && !!_optionalChain([this, 'access', _21 => _21.reducedMotionQuery, 'optionalAccess', _22 => _22.matches]);
@@ -1608,82 +1672,82 @@ var Scene = (_class7 = class _Scene {
1608
1672
  * Throttle interval (ms) for the a11y/automation shadow sync. `0` = every
1609
1673
  * frame. See {@link SceneOptions.a11ySyncInterval}.
1610
1674
  */
1611
- __init46() {this.a11ySyncInterval = 0}
1675
+ __init48() {this.a11ySyncInterval = 0}
1612
1676
  /** Timestamp of the last a11y sync, for throttling. */
1613
- __init47() {this.lastA11ySync = -Infinity}
1677
+ __init49() {this.lastA11ySync = -Infinity}
1614
1678
  /** True if we skipped an a11y sync during animation and need to sync when at rest. */
1615
- __init48() {this.a11yPendingSyncAfterAnimation = false}
1679
+ __init50() {this.a11yPendingSyncAfterAnimation = false}
1616
1680
  // A11y / Automation Layer. `null` in non-DOM (SSR/Node) environments — the
1617
1681
  // whole projection degrades to a no-op so the engine's logic stays usable
1618
1682
  // server-side (e.g. headless layout / vector export) without jsdom.
1619
1683
 
1620
- __init49() {this.a11yElements = /* @__PURE__ */ new Map()}
1684
+ __init51() {this.a11yElements = /* @__PURE__ */ new Map()}
1621
1685
  /** DOM nodes mirroring static text content, keyed by entity id. */
1622
- __init50() {this.contentElements = /* @__PURE__ */ new Map()}
1686
+ __init52() {this.contentElements = /* @__PURE__ */ new Map()}
1623
1687
  /** Pending cold font-calibration frame per projected grid entity. */
1624
- __init51() {this.contentGridCalibrationFrames = /* @__PURE__ */ new Map()}
1688
+ __init53() {this.contentGridCalibrationFrames = /* @__PURE__ */ new Map()}
1625
1689
  /** Detached, untransformed font probes used by the cold calibration pass. */
1626
- __init52() {this.contentGridCalibrationProbes = /* @__PURE__ */ new Map()}
1690
+ __init54() {this.contentGridCalibrationProbes = /* @__PURE__ */ new Map()}
1627
1691
  /** Invalidates grid font calibration after browser font availability changes. */
1628
- __init53() {this.contentFontEpoch = 0}
1692
+ __init55() {this.contentFontEpoch = 0}
1629
1693
  /** Cached Canvas-to-client scale for the current font/viewport epoch. */
1630
- __init54() {this.contentMetricScaleEpoch = -1}
1631
- __init55() {this.contentMetricScaleX = 1}
1632
- __init56() {this.contentProjectionEnabled = true}
1694
+ __init56() {this.contentMetricScaleEpoch = -1}
1695
+ __init57() {this.contentMetricScaleX = 1}
1696
+ __init58() {this.contentProjectionEnabled = true}
1633
1697
  // Virtualization margin (px) for content projection; `undefined` → one
1634
1698
  // viewport height, resolved at sync time. `Infinity` = materialize everything.
1635
- __init57() {this.contentProjectionMargin = void 0}
1699
+ __init59() {this.contentProjectionMargin = void 0}
1636
1700
  /**
1637
1701
  * True while a text-selection drag that started on a projection's blank
1638
1702
  * region (no text node under the press) is being driven manually — the
1639
1703
  * browser has no native anchor for it, so mousemove extends the Selection
1640
1704
  * from the position we resolved ourselves.
1641
1705
  */
1642
- __init58() {this.blankRegionSelectionDrag = false}
1643
- __init59() {this.contentSelectionAnchor = null}
1644
- __init60() {this.contentSelectionEndListener = null}
1706
+ __init60() {this.blankRegionSelectionDrag = false}
1707
+ __init61() {this.contentSelectionAnchor = null}
1708
+ __init62() {this.contentSelectionEndListener = null}
1645
1709
  // Animation/interactive flags collected during the render walk (tree-walk
1646
1710
  // fusion): the loop reads last frame's answers instead of re-walking the
1647
1711
  // tree up to 4× per tick. Start true so the first tick stays conservative.
1648
- __init61() {this.frameHadAnimation = true}
1649
- __init62() {this.frameHadInteractive = true}
1712
+ __init63() {this.frameHadAnimation = true}
1713
+ __init64() {this.frameHadInteractive = true}
1650
1714
 
1651
1715
  /** Active `(resolution: Ndppx)` media query watching for a runtime DPR change
1652
1716
  * (window moved between monitors, browser zoom) so the canvas backing store
1653
1717
  * can be re-scaled — otherwise it stays rasterized at the old DPR and blurs.
1654
1718
  * A resolution media query only fires when leaving its exact value, so the
1655
1719
  * handler re-arms a fresh query for the new DPR each time. */
1656
- __init63() {this.dprMediaQuery = null}
1720
+ __init65() {this.dprMediaQuery = null}
1657
1721
  /** For embedded (`disableWindowResize`) scenes: observes the canvas element so
1658
1722
  * a CSS/layout-driven size change re-runs `resize()`. A window `resize`
1659
1723
  * listener never fires for these (the window isn't what changed), so without
1660
1724
  * this an embedded canvas stayed at its initial size forever. */
1661
- __init64() {this.canvasResizeObserver = null}
1662
- __init65() {this.dprChangeHandler = null}
1663
- __init66() {this.focusedA11yElement = null}
1725
+ __init66() {this.canvasResizeObserver = null}
1726
+ __init67() {this.dprChangeHandler = null}
1727
+ __init68() {this.focusedA11yElement = null}
1664
1728
  /** Last geometry `syncOverlayGeometry` wrote, so an unchanged frame can skip the
1665
1729
  * style writes entirely. Reset to `null` to force the next sync (a new overlay
1666
1730
  * layer was created and has never been positioned). */
1667
- __init67() {this._overlayGeometry = null}
1731
+ __init69() {this._overlayGeometry = null}
1668
1732
  /** Shadow elements the pointer is currently inside. Lets a removal that happens
1669
1733
  * mid-hover synthesize the `pointerleave` the browser never sends for a
1670
1734
  * detached element, so the entity doesn't keep its hover state. */
1671
- __init68() {this.hoveredA11yElements = /* @__PURE__ */ new WeakSet()}
1735
+ __init70() {this.hoveredA11yElements = /* @__PURE__ */ new WeakSet()}
1672
1736
  /** Persistent tabindex=-1 element in a11yRoot. When the focused a11y mirror is
1673
1737
  * pruned (virtualization/streaming/removal) while it holds focus, we move
1674
1738
  * focus here instead of letting the browser drop it to <body> — keeping the
1675
1739
  * screen-reader virtual cursor inside the scene's a11y region. */
1676
- __init69() {this.focusSentinel = null}
1677
- __init70() {this.caretBlinkTimer = null}
1678
- __init71() {this.a11yNeedsReorder = true}
1679
- __init72() {this.portalRoot = null}
1680
- __init73() {this.fullViewportElements = []}
1681
- __init74() {this.normalElements = []}
1682
- __init75() {this.activeIds = /* @__PURE__ */ new Set()}
1683
- __init76() {this.activePortalsThisFrame = /* @__PURE__ */ new Set()}
1684
- __init77() {this.activePortalsPrevFrame = /* @__PURE__ */ new Set()}
1685
- __init78() {this.portalEntities = /* @__PURE__ */ new Map()}
1686
- __init79() {this.renderOrderCounter = 0}
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}
1687
1751
  /**
1688
1752
  * Monotonic render-frame counter, bumped once per authoritative `render()`
1689
1753
  * pass. Entities stamp their per-frame world-matrix cache with this value and
@@ -1692,7 +1756,7 @@ var Scene = (_class7 = class _Scene {
1692
1756
  * back to the ancestor walk. Public for the same reason `Entity._getTrig`/
1693
1757
  * `_setWorldCache` are: it is a cross-class render-internal contract.
1694
1758
  */
1695
- __init80() {this.currentFrame = 0}
1759
+ __init82() {this.currentFrame = 0}
1696
1760
  // ── WASM transform backend (invisible accelerator) ──────────────────────────
1697
1761
  // When `_transformBackend === 'wasm'`, the main render walk sources each
1698
1762
  // entity's world matrix from an SoA store composed by `_wasm` (see
@@ -1700,24 +1764,24 @@ var Scene = (_class7 = class _Scene {
1700
1764
  // fallback and the default: a null backend, a non-main renderer, or any entity
1701
1765
  // absent from the store all fall back to the JS composition, so WASM can only
1702
1766
  // ever change *how fast* a world matrix is produced, never *what* it is.
1703
- __init81() {this._wasm = null}
1704
- __init82() {this._transformBackend = "js"}
1767
+ __init83() {this._wasm = null}
1768
+ __init84() {this._transformBackend = "js"}
1705
1769
  // Resident store state (Stage 3). The store layout — slot assignment + sibling
1706
1770
  // runs — depends only on tree TOPOLOGY, so it is rebuilt only when the
1707
1771
  // structure changes (add/remove/reparent bump `_structureVersion`). Between
1708
1772
  // rebuilds the per-frame cost is: gather each entity's transform into the
1709
1773
  // resident wasm input view + run the kernel — no reallocation, no readback.
1710
- __init83() {this._treeStore = null}
1711
- __init84() {this._slotEntity = []}
1774
+ __init85() {this._treeStore = null}
1775
+ __init86() {this._slotEntity = []}
1712
1776
  // store slot -> entity (also validates slots)
1713
- __init85() {this._wasmInputs = null}
1714
- __init86() {this._wasmWorld = null}
1715
- __init87() {this._structureVersion = 0}
1716
- __init88() {this._storeStructureVersion = -1}
1777
+ __init87() {this._wasmInputs = null}
1778
+ __init88() {this._wasmWorld = null}
1779
+ __init89() {this._structureVersion = 0}
1780
+ __init90() {this._storeStructureVersion = -1}
1717
1781
  // Cached list of ComputeParticleEntity instances in the tree, keyed by the
1718
1782
  // structure version it was gathered at. Rebuilt only on a topology change.
1719
- __init89() {this._computeEntities = []}
1720
- __init90() {this._computeEntitiesVersion = -1}
1783
+ __init91() {this._computeEntities = []}
1784
+ __init92() {this._computeEntitiesVersion = -1}
1721
1785
  /** Invalidate the resident WASM store layout; the next wasm-mode frame rebuilds
1722
1786
  * it. Called by `Entity.add`/`remove` (topology changes only). */
1723
1787
  markStructureChanged() {
@@ -1799,7 +1863,7 @@ var Scene = (_class7 = class _Scene {
1799
1863
  * cached globally; the instance is per-Scene, which is the isolation that
1800
1864
  * actually matters.
1801
1865
  */
1802
- __init91() {this._wasmRuntime = null}
1866
+ __init93() {this._wasmRuntime = null}
1803
1867
  /**
1804
1868
  * Load (or reuse) this Scene's shared WASM runtime.
1805
1869
  *
@@ -1827,30 +1891,30 @@ var Scene = (_class7 = class _Scene {
1827
1891
  get wasmRuntime() {
1828
1892
  return this._wasmRuntime;
1829
1893
  }
1830
- __init92() {this._hitWasm = null}
1894
+ __init94() {this._hitWasm = null}
1831
1895
  // Cache key: which frame + structure version the grid was last (successfully,
1832
1896
  // non-overflowing) built for. findEntityAt is called ad-hoc (pointer
1833
1897
  // hover/click), not every frame, so the grid is refreshed lazily on demand
1834
1898
  // rather than proactively every render() — unlike the transform store, which
1835
1899
  // every frame's draw depends on.
1836
- __init93() {this._hitGridFrame = -1}
1837
- __init94() {this._hitGridOk = false}
1838
- __init95() {this._hitSlotEntity = []}
1839
- __init96() {this._hitBoundless = []}
1900
+ __init95() {this._hitGridFrame = -1}
1901
+ __init96() {this._hitGridOk = false}
1902
+ __init97() {this._hitSlotEntity = []}
1903
+ __init98() {this._hitBoundless = []}
1840
1904
  /** Reused buffer for the fused gather, so a pointer query allocates nothing. */
1841
- __init97() {this._hitGatherBuffer = null}
1905
+ __init99() {this._hitGatherBuffer = null}
1842
1906
  /**
1843
1907
  * Whether the last grid build sourced its AABBs from the WASM transform store
1844
1908
  * rather than recomputing them in JS. Diagnostic only — both paths must
1845
1909
  * produce the same entity for a given point.
1846
1910
  */
1847
- __init98() {this._hitFusedGather = false}
1911
+ __init100() {this._hitFusedGather = false}
1848
1912
  /**
1849
1913
  * Whether `compute_aabbs` has run against the current frame's world matrices.
1850
1914
  * The AABB pass is only meaningful after a `compose_*`, so the fused gather
1851
1915
  * must not read the views before then.
1852
1916
  */
1853
- __init99() {this._wasmAabbsFresh = false}
1917
+ __init101() {this._wasmAabbsFresh = false}
1854
1918
  /** Did the last hit-grid build use the fused (WASM-store) gather? */
1855
1919
  get hitGatherPath() {
1856
1920
  return this._hitFusedGather ? "fused" : "js";
@@ -1964,25 +2028,25 @@ var Scene = (_class7 = class _Scene {
1964
2028
  // EasingFn (which cannot cross into WASM) all fall through to it — WASM can
1965
2029
  // only ever change *how* a driver is advanced, never *what* value it lands
1966
2030
  // on.
1967
- __init100() {this._animWasm = null}
2031
+ __init102() {this._animWasm = null}
1968
2032
  // Entities with at least one active driver, added by Entity._spawnDriver.
1969
2033
  // Self-pruning: _tickBatchedDrivers drops an entry the first time it visits
1970
2034
  // an entity whose drivers have since all completed or been removed. This is
1971
2035
  // what lets the batch pass find its candidates in O(active drivers), not
1972
2036
  // O(tree size) — the exact mistake G3's first integrated benchmark made.
1973
- __init101() {this._activeDriverEntities = /* @__PURE__ */ new Set()}
2037
+ __init103() {this._activeDriverEntities = /* @__PURE__ */ new Set()}
1974
2038
  // Reused across frames instead of allocating a fresh array + N {entity,prop,
1975
2039
  // driver} objects every call — the integrated benchmark
1976
2040
  // (benchmarks/anim-wasm-scene) found that allocation churn was the
1977
2041
  // dominant integrated cost, not the wasm kernel itself. Parallel arrays,
1978
2042
  // truncated to the live count after each use so a stale tail slot never
1979
2043
  // pins a no-longer-active entity/driver in memory.
1980
- __init102() {this._springEntities = []}
1981
- __init103() {this._springProps = []}
1982
- __init104() {this._springDrivers = []}
1983
- __init105() {this._tweenEntities = []}
1984
- __init106() {this._tweenProps = []}
1985
- __init107() {this._tweenDrivers = []}
2044
+ __init104() {this._springEntities = []}
2045
+ __init105() {this._springProps = []}
2046
+ __init106() {this._springDrivers = []}
2047
+ __init107() {this._tweenEntities = []}
2048
+ __init108() {this._tweenProps = []}
2049
+ __init109() {this._tweenDrivers = []}
1986
2050
  /**
1987
2051
  * Minimum number of batchable (spring, or named-easing tween) active drivers
1988
2052
  * before a frame engages the WASM batch path at all; below it, every driver
@@ -2054,7 +2118,7 @@ var Scene = (_class7 = class _Scene {
2054
2118
  * Setting {@link animDriverGateCount} overwrites all three, so existing code
2055
2119
  * that tuned the single knob keeps working unchanged.
2056
2120
  */
2057
- __init108() {this._animBatchedLastFrame = false}
2121
+ __init110() {this._animBatchedLastFrame = false}
2058
2122
  /**
2059
2123
  * Whether the WASM batch path actually ran on the most recent frame.
2060
2124
  *
@@ -2066,7 +2130,7 @@ var Scene = (_class7 = class _Scene {
2066
2130
  get animBatchedLastFrame() {
2067
2131
  return this._animBatchedLastFrame;
2068
2132
  }
2069
- __init109() {this.animGate = {
2133
+ __init111() {this.animGate = {
2070
2134
  spring: 128,
2071
2135
  tween: 256,
2072
2136
  mixed: 128
@@ -2104,7 +2168,7 @@ var Scene = (_class7 = class _Scene {
2104
2168
  // (benchmarks/particle-wasm). f32 (matches the WGSL shader), bit-identical to
2105
2169
  // a JS f32 reference oracle; updateCPU (f64) stays the permanent fallback when
2106
2170
  // no backend is installed or a scene runs on WebGPU.
2107
- __init110() {this._particleWasm = null}
2171
+ __init112() {this._particleWasm = null}
2108
2172
  /** Which backend runs the CPU particle simulation. Reflects only whether a
2109
2173
  * backend is installed (the WebGPU compute path, when active, is used first
2110
2174
  * regardless). */
@@ -2354,46 +2418,46 @@ var Scene = (_class7 = class _Scene {
2354
2418
  * sync, so retaining the order prevents a newly opened overlay from spending
2355
2419
  * its first frame below previously projected controls.
2356
2420
  */
2357
- __init111() {this.a11yRenderOrders = /* @__PURE__ */ new Map()}
2421
+ __init113() {this.a11yRenderOrders = /* @__PURE__ */ new Map()}
2358
2422
  // Optional WebGL point-cloud layer (see SceneOptions.pointBackend).
2359
- __init112() {this.pointRenderer = null}
2360
- __init113() {this.glCanvas = null}
2361
- __init114() {this.glContextLostHandler = null}
2362
- __init115() {this.glContextRestoredHandler = null}
2423
+ __init114() {this.pointRenderer = null}
2424
+ __init115() {this.glCanvas = null}
2425
+ __init116() {this.glContextLostHandler = null}
2426
+ __init117() {this.glContextRestoredHandler = null}
2363
2427
 
2364
2428
 
2365
2429
 
2366
- __init116() {this.disableWindowResize = false}
2430
+ __init118() {this.disableWindowResize = false}
2367
2431
  /** See {@link SceneOptions.maxDPR}. `undefined` = uncapped (real DPR). */
2368
2432
 
2369
2433
  // WebGPU properties
2370
- __init117() {this.destroyed = false}
2371
- __init118() {this.device = null}
2372
- __init119() {this.deviceLost = false}
2373
- __init120() {this.particleBackend = "auto"}
2374
- __init121() {this._webgpuDisabled = false}
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}
2375
2439
  get webgpuDisabled() {
2376
2440
  return this._webgpuDisabled || this.particleBackend === "cpu";
2377
2441
  }
2378
2442
  set webgpuDisabled(value) {
2379
2443
  this._webgpuDisabled = value;
2380
2444
  }
2381
- __init122() {this.recoveryTimerId = null}
2382
- __init123() {this.manager = null}
2383
- __init124() {this.initializingWebGPU = false}
2384
- __init125() {this.gpuCanvas = null}
2385
- __init126() {this.gpuContext = null}
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}
2386
2450
  /** True while the GPU canvas holds a presented particle frame (needs clearing when they leave). */
2387
- __init127() {this.gpuHasContent = false}
2388
- __init128() {this.mouseX = -9999}
2389
- __init129() {this.mouseY = -9999}
2390
- __init130() {this.pointerMoveListener = null}
2391
- __init131() {this.pointerLeaveListener = null}
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}
2392
2456
  /** Element the pointer listeners are bound to (parent container if present,
2393
2457
  * else the canvas). Stored so `destroy()` detaches from the same element. */
2394
- __init132() {this.pointerEventTarget = null}
2395
- __init133() {this.hasWarnedZeroSize = false}
2396
- __init134() {this.fontLoadHandler = null}
2458
+ __init134() {this.pointerEventTarget = null}
2459
+ __init135() {this.hasWarnedZeroSize = false}
2460
+ __init136() {this.fontLoadHandler = null}
2397
2461
  // ── Dev-mode warning infrastructure ──────────────────────────────
2398
2462
  //
2399
2463
  // Enable with `Scene.devMode = true` or by setting `globalThis.__DEV__`.
@@ -2411,7 +2475,7 @@ var Scene = (_class7 = class _Scene {
2411
2475
  return false;
2412
2476
  }
2413
2477
 
2414
- __init135() {this._devFrameCount = 0}
2478
+ __init137() {this._devFrameCount = 0}
2415
2479
  _devWarn(message) {
2416
2480
  if (!this._devActive) return;
2417
2481
  console.warn(`[vectojs/dev] ${message}`);
@@ -2455,7 +2519,7 @@ var Scene = (_class7 = class _Scene {
2455
2519
  };
2456
2520
  walkProjections(this.root);
2457
2521
  }
2458
- 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);
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);
2459
2523
  this.canvas = canvas;
2460
2524
  this.debugA11y = _nullishCoalesce(options.debugA11y, () => ( false));
2461
2525
  this.disableWindowResize = _nullishCoalesce(options.disableWindowResize, () => ( false));
@@ -2486,7 +2550,7 @@ var Scene = (_class7 = class _Scene {
2486
2550
  this.forcedColorsChangeHandler = () => this.markDirty();
2487
2551
  _optionalChain([this, 'access', _45 => _45.forcedColorsQuery, 'access', _46 => _46.addEventListener, 'optionalCall', _47 => _47("change", this.forcedColorsChangeHandler)]);
2488
2552
  }
2489
- this.root = new class RootEntity extends _chunkIA3KW4CGjs.Entity {
2553
+ this.root = new class RootEntity extends _chunkYLH7F4ZVjs.Entity {
2490
2554
  isPointInside() {
2491
2555
  return false;
2492
2556
  }
@@ -2495,7 +2559,7 @@ var Scene = (_class7 = class _Scene {
2495
2559
  }
2496
2560
  }("root");
2497
2561
  this.root._scene = this;
2498
- this.overlayRoot = new class OverlayRoot extends _chunkIA3KW4CGjs.Entity {
2562
+ this.overlayRoot = new class OverlayRoot extends _chunkYLH7F4ZVjs.Entity {
2499
2563
  isPointInside() {
2500
2564
  return false;
2501
2565
  }
@@ -2835,6 +2899,20 @@ var Scene = (_class7 = class _Scene {
2835
2899
  delete el.dataset.vectoGridCalibrationMs;
2836
2900
  this.releaseContentSelectionForRebuild(el);
2837
2901
  }
2902
+ /**
2903
+ * Drop any projected elements under `node` without touching the entity tree.
2904
+ *
2905
+ * Used when the walk reaches an invisible subtree: the entities stay put (a
2906
+ * later `show()` re-projects them), but nothing under here may remain
2907
+ * focusable or announced while hidden.
2908
+ */
2909
+ pruneA11ySubtree(node) {
2910
+ if (this.a11yElements.has(node.id) || this.contentElements.has(node.id)) {
2911
+ this.removeA11yRecursively(node);
2912
+ return;
2913
+ }
2914
+ for (const child of node.children) this.pruneA11ySubtree(child);
2915
+ }
2838
2916
  removeA11yRecursively(node) {
2839
2917
  if (node.isDOMPortal) {
2840
2918
  node.releaseDOMBindings();
@@ -2861,7 +2939,7 @@ var Scene = (_class7 = class _Scene {
2861
2939
  }
2862
2940
  if (this.hoveredA11yElements.has(el)) {
2863
2941
  this.hoveredA11yElements.delete(el);
2864
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("pointerleave", node, void 0, false));
2942
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointerleave", node, void 0, false));
2865
2943
  }
2866
2944
  this.preserveFocusOnRemoval(el);
2867
2945
  el.remove();
@@ -3152,7 +3230,9 @@ var Scene = (_class7 = class _Scene {
3152
3230
  step(dt) {
3153
3231
  const time = this.lastTime + dt;
3154
3232
  this.lastTime = time;
3233
+ const t0 = this._phaseTiming ? performance.now() : 0;
3155
3234
  this.render(this.renderer, dt, time);
3235
+ if (this._phaseTiming) this._recordPhase("render", performance.now() - t0);
3156
3236
  this.dirty = false;
3157
3237
  }
3158
3238
  /**
@@ -3287,6 +3367,10 @@ var Scene = (_class7 = class _Scene {
3287
3367
  if (node.isDOMPortal) {
3288
3368
  return;
3289
3369
  }
3370
+ if (node.a11yHidden) {
3371
+ this.pruneA11ySubtree(node);
3372
+ return;
3373
+ }
3290
3374
  if (this.shouldProjectA11y(node)) {
3291
3375
  let el = this.a11yElements.get(node.id);
3292
3376
  const attrs = node.getA11yAttributes();
@@ -3328,20 +3412,20 @@ var Scene = (_class7 = class _Scene {
3328
3412
  el.style.background = "transparent";
3329
3413
  }
3330
3414
  el.addEventListener("click", (e) => {
3331
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("click", node, e));
3415
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("click", node, e));
3332
3416
  });
3333
3417
  el.addEventListener("dblclick", (e) => {
3334
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("dblclick", node, e));
3418
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("dblclick", node, e));
3335
3419
  });
3336
3420
  el.addEventListener("mouseenter", (e) => {
3337
3421
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.2)";
3338
3422
  this.hoveredA11yElements.add(el);
3339
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("hover", node, e, false));
3423
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("hover", node, e, false));
3340
3424
  });
3341
3425
  el.addEventListener("mouseleave", (e) => {
3342
3426
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.05)";
3343
3427
  this.hoveredA11yElements.delete(el);
3344
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("pointerleave", node, e, false));
3428
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointerleave", node, e, false));
3345
3429
  });
3346
3430
  const capEl = el;
3347
3431
  const releasePointer = (event) => {
@@ -3357,32 +3441,32 @@ var Scene = (_class7 = class _Scene {
3357
3441
  };
3358
3442
  el.addEventListener("pointerdown", (e) => {
3359
3443
  if (typeof capEl.setPointerCapture === "function") capEl.setPointerCapture(e.pointerId);
3360
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("pointerdown", node, e));
3444
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointerdown", node, e));
3361
3445
  });
3362
3446
  el.addEventListener("pointerup", (e) => {
3363
3447
  releasePointer(e);
3364
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("pointerup", node, e));
3448
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointerup", node, e));
3365
3449
  });
3366
3450
  el.addEventListener("pointercancel", (e) => {
3367
3451
  releasePointer(e);
3368
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("pointercancel", node, e));
3452
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointercancel", node, e));
3369
3453
  });
3370
3454
  el.addEventListener(
3371
3455
  "pointermove",
3372
- (e) => node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("pointermove", node, e))
3456
+ (e) => node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("pointermove", node, e))
3373
3457
  );
3374
3458
  el.addEventListener(
3375
3459
  "wheel",
3376
3460
  (e) => {
3377
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("wheel", node, e));
3461
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("wheel", node, e));
3378
3462
  },
3379
3463
  { passive: false }
3380
3464
  );
3381
3465
  el.addEventListener("keydown", (e) => {
3382
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("keydown", node, e));
3466
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("keydown", node, e));
3383
3467
  });
3384
3468
  el.addEventListener("keyup", (e) => {
3385
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("keyup", node, e));
3469
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("keyup", node, e));
3386
3470
  });
3387
3471
  if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
3388
3472
  const input = el;
@@ -3448,7 +3532,7 @@ var Scene = (_class7 = class _Scene {
3448
3532
  el.addEventListener("keydown", (e) => {
3449
3533
  if (e.key === "Enter" || e.key === " ") {
3450
3534
  e.preventDefault();
3451
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("click", node, e));
3535
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("click", node, e));
3452
3536
  }
3453
3537
  });
3454
3538
  }
@@ -3560,6 +3644,28 @@ var Scene = (_class7 = class _Scene {
3560
3644
  "aria-level",
3561
3645
  attrs.level === void 0 ? void 0 : String(attrs.level)
3562
3646
  );
3647
+ this.syncOptionalAttribute(
3648
+ el,
3649
+ "aria-posinset",
3650
+ attrs.posInSet === void 0 ? void 0 : String(attrs.posInSet)
3651
+ );
3652
+ this.syncOptionalAttribute(
3653
+ el,
3654
+ "aria-setsize",
3655
+ attrs.setSize === void 0 ? void 0 : String(attrs.setSize)
3656
+ );
3657
+ this.syncOptionalAttribute(
3658
+ el,
3659
+ "aria-rowcount",
3660
+ attrs.rowCount === void 0 ? void 0 : String(attrs.rowCount)
3661
+ );
3662
+ this.syncOptionalAttribute(
3663
+ el,
3664
+ "aria-rowindex",
3665
+ attrs.rowIndex === void 0 ? void 0 : String(attrs.rowIndex)
3666
+ );
3667
+ this.syncOptionalAttribute(el, "aria-valuetext", attrs.valueText);
3668
+ this.syncOptionalAttribute(el, "aria-orientation", attrs.orientation);
3563
3669
  if (attrs.value !== void 0) {
3564
3670
  if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
3565
3671
  if (el.value !== attrs.value) {
@@ -3708,7 +3814,7 @@ var Scene = (_class7 = class _Scene {
3708
3814
  el.addEventListener(
3709
3815
  "wheel",
3710
3816
  (e2) => {
3711
- node.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)("wheel", node, e2));
3817
+ node.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)("wheel", node, e2));
3712
3818
  },
3713
3819
  { passive: false }
3714
3820
  );
@@ -4351,7 +4457,9 @@ var Scene = (_class7 = class _Scene {
4351
4457
  }
4352
4458
  this._lastRenderTick = time;
4353
4459
  this._lastDt = dt;
4460
+ const phaseClock = this._phaseTiming ? performance.now() : 0;
4354
4461
  this.render(this.renderer, dt, time);
4462
+ if (this._phaseTiming) this._recordPhase("render", performance.now() - phaseClock);
4355
4463
  this._lastFrameMs = (typeof performance !== "undefined" ? performance.now() : time) - now;
4356
4464
  this._renderedFrames++;
4357
4465
  const hasActiveAnimation = this.frameHadAnimation;
@@ -4361,9 +4469,13 @@ var Scene = (_class7 = class _Scene {
4361
4469
  if ((hasInteractive || this.a11yElements.size > 0 || wantsContentSync) && (shouldSyncInterval || this.a11yPendingSyncAfterAnimation)) {
4362
4470
  this.lastA11ySync = time;
4363
4471
  if (hasInteractive || wantsContentSync) {
4472
+ const t0 = this._phaseTiming ? performance.now() : 0;
4364
4473
  this.syncA11y(this.root);
4474
+ if (this._phaseTiming) this._recordPhase("a11ySync", performance.now() - t0);
4365
4475
  }
4476
+ const t1 = this._phaseTiming ? performance.now() : 0;
4366
4477
  this.enforceA11yDomOrder();
4478
+ if (this._phaseTiming) this._recordPhase("a11yOrder", performance.now() - t1);
4367
4479
  this.a11yPendingSyncAfterAnimation = hasActiveAnimation;
4368
4480
  } else if (hasActiveAnimation) {
4369
4481
  this.a11yPendingSyncAfterAnimation = true;
@@ -4511,7 +4623,7 @@ var Scene = (_class7 = class _Scene {
4511
4623
  let walkHadAnimation = false;
4512
4624
  let walkHadInteractive = false;
4513
4625
  const runUpdate = (node) => {
4514
- const overridesUpdate = node.update !== _chunkIA3KW4CGjs.Entity.prototype.update;
4626
+ const overridesUpdate = node.update !== _chunkYLH7F4ZVjs.Entity.prototype.update;
4515
4627
  let pending = node.hasPendingAnimations();
4516
4628
  if (pending || overridesUpdate) {
4517
4629
  node.update(dt, time);
@@ -4520,7 +4632,7 @@ var Scene = (_class7 = class _Scene {
4520
4632
  if (pending) walkHadAnimation = true;
4521
4633
  if (!walkHadInteractive && node.interactive) walkHadInteractive = true;
4522
4634
  if (this._devActive && this._devFrameCount % 120 === 0) {
4523
- if (overridesUpdate && node.hasPendingAnimations === _chunkIA3KW4CGjs.Entity.prototype.hasPendingAnimations) {
4635
+ if (overridesUpdate && node.hasPendingAnimations === _chunkYLH7F4ZVjs.Entity.prototype.hasPendingAnimations) {
4524
4636
  this._devWarn(
4525
4637
  `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.`
4526
4638
  );
@@ -4537,7 +4649,9 @@ var Scene = (_class7 = class _Scene {
4537
4649
  updateWalk(this.root);
4538
4650
  for (const overlay of this.overlayRoot.children) updateWalk(overlay);
4539
4651
  }
4652
+ const wasmT0 = this._phaseTiming ? performance.now() : 0;
4540
4653
  const wasmWorld = wasmMain ? this._syncWasmStore() : null;
4654
+ if (this._phaseTiming) this._recordPhase("transform", performance.now() - wasmT0);
4541
4655
  const wasmSlotEntity = this._slotEntity;
4542
4656
  const renderNode = (node, pa, pb, pc, pd, pe, pf, parentOpacity) => {
4543
4657
  if (isMainRenderer && !wasmMain) {
@@ -4667,7 +4781,13 @@ var Scene = (_class7 = class _Scene {
4667
4781
  );
4668
4782
  }
4669
4783
  } else {
4670
- node.render(renderer);
4784
+ if (this._phaseTiming) {
4785
+ const t0 = performance.now();
4786
+ node.render(renderer);
4787
+ this._recordPhase("entityPaint", performance.now() - t0);
4788
+ } else {
4789
+ node.render(renderer);
4790
+ }
4671
4791
  }
4672
4792
  }
4673
4793
  if (node.clipChildren) {
@@ -4679,20 +4799,24 @@ var Scene = (_class7 = class _Scene {
4679
4799
  renderer.flush();
4680
4800
  renderer.restore();
4681
4801
  };
4802
+ const drawT0 = this._phaseTiming ? performance.now() : 0;
4682
4803
  renderNode(this.root, 1, 0, 0, 1, 0, 0, 1);
4683
4804
  for (const overlay of this.overlayRoot.children) {
4684
4805
  renderNode(overlay, 1, 0, 0, 1, 0, 0, 1);
4685
4806
  }
4807
+ if (this._phaseTiming) this._recordPhase("drawWalk", performance.now() - drawT0);
4686
4808
  if (isMainRenderer) {
4687
4809
  this.frameHadAnimation = walkHadAnimation;
4688
4810
  this.frameHadInteractive = walkHadInteractive;
4689
4811
  this.reconcilePortals();
4690
4812
  }
4813
+ const flushT0 = this._phaseTiming ? performance.now() : 0;
4691
4814
  renderer.flush();
4692
4815
  if (isMainRenderer) {
4693
4816
  _optionalChain([this, 'access', _133 => _133.pointRenderer, 'optionalAccess', _134 => _134.flush, 'call', _135 => _135()]);
4694
4817
  }
4695
4818
  _optionalChain([renderer, 'access', _136 => _136.present, 'optionalCall', _137 => _137()]);
4819
+ if (this._phaseTiming) this._recordPhase("flush", performance.now() - flushT0);
4696
4820
  if (this._devActive) {
4697
4821
  this._devFrameCount++;
4698
4822
  this._devRunChecks();
@@ -4979,20 +5103,20 @@ function defaultMeasurer() {
4979
5103
  if (sharedMeasurer === void 0) sharedMeasurer = _layout.createCanvasMeasurer.call(void 0, "sans-serif");
4980
5104
  return sharedMeasurer;
4981
5105
  }
4982
- var TextEntity = (_class8 = class extends _chunkIA3KW4CGjs.Entity {
5106
+ var TextEntity = (_class8 = class extends _chunkYLH7F4ZVjs.Entity {
4983
5107
 
4984
5108
 
4985
5109
 
4986
5110
 
4987
- __init136() {this.nodes = []}
5111
+ __init138() {this.nodes = []}
4988
5112
 
4989
- __init137() {this.fillStyle = "#94a3b8"}
4990
- __init138() {this.strokeStyle = null}
4991
- __init139() {this.hoveredFillStyle = "#ffffff"}
4992
- __init140() {this.lineWidth = 1}
4993
- __init141() {this.isHovered = false}
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}
4994
5118
  constructor(text, atlas, maxWidth, fontSize = 24) {
4995
- super();_class8.prototype.__init136.call(this);_class8.prototype.__init137.call(this);_class8.prototype.__init138.call(this);_class8.prototype.__init139.call(this);_class8.prototype.__init140.call(this);_class8.prototype.__init141.call(this);;
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);;
4996
5120
  this.text = text;
4997
5121
  this.atlas = atlas;
4998
5122
  this.fontSize = fontSize;
@@ -5105,17 +5229,17 @@ var TextEntity = (_class8 = class extends _chunkIA3KW4CGjs.Entity {
5105
5229
  }, _class8);
5106
5230
 
5107
5231
  // src/components/GridTextEntity.ts
5108
- var GridTextEntity = (_class9 = class extends _chunkIA3KW4CGjs.Entity {
5232
+ var GridTextEntity = (_class9 = class extends _chunkYLH7F4ZVjs.Entity {
5109
5233
 
5110
- __init142() {this.fillStyle = "#ffffff"}
5111
- __init143() {this.grid = []}
5234
+ __init144() {this.fillStyle = "#ffffff"}
5235
+ __init145() {this.grid = []}
5112
5236
  // Array of rows
5113
- __init144() {this.cols = 0}
5114
- __init145() {this.rows = 0}
5237
+ __init146() {this.cols = 0}
5238
+ __init147() {this.rows = 0}
5115
5239
 
5116
5240
 
5117
5241
  constructor(_atlas, fontSize = 10) {
5118
- super();_class9.prototype.__init142.call(this);_class9.prototype.__init143.call(this);_class9.prototype.__init144.call(this);_class9.prototype.__init145.call(this);;
5242
+ super();_class9.prototype.__init144.call(this);_class9.prototype.__init145.call(this);_class9.prototype.__init146.call(this);_class9.prototype.__init147.call(this);;
5119
5243
  this.fontSize = fontSize;
5120
5244
  this.charWidth = fontSize * 1;
5121
5245
  this.charHeight = fontSize * 1.1;
@@ -5199,7 +5323,7 @@ function distSqToSegment(px, py, x1, y1, x2, y2) {
5199
5323
  const ey = py - cy;
5200
5324
  return ex * ex + ey * ey;
5201
5325
  }
5202
- var SplineEntity = (_class10 = class extends _chunkIA3KW4CGjs.Entity {
5326
+ var SplineEntity = (_class10 = class extends _chunkYLH7F4ZVjs.Entity {
5203
5327
 
5204
5328
 
5205
5329
 
@@ -5207,23 +5331,23 @@ var SplineEntity = (_class10 = class extends _chunkIA3KW4CGjs.Entity {
5207
5331
 
5208
5332
 
5209
5333
 
5210
- __init146() {this.offscreen = null}
5211
- __init147() {this.baked = false}
5334
+ __init148() {this.offscreen = null}
5335
+ __init149() {this.baked = false}
5212
5336
  /** Logical (CSS-pixel) size of the baked bitmap — the blit destination size. */
5213
- __init148() {this.bakedWidth = 0}
5214
- __init149() {this.bakedHeight = 0}
5337
+ __init150() {this.bakedWidth = 0}
5338
+ __init151() {this.bakedHeight = 0}
5215
5339
  /** Gradient strokes can't be baked to a solid-color bitmap; they render per-frame. */
5216
5340
 
5217
5341
  /** Lazily-flattened polylines (one Float32Array of [x,y,...] per segment) for hit-testing. */
5218
- __init150() {this.polylines = null}
5342
+ __init152() {this.polylines = null}
5219
5343
  /**
5220
5344
  * When `true`, the renderer draws a rounded-rect outline of the entity's
5221
5345
  * local bounds after painting the curves. Useful for drag feedback and
5222
5346
  * debugging hit areas. Defaults to `false`.
5223
5347
  */
5224
- __init151() {this.showBounds = false}
5348
+ __init153() {this.showBounds = false}
5225
5349
  constructor(doc, opts = {}) {
5226
- super();_class10.prototype.__init146.call(this);_class10.prototype.__init147.call(this);_class10.prototype.__init148.call(this);_class10.prototype.__init149.call(this);_class10.prototype.__init150.call(this);_class10.prototype.__init151.call(this);;
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);;
5227
5351
  this.doc = doc;
5228
5352
  this.lineWidth = _nullishCoalesce(opts.lineWidth, () => ( 2));
5229
5353
  this.cache = _nullishCoalesce(opts.cache, () => ( true));
@@ -5474,7 +5598,7 @@ async function loadSpline(url) {
5474
5598
  }
5475
5599
 
5476
5600
  // src/components/Rect.ts
5477
- var Rect = class extends _chunkIA3KW4CGjs.Entity {
5601
+ var Rect = class extends _chunkYLH7F4ZVjs.Entity {
5478
5602
 
5479
5603
 
5480
5604
 
@@ -5523,7 +5647,7 @@ var Rect = class extends _chunkIA3KW4CGjs.Entity {
5523
5647
  };
5524
5648
 
5525
5649
  // src/components/Circle.ts
5526
- var Circle = class extends _chunkIA3KW4CGjs.Entity {
5650
+ var Circle = class extends _chunkYLH7F4ZVjs.Entity {
5527
5651
 
5528
5652
 
5529
5653
 
@@ -5583,7 +5707,7 @@ var Circle = class extends _chunkIA3KW4CGjs.Entity {
5583
5707
  };
5584
5708
 
5585
5709
  // src/components/Group.ts
5586
- var Group = class extends _chunkIA3KW4CGjs.Entity {
5710
+ var Group = class extends _chunkYLH7F4ZVjs.Entity {
5587
5711
  constructor(...children) {
5588
5712
  super();
5589
5713
  if (children.length > 0) this.add(...children);
@@ -5602,21 +5726,21 @@ var _math = require('@vectojs/math'); _createStarExport(_math);
5602
5726
 
5603
5727
 
5604
5728
  // src/tree/DOMPortalEntity.ts
5605
- var DOMPortalEntity = (_class11 = class extends _chunkIA3KW4CGjs.Entity {
5729
+ var DOMPortalEntity = (_class11 = class extends _chunkYLH7F4ZVjs.Entity {
5606
5730
 
5607
- __init152() {this.isDOMPortal = true}
5608
- __init153() {this.domListeners = []}
5609
- __init154() {this.resizeObserver = null}
5610
- __init155() {this.domBound = false}
5611
- __init156() {this.cachedWidth = 100}
5612
- __init157() {this.cachedHeight = 100}
5613
- __init158() {this.lastWidth = ""}
5614
- __init159() {this.lastHeight = ""}
5615
- __init160() {this.lastTransform = ""}
5616
- __init161() {this.lastZIndex = ""}
5617
- __init162() {this.lastOpacity = ""}
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 = ""}
5618
5742
  constructor(domElement, width, height, id) {
5619
- super(id);_class11.prototype.__init152.call(this);_class11.prototype.__init153.call(this);_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);;
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);;
5620
5744
  this.domElement = domElement;
5621
5745
  this.width = _nullishCoalesce(width, () => ( 0));
5622
5746
  this.height = _nullishCoalesce(height, () => ( 0));
@@ -5658,7 +5782,7 @@ var DOMPortalEntity = (_class11 = class extends _chunkIA3KW4CGjs.Entity {
5658
5782
  ];
5659
5783
  for (const type of events) {
5660
5784
  const handler = (e) => {
5661
- this.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)(type, this, e));
5785
+ this.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)(type, this, e));
5662
5786
  };
5663
5787
  this.domElement.addEventListener(type, handler);
5664
5788
  this.domListeners.push({ type, handler, capture: false });
@@ -5669,7 +5793,7 @@ var DOMPortalEntity = (_class11 = class extends _chunkIA3KW4CGjs.Entity {
5669
5793
  ];
5670
5794
  for (const { native, vecto } of hoverEvents) {
5671
5795
  const handler = (e) => {
5672
- this.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)(vecto, this, e, false));
5796
+ this.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)(vecto, this, e, false));
5673
5797
  };
5674
5798
  this.domElement.addEventListener(native, handler);
5675
5799
  this.domListeners.push({ type: native, handler, capture: false });
@@ -5677,7 +5801,7 @@ var DOMPortalEntity = (_class11 = class extends _chunkIA3KW4CGjs.Entity {
5677
5801
  const focusEvents = ["focus", "blur"];
5678
5802
  for (const type of focusEvents) {
5679
5803
  const handler = (e) => {
5680
- this.dispatchEvent(new (0, _chunkIA3KW4CGjs.VectoJSEvent)(type, this, e, true));
5804
+ this.dispatchEvent(new (0, _chunkYLH7F4ZVjs.VectoJSEvent)(type, this, e, true));
5681
5805
  };
5682
5806
  this.domElement.addEventListener(type, handler, true);
5683
5807
  this.domListeners.push({ type, handler, capture: true });
@@ -5764,4 +5888,4 @@ Scene.registerWebGPUParticleSystemManager(_chunkL4SWVP2Hjs.WebGPUParticleSystemM
5764
5888
 
5765
5889
 
5766
5890
 
5767
- exports.CanvasRenderer = _chunkL4SWVP2Hjs.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Entity = _chunkIA3KW4CGjs.Entity; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.MSDFTextEntity = _chunkIA3KW4CGjs.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 = _chunkIA3KW4CGjs.SVGEntity; exports.SVGRenderer = _chunkL4SWVP2Hjs.SVGRenderer; exports.Scene = Scene; exports.SplineEntity = SplineEntity; exports.TextEntity = TextEntity; exports.TextRasterCache = _chunkL4SWVP2Hjs.TextRasterCache; exports.VectoJSEvent = _chunkIA3KW4CGjs.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;
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;