@vectojs/core 1.30.0 → 1.32.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
@@ -19,7 +19,7 @@ var _chunkM73XB4ZKjs = require('./chunk-M73XB4ZK.js');
19
19
 
20
20
 
21
21
 
22
- var _chunk7PI7LVWWjs = require('./chunk-7PI7LVWW.js');
22
+ var _chunkTRT2TRCWjs = require('./chunk-TRT2TRCW.js');
23
23
 
24
24
  // src/tree/Scene.ts
25
25
  var _animation = require('@vectojs/animation'); _createStarExport(_animation);
@@ -34,7 +34,7 @@ var PARTICLE_OFFSET_ORIGIN_X = 4;
34
34
  var PARTICLE_OFFSET_ORIGIN_Y = 5;
35
35
  var PARTICLE_OFFSET_SIZE = 6;
36
36
  var PARTICLE_OFFSET_LIFE = 7;
37
- var ComputeParticleEntity = (_class = class extends _chunk7PI7LVWWjs.Entity {
37
+ var ComputeParticleEntity = (_class = class extends _chunkTRT2TRCWjs.Entity {
38
38
 
39
39
 
40
40
 
@@ -1380,6 +1380,8 @@ var SCENE_OPTION_KEYS = [
1380
1380
  "autoThrottle",
1381
1381
  "contentProjection",
1382
1382
  "contentProjectionMargin",
1383
+ "contentSemanticBudget",
1384
+ "contentSemanticMargin",
1383
1385
  "debugA11y",
1384
1386
  "disableWindowResize",
1385
1387
  "maxDPR",
@@ -1432,6 +1434,7 @@ function parseInlinePx(value) {
1432
1434
  const n = parseFloat(value);
1433
1435
  return Number.isFinite(n) && n > 0 ? n : null;
1434
1436
  }
1437
+ var DEFAULT_CONTENT_SEMANTIC_BUDGET = 256;
1435
1438
  function projectionGridLineWindow(grid, projectionLines, band) {
1436
1439
  const count = grid.lines.length;
1437
1440
  const all = { start: 0, end: count, gated: false };
@@ -1957,10 +1960,19 @@ var Scene = (_class7 = class _Scene {
1957
1960
  __init54() {this.a11yElements = /* @__PURE__ */ new Map()}
1958
1961
  /** DOM nodes mirroring static text content, keyed by entity id. */
1959
1962
  __init55() {this.contentElements = /* @__PURE__ */ new Map()}
1963
+ /**
1964
+ * What the last completed content-projection sync was built from, per entity.
1965
+ *
1966
+ * Compared at the top of {@link syncContentProjection} to skip a block whose
1967
+ * content AND geometry are both unchanged, before the O(glyphs) projection
1968
+ * build. Only populated for entities that opt in via
1969
+ * {@link Entity.getContentEpoch}. (carryctx CTX-0199)
1970
+ */
1971
+ __init56() {this.contentSyncState = /* @__PURE__ */ new Map()}
1960
1972
  /** Pending cold font-calibration frame per projected grid entity. */
1961
- __init56() {this.contentGridCalibrationFrames = /* @__PURE__ */ new Map()}
1973
+ __init57() {this.contentGridCalibrationFrames = /* @__PURE__ */ new Map()}
1962
1974
  /** Detached, untransformed font probes used by the cold calibration pass. */
1963
- __init57() {this.contentGridCalibrationProbes = /* @__PURE__ */ new Map()}
1975
+ __init58() {this.contentGridCalibrationProbes = /* @__PURE__ */ new Map()}
1964
1976
  /**
1965
1977
  * Monotonic stamp identifying the conditions grid cells were calibrated under.
1966
1978
  *
@@ -1981,54 +1993,94 @@ var Scene = (_class7 = class _Scene {
1981
1993
  * A plain incrementing integer rather than the descriptive calibration key,
1982
1994
  * because it goes into an attribute selector and must not need escaping.
1983
1995
  */
1984
- __init58() {this.contentGridCalibrationGeneration = 0}
1996
+ __init59() {this.contentGridCalibrationGeneration = 0}
1985
1997
  /** The `(fontEpoch, pageScale)` pair the current generation corresponds to. */
1986
- __init59() {this.contentGridCalibrationStamp = ""}
1998
+ __init60() {this.contentGridCalibrationStamp = ""}
1987
1999
  /** Invalidates grid font calibration after browser font availability changes. */
1988
- __init60() {this.contentFontEpoch = 0}
2000
+ __init61() {this.contentFontEpoch = 0}
1989
2001
  /** Cached Canvas-to-client scale for the current font/viewport epoch. */
1990
- __init61() {this.contentMetricScaleEpoch = -1}
1991
- __init62() {this.contentMetricScaleX = 1}
1992
- __init63() {this.contentProjectionEnabled = true}
1993
- // Virtualization margin (px) for content projection; `undefined` → one
1994
- // viewport height, resolved at sync time. `Infinity` = materialize everything.
1995
- __init64() {this.contentProjectionMargin = void 0}
2002
+ __init62() {this.contentMetricScaleEpoch = -1}
2003
+ __init63() {this.contentMetricScaleX = 1}
2004
+ __init64() {this.contentProjectionEnabled = true}
2005
+ // Virtualization margin (px) for the content-projection CARRIER band;
2006
+ // `undefined` → one viewport height, resolved at sync time. `Infinity` is
2007
+ // unsupported here: it unwindows every carrier, which is O(total glyphs).
2008
+ __init65() {this.contentProjectionMargin = void 0}
2009
+ // Virtualization margin (px) for the SEMANTIC tier — whether a block has
2010
+ // any projected DOM. `undefined` → falls back to contentProjectionMargin, so
2011
+ // the default keeps one gate. `Infinity` = every block keeps resident text.
2012
+ __init66() {this.contentSemanticMargin = void 0}
2013
+ // How many coarse-tier blocks may be MATERIALIZED per sync, spreading the
2014
+ // resident tier's document-open cost across frames. `Infinity` = one
2015
+ // synchronous pass.
2016
+ __init67() {this.contentSemanticBudget = DEFAULT_CONTENT_SEMANTIC_BUDGET}
2017
+ // Remaining materializations in the CURRENT sync. Reset at the start of each
2018
+ // a11y walk; decremented per coarse block that creates its element.
2019
+ __init68() {this.contentSemanticBudgetLeft = 0}
2020
+ // Set when a sync deferred at least one block, so the scene knows to keep
2021
+ // drawing frames until the resident tier is complete. Without it a static
2022
+ // scene in `onDemand` mode would stop rendering with the document half
2023
+ // materialized and never finish.
2024
+ __init69() {this.contentSemanticDeferred = false}
2025
+ /**
2026
+ * Per-sync memo of "does the document hold a selection at all".
2027
+ *
2028
+ * Reading ANY property of a `Selection` (`anchorNode`, `rangeCount`, `type`,
2029
+ * `isCollapsed`) forces a synchronous layout, because Blink validates the
2030
+ * selection against current box geometry before answering. Measured in real
2031
+ * Chrome against a 1000-carrier subtree with layout dirtied between reads:
2032
+ * `anchorNode` 0.5ms, `rangeCount` 0.4ms, `type` 0.5ms, `isCollapsed` 0.5ms —
2033
+ * all indistinguishable from `offsetHeight` (0.5ms), against a 0ms floor for
2034
+ * mutating without reading. So there is no cheap property to probe with; the
2035
+ * only way to avoid the layout is to not touch the object at all.
2036
+ *
2037
+ * Materializing a block rebuilds its carriers, which asks whether the rebuild
2038
+ * would destroy a selection. Once per block, that read cost a forced layout
2039
+ * over the whole (and growing) projection subtree, which is what made
2040
+ * per-block cost rise with resident count: profiled at 1973 forced layouts
2041
+ * totalling 633ms of an 847ms 1000-block drain (75%).
2042
+ *
2043
+ * A selection is a single document-wide object and a sync walk cannot yield to
2044
+ * the user, so its presence cannot change mid-walk. Resolving it once per walk
2045
+ * turns O(blocks) forced layouts into O(1). `null` = not yet resolved.
2046
+ */
2047
+ __init70() {this.contentSelectionPresentThisSync = null}
1996
2048
  /**
1997
2049
  * True while a text-selection drag that started on a projection's blank
1998
2050
  * region (no text node under the press) is being driven manually — the
1999
2051
  * browser has no native anchor for it, so mousemove extends the Selection
2000
2052
  * from the position we resolved ourselves.
2001
2053
  */
2002
- __init65() {this.blankRegionSelectionDrag = false}
2003
- __init66() {this.contentSelectionAnchor = null}
2004
- __init67() {this.contentSelectionEndListener = null}
2054
+ __init71() {this.blankRegionSelectionDrag = false}
2055
+ __init72() {this.contentSelectionAnchor = null}
2056
+ __init73() {this.contentSelectionEndListener = null}
2005
2057
  // Animation/interactive flags collected during the render walk (tree-walk
2006
2058
  // fusion): the loop reads last frame's answers instead of re-walking the
2007
2059
  // tree up to 4× per tick. Start true so the first tick stays conservative.
2008
- __init68() {this.frameHadAnimation = true}
2009
- __init69() {this.frameHadInteractive = true}
2060
+ __init74() {this.frameHadAnimation = true}
2061
+ __init75() {this.frameHadInteractive = true}
2010
2062
 
2011
2063
  /** Active `(resolution: Ndppx)` media query watching for a runtime DPR change
2012
2064
  * (window moved between monitors, browser zoom) so the canvas backing store
2013
2065
  * can be re-scaled — otherwise it stays rasterized at the old DPR and blurs.
2014
2066
  * A resolution media query only fires when leaving its exact value, so the
2015
2067
  * handler re-arms a fresh query for the new DPR each time. */
2016
- __init70() {this.dprMediaQuery = null}
2068
+ __init76() {this.dprMediaQuery = null}
2017
2069
  /** For embedded (`disableWindowResize`) scenes: observes the canvas element so
2018
2070
  * a CSS/layout-driven size change re-runs `resize()`. A window `resize`
2019
2071
  * listener never fires for these (the window isn't what changed), so without
2020
2072
  * this an embedded canvas stayed at its initial size forever. */
2021
- __init71() {this.canvasResizeObserver = null}
2022
- __init72() {this.dprChangeHandler = null}
2023
- __init73() {this.focusedA11yElement = null}
2073
+ __init77() {this.canvasResizeObserver = null}
2074
+ __init78() {this.dprChangeHandler = null}
2075
+ __init79() {this.focusedA11yElement = null}
2024
2076
  /** Last geometry `syncOverlayGeometry` wrote, so an unchanged frame can skip the
2025
2077
  * style writes entirely. Reset to `null` to force the next sync (a new overlay
2026
2078
  * layer was created and has never been positioned). */
2027
- __init74() {this._overlayGeometry = null}
2079
+ __init80() {this._overlayGeometry = null}
2028
2080
  /** Shadow elements the pointer is currently inside. Lets a removal that happens
2029
2081
  * mid-hover synthesize the `pointerleave` the browser never sends for a
2030
2082
  * detached element, so the entity doesn't keep its hover state. */
2031
- __init75() {this.hoveredA11yElements = /* @__PURE__ */ new WeakSet()}
2083
+ __init81() {this.hoveredA11yElements = /* @__PURE__ */ new WeakSet()}
2032
2084
  /**
2033
2085
  * Entity ids the application has pinned via {@link requestA11yProjection}.
2034
2086
  *
@@ -2036,22 +2088,22 @@ var Scene = (_class7 = class _Scene {
2036
2088
  * a stale id simply never matches. Cleared per-entity by
2037
2089
  * {@link releaseA11yProjection}.
2038
2090
  */
2039
- __init76() {this.a11yProjectionRequests = /* @__PURE__ */ new Set()}
2091
+ __init82() {this.a11yProjectionRequests = /* @__PURE__ */ new Set()}
2040
2092
  /** Persistent tabindex=-1 element in a11yRoot. When the focused a11y mirror is
2041
2093
  * pruned (virtualization/streaming/removal) while it holds focus, we move
2042
2094
  * focus here instead of letting the browser drop it to <body> — keeping the
2043
2095
  * screen-reader virtual cursor inside the scene's a11y region. */
2044
- __init77() {this.focusSentinel = null}
2045
- __init78() {this.caretBlinkTimer = null}
2046
- __init79() {this.a11yNeedsReorder = true}
2047
- __init80() {this.portalRoot = null}
2048
- __init81() {this.fullViewportElements = []}
2049
- __init82() {this.normalElements = []}
2050
- __init83() {this.activeIds = /* @__PURE__ */ new Set()}
2096
+ __init83() {this.focusSentinel = null}
2097
+ __init84() {this.caretBlinkTimer = null}
2098
+ __init85() {this.a11yNeedsReorder = true}
2099
+ __init86() {this.portalRoot = null}
2100
+ __init87() {this.fullViewportElements = []}
2101
+ __init88() {this.normalElements = []}
2102
+ __init89() {this.activeIds = /* @__PURE__ */ new Set()}
2051
2103
  /** Per-parent insertion cursor, reused by `enforceA11yDomOrder`. */
2052
- __init84() {this.a11yOrderCursors = /* @__PURE__ */ new Map()}
2104
+ __init90() {this.a11yOrderCursors = /* @__PURE__ */ new Map()}
2053
2105
  /** Membership set for the elements being ordered, reused per reorder pass. */
2054
- __init85() {this.a11yOrderMembers = /* @__PURE__ */ new Set()}
2106
+ __init91() {this.a11yOrderMembers = /* @__PURE__ */ new Set()}
2055
2107
  /**
2056
2108
  * Elements that are an *ancestor* of another ordered element, reused per pass.
2057
2109
  *
@@ -2059,11 +2111,11 @@ var Scene = (_class7 = class _Scene {
2059
2111
  * items) spans every descendant row, so it must not extend a visual row band —
2060
2112
  * see {@link sortNormalElementsVisually}.
2061
2113
  */
2062
- __init86() {this.a11yOrderContainers = /* @__PURE__ */ new Set()}
2063
- __init87() {this.activePortalsThisFrame = /* @__PURE__ */ new Set()}
2064
- __init88() {this.activePortalsPrevFrame = /* @__PURE__ */ new Set()}
2065
- __init89() {this.portalEntities = /* @__PURE__ */ new Map()}
2066
- __init90() {this.renderOrderCounter = 0}
2114
+ __init92() {this.a11yOrderContainers = /* @__PURE__ */ new Set()}
2115
+ __init93() {this.activePortalsThisFrame = /* @__PURE__ */ new Set()}
2116
+ __init94() {this.activePortalsPrevFrame = /* @__PURE__ */ new Set()}
2117
+ __init95() {this.portalEntities = /* @__PURE__ */ new Map()}
2118
+ __init96() {this.renderOrderCounter = 0}
2067
2119
  /**
2068
2120
  * Monotonic render-frame counter, bumped once per authoritative `render()`
2069
2121
  * pass. Entities stamp their per-frame world-matrix cache with this value and
@@ -2072,7 +2124,7 @@ var Scene = (_class7 = class _Scene {
2072
2124
  * back to the ancestor walk. Public for the same reason `Entity._getTrig`/
2073
2125
  * `_setWorldCache` are: it is a cross-class render-internal contract.
2074
2126
  */
2075
- __init91() {this.currentFrame = 0}
2127
+ __init97() {this.currentFrame = 0}
2076
2128
  // ── WASM transform backend (invisible accelerator) ──────────────────────────
2077
2129
  // When `_transformBackend === 'wasm'`, the main render walk sources each
2078
2130
  // entity's world matrix from an SoA store composed by `_wasm` (see
@@ -2080,24 +2132,24 @@ var Scene = (_class7 = class _Scene {
2080
2132
  // fallback and the default: a null backend, a non-main renderer, or any entity
2081
2133
  // absent from the store all fall back to the JS composition, so WASM can only
2082
2134
  // ever change *how fast* a world matrix is produced, never *what* it is.
2083
- __init92() {this._wasm = null}
2084
- __init93() {this._transformBackend = "js"}
2135
+ __init98() {this._wasm = null}
2136
+ __init99() {this._transformBackend = "js"}
2085
2137
  // Resident store state (Stage 3). The store layout — slot assignment + sibling
2086
2138
  // runs — depends only on tree TOPOLOGY, so it is rebuilt only when the
2087
2139
  // structure changes (add/remove/reparent bump `_structureVersion`). Between
2088
2140
  // rebuilds the per-frame cost is: gather each entity's transform into the
2089
2141
  // resident wasm input view + run the kernel — no reallocation, no readback.
2090
- __init94() {this._treeStore = null}
2091
- __init95() {this._slotEntity = []}
2142
+ __init100() {this._treeStore = null}
2143
+ __init101() {this._slotEntity = []}
2092
2144
  // store slot -> entity (also validates slots)
2093
- __init96() {this._wasmInputs = null}
2094
- __init97() {this._wasmWorld = null}
2095
- __init98() {this._structureVersion = 0}
2096
- __init99() {this._storeStructureVersion = -1}
2145
+ __init102() {this._wasmInputs = null}
2146
+ __init103() {this._wasmWorld = null}
2147
+ __init104() {this._structureVersion = 0}
2148
+ __init105() {this._storeStructureVersion = -1}
2097
2149
  // Cached list of ComputeParticleEntity instances in the tree, keyed by the
2098
2150
  // structure version it was gathered at. Rebuilt only on a topology change.
2099
- __init100() {this._computeEntities = []}
2100
- __init101() {this._computeEntitiesVersion = -1}
2151
+ __init106() {this._computeEntities = []}
2152
+ __init107() {this._computeEntitiesVersion = -1}
2101
2153
  /** Invalidate the resident WASM store layout; the next wasm-mode frame rebuilds
2102
2154
  * it. Called by `Entity.add`/`remove` (topology changes only). */
2103
2155
  markStructureChanged() {
@@ -2182,7 +2234,7 @@ var Scene = (_class7 = class _Scene {
2182
2234
  * cached globally; the instance is per-Scene, which is the isolation that
2183
2235
  * actually matters.
2184
2236
  */
2185
- __init102() {this._wasmRuntime = null}
2237
+ __init108() {this._wasmRuntime = null}
2186
2238
  /**
2187
2239
  * Load (or reuse) this Scene's shared WASM runtime.
2188
2240
  *
@@ -2210,30 +2262,30 @@ var Scene = (_class7 = class _Scene {
2210
2262
  get wasmRuntime() {
2211
2263
  return this._wasmRuntime;
2212
2264
  }
2213
- __init103() {this._hitWasm = null}
2265
+ __init109() {this._hitWasm = null}
2214
2266
  // Cache key: which frame + structure version the grid was last (successfully,
2215
2267
  // non-overflowing) built for. findEntityAt is called ad-hoc (pointer
2216
2268
  // hover/click), not every frame, so the grid is refreshed lazily on demand
2217
2269
  // rather than proactively every render() — unlike the transform store, which
2218
2270
  // every frame's draw depends on.
2219
- __init104() {this._hitGridFrame = -1}
2220
- __init105() {this._hitGridOk = false}
2221
- __init106() {this._hitSlotEntity = []}
2222
- __init107() {this._hitBoundless = []}
2271
+ __init110() {this._hitGridFrame = -1}
2272
+ __init111() {this._hitGridOk = false}
2273
+ __init112() {this._hitSlotEntity = []}
2274
+ __init113() {this._hitBoundless = []}
2223
2275
  /** Reused buffer for the fused gather, so a pointer query allocates nothing. */
2224
- __init108() {this._hitGatherBuffer = null}
2276
+ __init114() {this._hitGatherBuffer = null}
2225
2277
  /**
2226
2278
  * Whether the last grid build sourced its AABBs from the WASM transform store
2227
2279
  * rather than recomputing them in JS. Diagnostic only — both paths must
2228
2280
  * produce the same entity for a given point.
2229
2281
  */
2230
- __init109() {this._hitFusedGather = false}
2282
+ __init115() {this._hitFusedGather = false}
2231
2283
  /**
2232
2284
  * Whether `compute_aabbs` has run against the current frame's world matrices.
2233
2285
  * The AABB pass is only meaningful after a `compose_*`, so the fused gather
2234
2286
  * must not read the views before then.
2235
2287
  */
2236
- __init110() {this._wasmAabbsFresh = false}
2288
+ __init116() {this._wasmAabbsFresh = false}
2237
2289
  /** Did the last hit-grid build use the fused (WASM-store) gather? */
2238
2290
  get hitGatherPath() {
2239
2291
  return this._hitFusedGather ? "fused" : "js";
@@ -2242,9 +2294,9 @@ var Scene = (_class7 = class _Scene {
2242
2294
  * Why the transform accelerator did or did not run on the most recent frame.
2243
2295
  * Written by the render walk and `_syncWasmStore`.
2244
2296
  */
2245
- __init111() {this._transformReason = "not-installed"}
2297
+ __init117() {this._transformReason = "not-installed"}
2246
2298
  /** Why the batched-driver accelerator did or did not run. */
2247
- __init112() {this._animReason = "not-installed"}
2299
+ __init118() {this._animReason = "not-installed"}
2248
2300
  /**
2249
2301
  * Why the hit-test accelerator did or did not serve the last pointer query.
2250
2302
  * The grid is built lazily on demand, not every frame, so this describes the
@@ -2252,11 +2304,11 @@ var Scene = (_class7 = class _Scene {
2252
2304
  * before a backend exists; `_ensureHitGrid` moves it to `'not-applicable'`
2253
2305
  * once one is installed but nothing has queried yet.
2254
2306
  */
2255
- __init113() {this._hitReason = "not-installed"}
2307
+ __init119() {this._hitReason = "not-installed"}
2256
2308
  /** Why the particle accelerator did or did not run. */
2257
- __init114() {this._particleReason = "not-applicable"}
2309
+ __init120() {this._particleReason = "not-applicable"}
2258
2310
  /** Which particle implementation actually simulated the most recent frame. */
2259
- __init115() {this._particlePath = "none"}
2311
+ __init121() {this._particlePath = "none"}
2260
2312
  /**
2261
2313
  * Per-frame status of every invisible accelerator: whether each is installed,
2262
2314
  * whether it actually ran on the most recent frame, and why.
@@ -2416,25 +2468,25 @@ var Scene = (_class7 = class _Scene {
2416
2468
  // EasingFn (which cannot cross into WASM) all fall through to it — WASM can
2417
2469
  // only ever change *how* a driver is advanced, never *what* value it lands
2418
2470
  // on.
2419
- __init116() {this._animWasm = null}
2471
+ __init122() {this._animWasm = null}
2420
2472
  // Entities with at least one active driver, added by Entity._spawnDriver.
2421
2473
  // Self-pruning: _tickBatchedDrivers drops an entry the first time it visits
2422
2474
  // an entity whose drivers have since all completed or been removed. This is
2423
2475
  // what lets the batch pass find its candidates in O(active drivers), not
2424
2476
  // O(tree size) — the exact mistake G3's first integrated benchmark made.
2425
- __init117() {this._activeDriverEntities = /* @__PURE__ */ new Set()}
2477
+ __init123() {this._activeDriverEntities = /* @__PURE__ */ new Set()}
2426
2478
  // Reused across frames instead of allocating a fresh array + N {entity,prop,
2427
2479
  // driver} objects every call — the integrated benchmark
2428
2480
  // (benchmarks/anim-wasm-scene) found that allocation churn was the
2429
2481
  // dominant integrated cost, not the wasm kernel itself. Parallel arrays,
2430
2482
  // truncated to the live count after each use so a stale tail slot never
2431
2483
  // pins a no-longer-active entity/driver in memory.
2432
- __init118() {this._springEntities = []}
2433
- __init119() {this._springProps = []}
2434
- __init120() {this._springDrivers = []}
2435
- __init121() {this._tweenEntities = []}
2436
- __init122() {this._tweenProps = []}
2437
- __init123() {this._tweenDrivers = []}
2484
+ __init124() {this._springEntities = []}
2485
+ __init125() {this._springProps = []}
2486
+ __init126() {this._springDrivers = []}
2487
+ __init127() {this._tweenEntities = []}
2488
+ __init128() {this._tweenProps = []}
2489
+ __init129() {this._tweenDrivers = []}
2438
2490
  /**
2439
2491
  * Minimum number of batchable (spring, or named-easing tween) active drivers
2440
2492
  * before a frame engages the WASM batch path at all; below it, every driver
@@ -2506,7 +2558,7 @@ var Scene = (_class7 = class _Scene {
2506
2558
  * Setting {@link animDriverGateCount} overwrites all three, so existing code
2507
2559
  * that tuned the single knob keeps working unchanged.
2508
2560
  */
2509
- __init124() {this._animBatchedLastFrame = false}
2561
+ __init130() {this._animBatchedLastFrame = false}
2510
2562
  /**
2511
2563
  * Whether the WASM batch path actually ran on the most recent frame.
2512
2564
  *
@@ -2518,7 +2570,7 @@ var Scene = (_class7 = class _Scene {
2518
2570
  get animBatchedLastFrame() {
2519
2571
  return this._animBatchedLastFrame;
2520
2572
  }
2521
- __init125() {this.animGate = {
2573
+ __init131() {this.animGate = {
2522
2574
  spring: 128,
2523
2575
  tween: 256,
2524
2576
  mixed: 128
@@ -2556,7 +2608,7 @@ var Scene = (_class7 = class _Scene {
2556
2608
  // (benchmarks/particle-wasm). f32 (matches the WGSL shader), bit-identical to
2557
2609
  // a JS f32 reference oracle; updateCPU (f64) stays the permanent fallback when
2558
2610
  // no backend is installed or a scene runs on WebGPU.
2559
- __init126() {this._particleWasm = null}
2611
+ __init132() {this._particleWasm = null}
2560
2612
  /** Which backend runs the CPU particle simulation. Reflects only whether a
2561
2613
  * backend is installed (the WebGPU compute path, when active, is used first
2562
2614
  * regardless). */
@@ -2833,24 +2885,24 @@ var Scene = (_class7 = class _Scene {
2833
2885
  * sync, so retaining the order prevents a newly opened overlay from spending
2834
2886
  * its first frame below previously projected controls.
2835
2887
  */
2836
- __init127() {this.a11yRenderOrders = /* @__PURE__ */ new Map()}
2888
+ __init133() {this.a11yRenderOrders = /* @__PURE__ */ new Map()}
2837
2889
  // Optional WebGL point-cloud layer (see SceneOptions.pointBackend).
2838
- __init128() {this.pointRenderer = null}
2839
- __init129() {this.glCanvas = null}
2840
- __init130() {this.glContextLostHandler = null}
2841
- __init131() {this.glContextRestoredHandler = null}
2890
+ __init134() {this.pointRenderer = null}
2891
+ __init135() {this.glCanvas = null}
2892
+ __init136() {this.glContextLostHandler = null}
2893
+ __init137() {this.glContextRestoredHandler = null}
2842
2894
 
2843
2895
 
2844
2896
 
2845
- __init132() {this.disableWindowResize = false}
2897
+ __init138() {this.disableWindowResize = false}
2846
2898
  /** See {@link SceneOptions.maxDPR}. `undefined` = uncapped (real DPR). */
2847
2899
 
2848
2900
  // WebGPU properties
2849
- __init133() {this.destroyed = false}
2850
- __init134() {this.device = null}
2851
- __init135() {this.deviceLost = false}
2852
- __init136() {this.particleBackend = "auto"}
2853
- __init137() {this._webgpuDisabled = false}
2901
+ __init139() {this.destroyed = false}
2902
+ __init140() {this.device = null}
2903
+ __init141() {this.deviceLost = false}
2904
+ __init142() {this.particleBackend = "auto"}
2905
+ __init143() {this._webgpuDisabled = false}
2854
2906
  get webgpuDisabled() {
2855
2907
  return this._webgpuDisabled || this.particleBackend === "cpu";
2856
2908
  }
@@ -2878,22 +2930,22 @@ var Scene = (_class7 = class _Scene {
2878
2930
  set webgpuDisabled(value) {
2879
2931
  this._webgpuDisabled = value;
2880
2932
  }
2881
- __init138() {this.recoveryTimerId = null}
2882
- __init139() {this.manager = null}
2883
- __init140() {this.initializingWebGPU = false}
2884
- __init141() {this.gpuCanvas = null}
2885
- __init142() {this.gpuContext = null}
2933
+ __init144() {this.recoveryTimerId = null}
2934
+ __init145() {this.manager = null}
2935
+ __init146() {this.initializingWebGPU = false}
2936
+ __init147() {this.gpuCanvas = null}
2937
+ __init148() {this.gpuContext = null}
2886
2938
  /** True while the GPU canvas holds a presented particle frame (needs clearing when they leave). */
2887
- __init143() {this.gpuHasContent = false}
2888
- __init144() {this.mouseX = -9999}
2889
- __init145() {this.mouseY = -9999}
2890
- __init146() {this.pointerMoveListener = null}
2891
- __init147() {this.pointerLeaveListener = null}
2939
+ __init149() {this.gpuHasContent = false}
2940
+ __init150() {this.mouseX = -9999}
2941
+ __init151() {this.mouseY = -9999}
2942
+ __init152() {this.pointerMoveListener = null}
2943
+ __init153() {this.pointerLeaveListener = null}
2892
2944
  /** Element the pointer listeners are bound to (parent container if present,
2893
2945
  * else the canvas). Stored so `destroy()` detaches from the same element. */
2894
- __init148() {this.pointerEventTarget = null}
2895
- __init149() {this.hasWarnedZeroSize = false}
2896
- __init150() {this.fontLoadHandler = null}
2946
+ __init154() {this.pointerEventTarget = null}
2947
+ __init155() {this.hasWarnedZeroSize = false}
2948
+ __init156() {this.fontLoadHandler = null}
2897
2949
  // ── Dev-mode warning infrastructure ──────────────────────────────
2898
2950
  //
2899
2951
  // Enable with `Scene.devMode = true` or by setting `globalThis.__DEV__`.
@@ -2927,7 +2979,7 @@ var Scene = (_class7 = class _Scene {
2927
2979
  return false;
2928
2980
  }
2929
2981
 
2930
- __init151() {this._devFrameCount = 0}
2982
+ __init157() {this._devFrameCount = 0}
2931
2983
  _devWarn(message) {
2932
2984
  if (!this._devActive) return;
2933
2985
  console.warn(`[vectojs/dev] ${message}`);
@@ -3004,7 +3056,7 @@ var Scene = (_class7 = class _Scene {
3004
3056
  };
3005
3057
  walkProjections(this.root);
3006
3058
  }
3007
- constructor(canvas, options = {}) {;_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);_class7.prototype.__init140.call(this);_class7.prototype.__init141.call(this);_class7.prototype.__init142.call(this);_class7.prototype.__init143.call(this);_class7.prototype.__init144.call(this);_class7.prototype.__init145.call(this);_class7.prototype.__init146.call(this);_class7.prototype.__init147.call(this);_class7.prototype.__init148.call(this);_class7.prototype.__init149.call(this);_class7.prototype.__init150.call(this);_class7.prototype.__init151.call(this);
3059
+ constructor(canvas, options = {}) {;_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);_class7.prototype.__init140.call(this);_class7.prototype.__init141.call(this);_class7.prototype.__init142.call(this);_class7.prototype.__init143.call(this);_class7.prototype.__init144.call(this);_class7.prototype.__init145.call(this);_class7.prototype.__init146.call(this);_class7.prototype.__init147.call(this);_class7.prototype.__init148.call(this);_class7.prototype.__init149.call(this);_class7.prototype.__init150.call(this);_class7.prototype.__init151.call(this);_class7.prototype.__init152.call(this);_class7.prototype.__init153.call(this);_class7.prototype.__init154.call(this);_class7.prototype.__init155.call(this);_class7.prototype.__init156.call(this);_class7.prototype.__init157.call(this);
3008
3060
  this.canvas = canvas;
3009
3061
  this.debugA11y = _nullishCoalesce(options.debugA11y, () => ( false));
3010
3062
  this.disableWindowResize = _nullishCoalesce(options.disableWindowResize, () => ( false));
@@ -3028,6 +3080,8 @@ var Scene = (_class7 = class _Scene {
3028
3080
  this.a11ySyncInterval = _nullishCoalesce(options.a11ySyncInterval, () => ( 0));
3029
3081
  this.contentProjectionEnabled = _nullishCoalesce(options.contentProjection, () => ( true));
3030
3082
  this.contentProjectionMargin = options.contentProjectionMargin;
3083
+ this.contentSemanticMargin = options.contentSemanticMargin;
3084
+ this.contentSemanticBudget = _nullishCoalesce(options.contentSemanticBudget, () => ( DEFAULT_CONTENT_SEMANTIC_BUDGET));
3031
3085
  this.readingDirection = _nullishCoalesce(options.readingDirection, () => ( "ltr"));
3032
3086
  this.renderMode = _nullishCoalesce(options.renderMode, () => ( "always"));
3033
3087
  this._devActive = _Scene._devModeDetected();
@@ -3039,7 +3093,7 @@ var Scene = (_class7 = class _Scene {
3039
3093
  this.forcedColorsChangeHandler = () => this.markDirty();
3040
3094
  _optionalChain([this, 'access', _62 => _62.forcedColorsQuery, 'access', _63 => _63.addEventListener, 'optionalCall', _64 => _64("change", this.forcedColorsChangeHandler)]);
3041
3095
  }
3042
- this.root = new class RootEntity extends _chunk7PI7LVWWjs.Entity {
3096
+ this.root = new class RootEntity extends _chunkTRT2TRCWjs.Entity {
3043
3097
  isPointInside() {
3044
3098
  return false;
3045
3099
  }
@@ -3048,7 +3102,7 @@ var Scene = (_class7 = class _Scene {
3048
3102
  }
3049
3103
  }("root");
3050
3104
  this.root._scene = this;
3051
- this.overlayRoot = new class OverlayRoot extends _chunk7PI7LVWWjs.Entity {
3105
+ this.overlayRoot = new class OverlayRoot extends _chunkTRT2TRCWjs.Entity {
3052
3106
  isPointInside() {
3053
3107
  return false;
3054
3108
  }
@@ -3309,12 +3363,31 @@ var Scene = (_class7 = class _Scene {
3309
3363
  }
3310
3364
  return null;
3311
3365
  }
3366
+ /**
3367
+ * Does the document hold a selection right now, memoized for this sync walk?
3368
+ *
3369
+ * Pays one forced layout per walk instead of one per rebuilt element — see
3370
+ * {@link Scene.contentSelectionPresentThisSync} for the measurements. When the
3371
+ * answer is `false` no element can own a selection, so every per-element
3372
+ * ownership test can be skipped without touching the object.
3373
+ */
3374
+ contentSelectionPresent() {
3375
+ if (this.contentSelectionPresentThisSync !== null) {
3376
+ return this.contentSelectionPresentThisSync;
3377
+ }
3378
+ const selection = typeof window !== "undefined" && typeof window.getSelection === "function" ? window.getSelection() : null;
3379
+ const present = !!selection && (!!selection.anchorNode || !!selection.focusNode);
3380
+ this.contentSelectionPresentThisSync = present;
3381
+ return present;
3382
+ }
3312
3383
  releaseContentSelectionForRebuild(el) {
3384
+ if (!this.contentSelectionAnchor && !this.contentSelectionPresent()) return;
3313
3385
  const selection = typeof window !== "undefined" && typeof window.getSelection === "function" ? window.getSelection() : null;
3314
3386
  const ownsSelection = this.contentSelectionAnchor && el.contains(this.contentSelectionAnchor.node) || (_optionalChain([selection, 'optionalAccess', _85 => _85.anchorNode]) ? el.contains(selection.anchorNode) : false) || (_optionalChain([selection, 'optionalAccess', _86 => _86.focusNode]) ? el.contains(selection.focusNode) : false);
3315
3387
  if (!ownsSelection) return;
3316
3388
  this.endContentSelectionDrag();
3317
3389
  _optionalChain([selection, 'optionalAccess', _87 => _87.removeAllRanges, 'call', _88 => _88()]);
3390
+ this.contentSelectionPresentThisSync = null;
3318
3391
  }
3319
3392
  /**
3320
3393
  * Rebuild a content-projection element's DOM (`rebuild`) while preserving a
@@ -3332,6 +3405,10 @@ var Scene = (_class7 = class _Scene {
3332
3405
  * restore against).
3333
3406
  */
3334
3407
  preserveContentSelectionAcrossRebuild(el, rebuild) {
3408
+ if (!this.contentSelectionAnchor && !this.contentSelectionPresent()) {
3409
+ rebuild();
3410
+ return;
3411
+ }
3335
3412
  const selection = typeof window !== "undefined" && typeof window.getSelection === "function" ? window.getSelection() : null;
3336
3413
  const owns = !!selection && !this.blankRegionSelectionDrag && ((selection.anchorNode ? el.contains(selection.anchorNode) : false) || (selection.focusNode ? el.contains(selection.focusNode) : false));
3337
3414
  if (!owns || !selection.anchorNode || !selection.focusNode) {
@@ -3450,6 +3527,7 @@ var Scene = (_class7 = class _Scene {
3450
3527
  this.clearContentGridState(node.id, contentEl);
3451
3528
  contentEl.remove();
3452
3529
  this.contentElements.delete(node.id);
3530
+ this.contentSyncState.delete(node.id);
3453
3531
  this.a11yNeedsReorder = true;
3454
3532
  }
3455
3533
  const el = this.a11yElements.get(node.id);
@@ -3463,7 +3541,7 @@ var Scene = (_class7 = class _Scene {
3463
3541
  }
3464
3542
  if (this.hoveredA11yElements.has(el)) {
3465
3543
  this.hoveredA11yElements.delete(el);
3466
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("pointerleave", node, void 0, false));
3544
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("pointerleave", node, void 0, false));
3467
3545
  }
3468
3546
  this.preserveFocusOnRemoval(el);
3469
3547
  el.remove();
@@ -3594,6 +3672,7 @@ var Scene = (_class7 = class _Scene {
3594
3672
  this.a11yElements.clear();
3595
3673
  for (const el of this.contentElements.values()) el.remove();
3596
3674
  this.contentElements.clear();
3675
+ this.contentSyncState.clear();
3597
3676
  if (typeof cancelAnimationFrame === "function") {
3598
3677
  for (const frame of this.contentGridCalibrationFrames.values()) {
3599
3678
  cancelAnimationFrame(frame);
@@ -4025,6 +4104,11 @@ var Scene = (_class7 = class _Scene {
4025
4104
  }
4026
4105
  syncA11y(node, container = null) {
4027
4106
  if (!this.a11yRoot) return;
4107
+ if (node === this.root) {
4108
+ this.contentSemanticBudgetLeft = this.contentSemanticBudget;
4109
+ this.contentSemanticDeferred = false;
4110
+ this.contentSelectionPresentThisSync = null;
4111
+ }
4028
4112
  if (node.isDOMPortal) {
4029
4113
  return;
4030
4114
  }
@@ -4076,20 +4160,20 @@ var Scene = (_class7 = class _Scene {
4076
4160
  el.style.background = "transparent";
4077
4161
  }
4078
4162
  el.addEventListener("click", (e) => {
4079
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("click", node, e));
4163
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("click", node, e));
4080
4164
  });
4081
4165
  el.addEventListener("dblclick", (e) => {
4082
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("dblclick", node, e));
4166
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("dblclick", node, e));
4083
4167
  });
4084
4168
  el.addEventListener("mouseenter", (e) => {
4085
4169
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.2)";
4086
4170
  this.hoveredA11yElements.add(el);
4087
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("hover", node, e, false));
4171
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("hover", node, e, false));
4088
4172
  });
4089
4173
  el.addEventListener("mouseleave", (e) => {
4090
4174
  if (this.debugA11y) el.style.backgroundColor = "rgba(56, 189, 248, 0.05)";
4091
4175
  this.hoveredA11yElements.delete(el);
4092
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("pointerleave", node, e, false));
4176
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("pointerleave", node, e, false));
4093
4177
  });
4094
4178
  const capEl = el;
4095
4179
  const releasePointer = (event) => {
@@ -4105,24 +4189,24 @@ var Scene = (_class7 = class _Scene {
4105
4189
  };
4106
4190
  el.addEventListener("pointerdown", (e) => {
4107
4191
  if (typeof capEl.setPointerCapture === "function") capEl.setPointerCapture(e.pointerId);
4108
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("pointerdown", node, e));
4192
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("pointerdown", node, e));
4109
4193
  });
4110
4194
  el.addEventListener("pointerup", (e) => {
4111
4195
  releasePointer(e);
4112
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("pointerup", node, e));
4196
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("pointerup", node, e));
4113
4197
  });
4114
4198
  el.addEventListener("pointercancel", (e) => {
4115
4199
  releasePointer(e);
4116
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("pointercancel", node, e));
4200
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("pointercancel", node, e));
4117
4201
  });
4118
4202
  el.addEventListener(
4119
4203
  "pointermove",
4120
- (e) => node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("pointermove", node, e))
4204
+ (e) => node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("pointermove", node, e))
4121
4205
  );
4122
4206
  el.addEventListener(
4123
4207
  "wheel",
4124
4208
  (e) => {
4125
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("wheel", node, e));
4209
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("wheel", node, e));
4126
4210
  },
4127
4211
  { passive: false }
4128
4212
  );
@@ -4147,10 +4231,10 @@ var Scene = (_class7 = class _Scene {
4147
4231
  );
4148
4232
  emitInitialScroll = emitScroll;
4149
4233
  el.addEventListener("keydown", (e) => {
4150
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("keydown", node, e));
4234
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("keydown", node, e));
4151
4235
  });
4152
4236
  el.addEventListener("keyup", (e) => {
4153
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("keyup", node, e));
4237
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("keyup", node, e));
4154
4238
  });
4155
4239
  if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
4156
4240
  const input = el;
@@ -4216,7 +4300,7 @@ var Scene = (_class7 = class _Scene {
4216
4300
  el.addEventListener("keydown", (e) => {
4217
4301
  if (e.key === "Enter" || e.key === " ") {
4218
4302
  e.preventDefault();
4219
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("click", node, e));
4303
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("click", node, e));
4220
4304
  }
4221
4305
  });
4222
4306
  }
@@ -4443,7 +4527,9 @@ var Scene = (_class7 = class _Scene {
4443
4527
  * transparent DOM node positioned over the drawn glyphs. Runs on the a11y
4444
4528
  * sync cadence; all writes are dirty-checked. Off-viewport projections are
4445
4529
  * hidden (`display: none`) so text-heavy scenes only materialize what is
4446
- * visible to the browser's text machinery anyway.
4530
+ * visible to the browser's text machinery anyway — except in the coarse
4531
+ * (resident) tier, which stays displayed because hiding it would make its text
4532
+ * unfindable and remove it from the accessibility tree, defeating the tier.
4447
4533
  */
4448
4534
  /**
4449
4535
  * Whether `node`'s world-space box, expanded by `margin` px on every side,
@@ -4452,8 +4538,15 @@ var Scene = (_class7 = class _Scene {
4452
4538
  * at `margin = contentProjectionMargin`) and for the exact `display:none`
4453
4539
  * visibility test (`margin = 0`). Boundless nodes (width/height 0) opt out of
4454
4540
  * culling and always count as visible, matching the legacy behavior.
4541
+ *
4542
+ * `viewportOnly` skips the `clipChildren` ancestor walk, answering the narrower
4543
+ * question "does this box overlap the viewport at all". The coarse content tier
4544
+ * needs the two apart: text that is merely off-viewport is clipped by
4545
+ * `a11yRoot`'s own `overflow: hidden` and can safely stay displayed, while text
4546
+ * rejected by an ancestor clip box that itself overlaps the viewport would sit
4547
+ * transparently on top of whatever is really drawn there.
4455
4548
  */
4456
- projectionBoxVisible(node, tf, margin) {
4549
+ projectionBoxVisible(node, tf, margin, viewportOnly = false) {
4457
4550
  if (!(node.width > 0 && node.height > 0)) return true;
4458
4551
  const { a, b, c, d, e, f } = tf;
4459
4552
  const worldCorners = [];
@@ -4475,6 +4568,7 @@ var Scene = (_class7 = class _Scene {
4475
4568
  if (!(maxX >= -margin && minX <= this.width + margin && maxY >= -margin && minY <= this.height + margin)) {
4476
4569
  return false;
4477
4570
  }
4571
+ if (viewportOnly) return true;
4478
4572
  for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
4479
4573
  if (!ancestor.clipChildren || ancestor.width <= 0 || ancestor.height <= 0) continue;
4480
4574
  let localMinX = Infinity;
@@ -4556,14 +4650,31 @@ var Scene = (_class7 = class _Scene {
4556
4650
  this.contentElements.delete(node.id);
4557
4651
  this.a11yNeedsReorder = true;
4558
4652
  }
4653
+ this.contentSyncState.delete(node.id);
4559
4654
  };
4560
4655
  const worldTf = node.getWorldTransform();
4561
- const margin = _nullishCoalesce(this.contentProjectionMargin, () => ( this.height));
4562
- if (Number.isFinite(margin) && !this.projectionBoxVisible(node, worldTf, margin)) {
4656
+ const interactionMargin = _nullishCoalesce(this.contentProjectionMargin, () => ( this.height));
4657
+ const semanticMargin = _nullishCoalesce(this.contentSemanticMargin, () => ( interactionMargin));
4658
+ if (Number.isFinite(semanticMargin) && !this.projectionBoxVisible(node, worldTf, semanticMargin)) {
4563
4659
  releaseProjectionEl();
4564
4660
  return;
4565
4661
  }
4566
- const lineBand = Number.isFinite(margin) ? this.projectionVisibleLocalYBand(node, worldTf, margin) : null;
4662
+ const inInteractionBand = !Number.isFinite(interactionMargin) || this.projectionBoxVisible(node, worldTf, interactionMargin);
4663
+ const tier = inInteractionBand ? "fine" : "coarse";
4664
+ const lineBand = tier === "coarse" ? null : Number.isFinite(interactionMargin) ? this.projectionVisibleLocalYBand(node, worldTf, interactionMargin) : null;
4665
+ const visible = this.projectionBoxVisible(node, worldTf, 0);
4666
+ const epoch = node.getContentEpoch();
4667
+ const prior = this.contentSyncState.get(node.id);
4668
+ if (epoch !== null && el && prior !== void 0) {
4669
+ const { a: a2, b: b2, c: c2, d: d2, e: e2, f: f2 } = worldTf;
4670
+ if (prior.epoch === epoch && prior.fontEpoch === this.contentFontEpoch && prior.a === a2 && prior.b === b2 && prior.c === c2 && prior.d === d2 && prior.e === e2 && prior.f === f2 && prior.tier === tier && prior.hasBand === (lineBand !== null) && (lineBand === null || prior.bandMin === lineBand.minY && prior.bandMax === lineBand.maxY) && prior.visible === visible && prior.width === node.width && prior.height === node.height && prior.interactive === node.interactive) {
4671
+ return;
4672
+ }
4673
+ }
4674
+ if (tier === "coarse" && !el && this.contentSemanticBudgetLeft <= 0) {
4675
+ this.contentSemanticDeferred = true;
4676
+ return;
4677
+ }
4567
4678
  const projection = node.getContentProjection(
4568
4679
  lineBand ? { minY: lineBand.minY, maxY: lineBand.maxY } : void 0
4569
4680
  );
@@ -4572,6 +4683,7 @@ var Scene = (_class7 = class _Scene {
4572
4683
  return;
4573
4684
  }
4574
4685
  if (!el) {
4686
+ if (tier === "coarse") this.contentSemanticBudgetLeft--;
4575
4687
  el = document.createElement("div");
4576
4688
  el.setAttribute("data-vecto-content", node.id);
4577
4689
  const s = el.style;
@@ -4587,7 +4699,7 @@ var Scene = (_class7 = class _Scene {
4587
4699
  el.addEventListener(
4588
4700
  "wheel",
4589
4701
  (e2) => {
4590
- node.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)("wheel", node, e2));
4702
+ node.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)("wheel", node, e2));
4591
4703
  },
4592
4704
  { passive: false }
4593
4705
  );
@@ -4596,14 +4708,15 @@ var Scene = (_class7 = class _Scene {
4596
4708
  this.a11yNeedsReorder = true;
4597
4709
  }
4598
4710
  const lines = projection.lines;
4599
- if (!projection.grid && el.dataset.vectoContentGrid !== void 0) {
4711
+ const useCarriers = tier === "fine";
4712
+ if ((!projection.grid || !useCarriers) && el.dataset.vectoContentGrid !== void 0) {
4600
4713
  this.clearContentGridState(node.id, el);
4601
4714
  }
4602
- if (projection.grid) {
4715
+ if (projection.grid && useCarriers) {
4603
4716
  const gridSyncStart = this._phaseTiming ? performance.now() : 0;
4604
4717
  this.syncContentGridProjection(node, el, projection, projection.grid, lineBand);
4605
4718
  if (this._phaseTiming) this._recordPhase("gridSync", performance.now() - gridSyncStart);
4606
- } else if (lines && lines.length > 0) {
4719
+ } else if (useCarriers && lines && lines.length > 0) {
4607
4720
  const lineWindow = projectionLineWindow(lines, lineBand, _nullishCoalesce(projection.lineHeight, () => ( 16)));
4608
4721
  const signature = JSON.stringify({
4609
4722
  lines,
@@ -4666,11 +4779,13 @@ var Scene = (_class7 = class _Scene {
4666
4779
  }
4667
4780
  }
4668
4781
  } else {
4669
- if (el.textContent !== projection.text) {
4782
+ const demoted = tier === "coarse" && el.children.length > 0;
4783
+ if (el.textContent !== projection.text || demoted) {
4670
4784
  this.releaseContentSelectionForRebuild(el);
4671
4785
  el.textContent = projection.text;
4672
4786
  }
4673
4787
  delete el.dataset.vectoProjectionLines;
4788
+ if (tier === "coarse") delete el.dataset.vectoProjectionWindow;
4674
4789
  }
4675
4790
  const font = _nullishCoalesce(projection.font, () => ( ""));
4676
4791
  if (el.style.font !== font) el.style.font = font;
@@ -4703,9 +4818,30 @@ var Scene = (_class7 = class _Scene {
4703
4818
  if (node.width > 0) el.style.width = `${node.width}px`;
4704
4819
  if (node.height > 0) el.style.height = `${node.height}px`;
4705
4820
  el.style.transform = `matrix(${a}, ${b}, ${c}, ${d}, 0, 0)`;
4706
- const visible = this.projectionBoxVisible(node, worldTf, 0);
4707
- const display = visible ? "" : "none";
4821
+ const residentTier = semanticMargin > interactionMargin;
4822
+ const display = visible || residentTier && !this.projectionBoxVisible(node, worldTf, 0, true) ? "" : "none";
4708
4823
  if (el.style.display !== display) el.style.display = display;
4824
+ if (epoch !== null) {
4825
+ const { a: a2, b: b2, c: c2, d: d2, e: e2, f: f2 } = worldTf;
4826
+ const next = _nullishCoalesce(prior, () => ( {}));
4827
+ next.epoch = epoch;
4828
+ next.fontEpoch = this.contentFontEpoch;
4829
+ next.a = a2;
4830
+ next.b = b2;
4831
+ next.c = c2;
4832
+ next.d = d2;
4833
+ next.e = e2;
4834
+ next.f = f2;
4835
+ next.tier = tier;
4836
+ next.hasBand = lineBand !== null;
4837
+ next.bandMin = _nullishCoalesce(_optionalChain([lineBand, 'optionalAccess', _132 => _132.minY]), () => ( 0));
4838
+ next.bandMax = _nullishCoalesce(_optionalChain([lineBand, 'optionalAccess', _133 => _133.maxY]), () => ( 0));
4839
+ next.visible = visible;
4840
+ next.width = node.width;
4841
+ next.height = node.height;
4842
+ next.interactive = node.interactive;
4843
+ if (prior === void 0) this.contentSyncState.set(node.id, next);
4844
+ }
4709
4845
  }
4710
4846
  /**
4711
4847
  * Materialize a prepared grid in logical source order while positioning each
@@ -4729,9 +4865,9 @@ var Scene = (_class7 = class _Scene {
4729
4865
  const domIndex = lineIndex - gridWindow.start;
4730
4866
  const gridLine = grid.lines[lineIndex];
4731
4867
  const projectedLine = projectionLines[lineIndex];
4732
- const lineHeight = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _132 => _132.lineHeight]), () => ( grid.lineHeight));
4733
- const baseline = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _133 => _133.baseline]), () => ( grid.baseline));
4734
- const lineFont = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _134 => _134.font]), () => ( grid.font));
4868
+ const lineHeight = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _134 => _134.lineHeight]), () => ( grid.lineHeight));
4869
+ const baseline = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _135 => _135.baseline]), () => ( grid.baseline));
4870
+ const lineFont = _nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _136 => _136.font]), () => ( grid.font));
4735
4871
  const lineSignature = contentGridLineSignature(
4736
4872
  grid,
4737
4873
  gridLine,
@@ -4751,8 +4887,8 @@ var Scene = (_class7 = class _Scene {
4751
4887
  lineElement.dir = "ltr";
4752
4888
  lineElement.dataset.vectoGridLine = `${lineIndex}`;
4753
4889
  lineElement.style.position = "absolute";
4754
- lineElement.style.left = `${_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _135 => _135.x]), () => ( 0))}px`;
4755
- lineElement.style.top = `${(_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _136 => _136.y]), () => ( lineIndex * grid.lineHeight))) + baseline - _text.cssLineBoxBaseline.call(void 0, lineFont, lineHeight)}px`;
4890
+ lineElement.style.left = `${_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _137 => _137.x]), () => ( 0))}px`;
4891
+ lineElement.style.top = `${(_nullishCoalesce(_optionalChain([projectedLine, 'optionalAccess', _138 => _138.y]), () => ( lineIndex * grid.lineHeight))) + baseline - _text.cssLineBoxBaseline.call(void 0, lineFont, lineHeight)}px`;
4756
4892
  lineElement.style.width = `${gridLine.width}px`;
4757
4893
  lineElement.style.height = `${lineHeight}px`;
4758
4894
  lineElement.style.whiteSpace = "pre";
@@ -4823,7 +4959,7 @@ var Scene = (_class7 = class _Scene {
4823
4959
  if (selectionLine !== null && selectionLine >= gridWindow.end) {
4824
4960
  rebuiltSelectionLine = true;
4825
4961
  }
4826
- _optionalChain([el, 'access', _137 => _137.lastElementChild, 'optionalAccess', _138 => _138.remove, 'call', _139 => _139()]);
4962
+ _optionalChain([el, 'access', _139 => _139.lastElementChild, 'optionalAccess', _140 => _140.remove, 'call', _141 => _141()]);
4827
4963
  }
4828
4964
  if (rebuiltSelectionLine) this.releaseContentSelectionForRebuild(el);
4829
4965
  el.dataset.vectoProjectionLines = signature;
@@ -4892,7 +5028,7 @@ var Scene = (_class7 = class _Scene {
4892
5028
  if (previous !== void 0 && typeof cancelAnimationFrame === "function") {
4893
5029
  cancelAnimationFrame(previous);
4894
5030
  }
4895
- _optionalChain([this, 'access', _140 => _140.contentGridCalibrationProbes, 'access', _141 => _141.get, 'call', _142 => _142(entityId), 'optionalAccess', _143 => _143.remove, 'call', _144 => _144()]);
5031
+ _optionalChain([this, 'access', _142 => _142.contentGridCalibrationProbes, 'access', _143 => _143.get, 'call', _144 => _144(entityId), 'optionalAccess', _145 => _145.remove, 'call', _146 => _146()]);
4896
5032
  this.contentGridCalibrationProbes.delete(entityId);
4897
5033
  const calibrationStart = typeof performance !== "undefined" ? performance.now() : 0;
4898
5034
  const probe = document.createElement("div");
@@ -4926,7 +5062,7 @@ var Scene = (_class7 = class _Scene {
4926
5062
  target.dataset.vectoGridCalib = generation;
4927
5063
  continue;
4928
5064
  }
4929
- const sourceText = _nullishCoalesce(_optionalChain([target, 'access', _145 => _145.textContent, 'optionalAccess', _146 => _146.slice, 'call', _147 => _147(0, sourceLength)]), () => ( ""));
5065
+ const sourceText = _nullishCoalesce(_optionalChain([target, 'access', _147 => _147.textContent, 'optionalAccess', _148 => _148.slice, 'call', _149 => _149(0, sourceLength)]), () => ( ""));
4930
5066
  if (!sourceText) {
4931
5067
  target.dataset.vectoGridCalib = generation;
4932
5068
  continue;
@@ -5173,12 +5309,12 @@ var Scene = (_class7 = class _Scene {
5173
5309
  syncOverlayGeometry() {
5174
5310
  const parent = this.canvas.parentElement;
5175
5311
  if (!parent) return;
5176
- const canvasRect = _optionalChain([this, 'access', _148 => _148.canvas, 'access', _149 => _149.getBoundingClientRect, 'optionalCall', _150 => _150()]);
5177
- const parentRect = _optionalChain([parent, 'access', _151 => _151.getBoundingClientRect, 'optionalCall', _152 => _152()]);
5178
- const cssWidth = _optionalChain([canvasRect, 'optionalAccess', _153 => _153.width]) || this.canvas.clientWidth || this.width;
5179
- const cssHeight = _optionalChain([canvasRect, 'optionalAccess', _154 => _154.height]) || this.canvas.clientHeight || this.height;
5180
- const left = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _155 => _155.left]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _156 => _156.left]), () => ( 0))) - (parent.clientLeft || 0) + parent.scrollLeft;
5181
- const top = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _157 => _157.top]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _158 => _158.top]), () => ( 0))) - (parent.clientTop || 0) + parent.scrollTop;
5312
+ const canvasRect = _optionalChain([this, 'access', _150 => _150.canvas, 'access', _151 => _151.getBoundingClientRect, 'optionalCall', _152 => _152()]);
5313
+ const parentRect = _optionalChain([parent, 'access', _153 => _153.getBoundingClientRect, 'optionalCall', _154 => _154()]);
5314
+ const cssWidth = _optionalChain([canvasRect, 'optionalAccess', _155 => _155.width]) || this.canvas.clientWidth || this.width;
5315
+ const cssHeight = _optionalChain([canvasRect, 'optionalAccess', _156 => _156.height]) || this.canvas.clientHeight || this.height;
5316
+ const left = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _157 => _157.left]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _158 => _158.left]), () => ( 0))) - (parent.clientLeft || 0) + parent.scrollLeft;
5317
+ const top = (_nullishCoalesce(_optionalChain([canvasRect, 'optionalAccess', _159 => _159.top]), () => ( 0))) - (_nullishCoalesce(_optionalChain([parentRect, 'optionalAccess', _160 => _160.top]), () => ( 0))) - (parent.clientTop || 0) + parent.scrollTop;
5182
5318
  const scaleX = this.width > 0 ? cssWidth / this.width : 1;
5183
5319
  const scaleY = this.height > 0 ? cssHeight / this.height : 1;
5184
5320
  const prev = this._overlayGeometry;
@@ -5317,7 +5453,7 @@ var Scene = (_class7 = class _Scene {
5317
5453
  * (and {@link respectReducedMotion} is on). `0` means uncapped.
5318
5454
  */
5319
5455
  effectiveMaxFPS() {
5320
- const reduced = this.respectReducedMotion && !!_optionalChain([this, 'access', _159 => _159.reducedMotionQuery, 'optionalAccess', _160 => _160.matches]);
5456
+ const reduced = this.respectReducedMotion && !!_optionalChain([this, 'access', _161 => _161.reducedMotionQuery, 'optionalAccess', _162 => _162.matches]);
5321
5457
  if (reduced)
5322
5458
  return this.maxFPS > 0 ? Math.min(this.maxFPS, REDUCED_MOTION_FPS) : REDUCED_MOTION_FPS;
5323
5459
  return this.maxFPS;
@@ -5326,7 +5462,7 @@ var Scene = (_class7 = class _Scene {
5326
5462
  if (!this.isRunning) return;
5327
5463
  if (!this._canvasOnScreen) return;
5328
5464
  let cap = this.effectiveMaxFPS();
5329
- const isIdle = !this.dirty && !this.frameHadAnimation;
5465
+ const isIdle = !this.dirty && !this.frameHadAnimation && !this.contentSemanticDeferred;
5330
5466
  if (isIdle && this.autoThrottle && this.renderMode === "always" && this.maxFPS > 0) {
5331
5467
  cap = Math.min(cap, 2);
5332
5468
  }
@@ -5412,7 +5548,7 @@ var Scene = (_class7 = class _Scene {
5412
5548
  * @param time - Current absolute time in milliseconds (default 0).
5413
5549
  */
5414
5550
  render(renderer, dt = 0, time = 0) {
5415
- if (_optionalChain([renderer, 'access', _161 => _161.isContextLost, 'optionalCall', _162 => _162()])) return;
5551
+ if (_optionalChain([renderer, 'access', _163 => _163.isContextLost, 'optionalCall', _164 => _164()])) return;
5416
5552
  const isMainRenderer = renderer === this.renderer;
5417
5553
  if (isMainRenderer && this.a11yRoot && this.canvas.parentElement) {
5418
5554
  const parentStyle = this.canvas.parentElement.style;
@@ -5556,14 +5692,14 @@ var Scene = (_class7 = class _Scene {
5556
5692
  }
5557
5693
  renderer.clear();
5558
5694
  if (isMainRenderer) {
5559
- _optionalChain([this, 'access', _163 => _163.pointRenderer, 'optionalAccess', _164 => _164.begin, 'call', _165 => _165()]);
5695
+ _optionalChain([this, 'access', _165 => _165.pointRenderer, 'optionalAccess', _166 => _166.begin, 'call', _167 => _167()]);
5560
5696
  }
5561
5697
  const vw = this.width;
5562
5698
  const vh = this.height;
5563
5699
  let walkHadAnimation = false;
5564
5700
  let walkHadInteractive = false;
5565
5701
  const runUpdate = (node) => {
5566
- const overridesUpdate = node.update !== _chunk7PI7LVWWjs.Entity.prototype.update;
5702
+ const overridesUpdate = node.update !== _chunkTRT2TRCWjs.Entity.prototype.update;
5567
5703
  let pending = node.hasPendingAnimations();
5568
5704
  if (pending || overridesUpdate) {
5569
5705
  node.update(dt, time);
@@ -5572,7 +5708,7 @@ var Scene = (_class7 = class _Scene {
5572
5708
  if (pending) walkHadAnimation = true;
5573
5709
  if (!walkHadInteractive && node.interactive) walkHadInteractive = true;
5574
5710
  if (this._devActive && this._devFrameCount % 120 === 0) {
5575
- if (overridesUpdate && node.hasPendingAnimations === _chunk7PI7LVWWjs.Entity.prototype.hasPendingAnimations) {
5711
+ if (overridesUpdate && node.hasPendingAnimations === _chunkTRT2TRCWjs.Entity.prototype.hasPendingAnimations) {
5576
5712
  this._devWarn(
5577
5713
  `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.`
5578
5714
  );
@@ -5770,9 +5906,9 @@ var Scene = (_class7 = class _Scene {
5770
5906
  const flushT0 = this._phaseTiming ? performance.now() : 0;
5771
5907
  renderer.flush();
5772
5908
  if (isMainRenderer) {
5773
- _optionalChain([this, 'access', _166 => _166.pointRenderer, 'optionalAccess', _167 => _167.flush, 'call', _168 => _168()]);
5909
+ _optionalChain([this, 'access', _168 => _168.pointRenderer, 'optionalAccess', _169 => _169.flush, 'call', _170 => _170()]);
5774
5910
  }
5775
- _optionalChain([renderer, 'access', _169 => _169.present, 'optionalCall', _170 => _170()]);
5911
+ _optionalChain([renderer, 'access', _171 => _171.present, 'optionalCall', _172 => _172()]);
5776
5912
  if (this._phaseTiming) this._recordPhase("flush", performance.now() - flushT0);
5777
5913
  if (flushTiming) endVectoUserTiming(flushTiming);
5778
5914
  if (this._devActive) {
@@ -6053,8 +6189,8 @@ function pointInBounds(b, x, y) {
6053
6189
  function contentGridLineSignature(grid, line, projected, lineHeight, baseline, font, isFirstLine) {
6054
6190
  const parts = [
6055
6191
  // Line box: position, size, and the font that resolves its baseline.
6056
- `${_nullishCoalesce(_optionalChain([projected, 'optionalAccess', _171 => _171.x]), () => ( 0))}`,
6057
- `${_nullishCoalesce(_optionalChain([projected, 'optionalAccess', _172 => _172.y]), () => ( ""))}`,
6192
+ `${_nullishCoalesce(_optionalChain([projected, 'optionalAccess', _173 => _173.x]), () => ( 0))}`,
6193
+ `${_nullishCoalesce(_optionalChain([projected, 'optionalAccess', _174 => _174.y]), () => ( ""))}`,
6058
6194
  `${lineHeight}`,
6059
6195
  `${baseline}`,
6060
6196
  font,
@@ -6096,20 +6232,22 @@ function defaultMeasurer() {
6096
6232
  sharedMeasurer ??= _layout.resolveGlyphMeasurer.call(void 0, "sans-serif");
6097
6233
  return sharedMeasurer;
6098
6234
  }
6099
- var TextEntity = (_class8 = class extends _chunk7PI7LVWWjs.Entity {
6235
+ var TextEntity = (_class8 = class extends _chunkTRT2TRCWjs.Entity {
6100
6236
 
6101
6237
 
6102
6238
 
6103
6239
 
6104
- __init152() {this.nodes = []}
6240
+ __init158() {this.nodes = []}
6105
6241
 
6106
- __init153() {this.fillStyle = "#94a3b8"}
6107
- __init154() {this.strokeStyle = null}
6108
- __init155() {this.hoveredFillStyle = "#ffffff"}
6109
- __init156() {this.lineWidth = 1}
6110
- __init157() {this.isHovered = false}
6242
+ __init159() {this.fillStyle = "#94a3b8"}
6243
+ __init160() {this.strokeStyle = null}
6244
+ __init161() {this.hoveredFillStyle = "#ffffff"}
6245
+ __init162() {this.lineWidth = 1}
6246
+ __init163() {this.isHovered = false}
6247
+ /** Bumped by {@link applyLayout}; read by `Scene` to skip an unchanged sync. */
6248
+ __init164() {this.contentEpoch = 0}
6111
6249
  constructor(text, atlas, maxWidth, fontSize = 24) {
6112
- super();_class8.prototype.__init152.call(this);_class8.prototype.__init153.call(this);_class8.prototype.__init154.call(this);_class8.prototype.__init155.call(this);_class8.prototype.__init156.call(this);_class8.prototype.__init157.call(this);;
6250
+ super();_class8.prototype.__init158.call(this);_class8.prototype.__init159.call(this);_class8.prototype.__init160.call(this);_class8.prototype.__init161.call(this);_class8.prototype.__init162.call(this);_class8.prototype.__init163.call(this);_class8.prototype.__init164.call(this);;
6113
6251
  this.text = text;
6114
6252
  this.atlas = atlas;
6115
6253
  this.fontSize = fontSize;
@@ -6128,6 +6266,9 @@ var TextEntity = (_class8 = class extends _chunk7PI7LVWWjs.Entity {
6128
6266
  if (!this.text) return null;
6129
6267
  return { text: this.text, font: `${this.fontSize}px sans-serif` };
6130
6268
  }
6269
+ getContentEpoch() {
6270
+ return this.contentEpoch;
6271
+ }
6131
6272
  /**
6132
6273
  * Replace the text content. Runs the **cold** measurement pass (re-segment +
6133
6274
  * re-measure) since the glyphs changed, then re-lays out.
@@ -6174,6 +6315,7 @@ var TextEntity = (_class8 = class extends _chunk7PI7LVWWjs.Entity {
6174
6315
  }
6175
6316
  /** Hot pass: place the cached {@link PreparedText} and refresh the a11y box. */
6176
6317
  applyLayout() {
6318
+ this.contentEpoch++;
6177
6319
  const result = this.layout.layoutPrepared(this.prepared);
6178
6320
  this.nodes = result.nodes;
6179
6321
  this.width = result.totalWidth;
@@ -6222,17 +6364,17 @@ var TextEntity = (_class8 = class extends _chunk7PI7LVWWjs.Entity {
6222
6364
  }, _class8);
6223
6365
 
6224
6366
  // src/components/GridTextEntity.ts
6225
- var GridTextEntity = (_class9 = class extends _chunk7PI7LVWWjs.Entity {
6367
+ var GridTextEntity = (_class9 = class extends _chunkTRT2TRCWjs.Entity {
6226
6368
 
6227
- __init158() {this.fillStyle = "#ffffff"}
6228
- __init159() {this.grid = []}
6369
+ __init165() {this.fillStyle = "#ffffff"}
6370
+ __init166() {this.grid = []}
6229
6371
  // Array of rows
6230
- __init160() {this.cols = 0}
6231
- __init161() {this.rows = 0}
6372
+ __init167() {this.cols = 0}
6373
+ __init168() {this.rows = 0}
6232
6374
 
6233
6375
 
6234
6376
  constructor(_atlas, fontSize = 10) {
6235
- super();_class9.prototype.__init158.call(this);_class9.prototype.__init159.call(this);_class9.prototype.__init160.call(this);_class9.prototype.__init161.call(this);;
6377
+ super();_class9.prototype.__init165.call(this);_class9.prototype.__init166.call(this);_class9.prototype.__init167.call(this);_class9.prototype.__init168.call(this);;
6236
6378
  this.fontSize = fontSize;
6237
6379
  this.charWidth = fontSize * 1;
6238
6380
  this.charHeight = fontSize * 1.1;
@@ -6241,7 +6383,7 @@ var GridTextEntity = (_class9 = class extends _chunk7PI7LVWWjs.Entity {
6241
6383
  updateGrid(ascii) {
6242
6384
  this.grid = ascii;
6243
6385
  this.rows = ascii.length;
6244
- this.cols = _optionalChain([ascii, 'access', _173 => _173[0], 'optionalAccess', _174 => _174.length]) || 0;
6386
+ this.cols = _optionalChain([ascii, 'access', _175 => _175[0], 'optionalAccess', _176 => _176.length]) || 0;
6245
6387
  }
6246
6388
  isPointInside(_globalX, _globalY) {
6247
6389
  return false;
@@ -6316,7 +6458,7 @@ function distSqToSegment(px, py, x1, y1, x2, y2) {
6316
6458
  const ey = py - cy;
6317
6459
  return ex * ex + ey * ey;
6318
6460
  }
6319
- var SplineEntity = (_class10 = class extends _chunk7PI7LVWWjs.Entity {
6461
+ var SplineEntity = (_class10 = class extends _chunkTRT2TRCWjs.Entity {
6320
6462
 
6321
6463
 
6322
6464
 
@@ -6324,23 +6466,23 @@ var SplineEntity = (_class10 = class extends _chunk7PI7LVWWjs.Entity {
6324
6466
 
6325
6467
 
6326
6468
 
6327
- __init162() {this.offscreen = null}
6328
- __init163() {this.baked = false}
6469
+ __init169() {this.offscreen = null}
6470
+ __init170() {this.baked = false}
6329
6471
  /** Logical (CSS-pixel) size of the baked bitmap — the blit destination size. */
6330
- __init164() {this.bakedWidth = 0}
6331
- __init165() {this.bakedHeight = 0}
6472
+ __init171() {this.bakedWidth = 0}
6473
+ __init172() {this.bakedHeight = 0}
6332
6474
  /** Gradient strokes can't be baked to a solid-color bitmap; they render per-frame. */
6333
6475
 
6334
6476
  /** Lazily-flattened polylines (one Float32Array of [x,y,...] per segment) for hit-testing. */
6335
- __init166() {this.polylines = null}
6477
+ __init173() {this.polylines = null}
6336
6478
  /**
6337
6479
  * When `true`, the renderer draws a rounded-rect outline of the entity's
6338
6480
  * local bounds after painting the curves. Useful for drag feedback and
6339
6481
  * debugging hit areas. Defaults to `false`.
6340
6482
  */
6341
- __init167() {this.showBounds = false}
6483
+ __init174() {this.showBounds = false}
6342
6484
  constructor(doc, opts = {}) {
6343
- super();_class10.prototype.__init162.call(this);_class10.prototype.__init163.call(this);_class10.prototype.__init164.call(this);_class10.prototype.__init165.call(this);_class10.prototype.__init166.call(this);_class10.prototype.__init167.call(this);;
6485
+ super();_class10.prototype.__init169.call(this);_class10.prototype.__init170.call(this);_class10.prototype.__init171.call(this);_class10.prototype.__init172.call(this);_class10.prototype.__init173.call(this);_class10.prototype.__init174.call(this);;
6344
6486
  this.doc = doc;
6345
6487
  this.lineWidth = _nullishCoalesce(opts.lineWidth, () => ( 2));
6346
6488
  this.cache = _nullishCoalesce(opts.cache, () => ( true));
@@ -6351,7 +6493,7 @@ var SplineEntity = (_class10 = class extends _chunk7PI7LVWWjs.Entity {
6351
6493
  this.width = this.bounds.width;
6352
6494
  this.height = this.bounds.height;
6353
6495
  const isGradient = (c) => c !== null && !Array.isArray(c);
6354
- this.containsGradient = (_nullishCoalesce(_optionalChain([this, 'access', _175 => _175.doc, 'access', _176 => _176.equations, 'optionalAccess', _177 => _177.some, 'call', _178 => _178((eq) => isGradient(eq.color_rgb))]), () => ( false))) || (_nullishCoalesce(_optionalChain([this, 'access', _179 => _179.doc, 'access', _180 => _180.paths, 'optionalAccess', _181 => _181.some, 'call', _182 => _182((p) => isGradient(p.color_rgb))]), () => ( false)));
6496
+ this.containsGradient = (_nullishCoalesce(_optionalChain([this, 'access', _177 => _177.doc, 'access', _178 => _178.equations, 'optionalAccess', _179 => _179.some, 'call', _180 => _180((eq) => isGradient(eq.color_rgb))]), () => ( false))) || (_nullishCoalesce(_optionalChain([this, 'access', _181 => _181.doc, 'access', _182 => _182.paths, 'optionalAccess', _183 => _183.some, 'call', _184 => _184((p) => isGradient(p.color_rgb))]), () => ( false)));
6355
6497
  this.interactive = true;
6356
6498
  }
6357
6499
  computeBounds() {
@@ -6591,7 +6733,7 @@ async function loadSpline(url) {
6591
6733
  }
6592
6734
 
6593
6735
  // src/components/Rect.ts
6594
- var Rect = class extends _chunk7PI7LVWWjs.Entity {
6736
+ var Rect = class extends _chunkTRT2TRCWjs.Entity {
6595
6737
 
6596
6738
 
6597
6739
 
@@ -6640,7 +6782,7 @@ var Rect = class extends _chunk7PI7LVWWjs.Entity {
6640
6782
  };
6641
6783
 
6642
6784
  // src/components/Circle.ts
6643
- var Circle = class extends _chunk7PI7LVWWjs.Entity {
6785
+ var Circle = class extends _chunkTRT2TRCWjs.Entity {
6644
6786
 
6645
6787
 
6646
6788
 
@@ -6700,7 +6842,7 @@ var Circle = class extends _chunk7PI7LVWWjs.Entity {
6700
6842
  };
6701
6843
 
6702
6844
  // src/components/Group.ts
6703
- var Group = class extends _chunk7PI7LVWWjs.Entity {
6845
+ var Group = class extends _chunkTRT2TRCWjs.Entity {
6704
6846
  constructor(...children) {
6705
6847
  super();
6706
6848
  if (children.length > 0) this.add(...children);
@@ -6719,21 +6861,21 @@ var _math = require('@vectojs/math'); _createStarExport(_math);
6719
6861
 
6720
6862
 
6721
6863
  // src/tree/DOMPortalEntity.ts
6722
- var DOMPortalEntity = (_class11 = class extends _chunk7PI7LVWWjs.Entity {
6864
+ var DOMPortalEntity = (_class11 = class extends _chunkTRT2TRCWjs.Entity {
6723
6865
 
6724
- __init168() {this.isDOMPortal = true}
6725
- __init169() {this.domListeners = []}
6726
- __init170() {this.resizeObserver = null}
6727
- __init171() {this.domBound = false}
6728
- __init172() {this.cachedWidth = 100}
6729
- __init173() {this.cachedHeight = 100}
6730
- __init174() {this.lastWidth = ""}
6731
- __init175() {this.lastHeight = ""}
6732
- __init176() {this.lastTransform = ""}
6733
- __init177() {this.lastZIndex = ""}
6734
- __init178() {this.lastOpacity = ""}
6866
+ __init175() {this.isDOMPortal = true}
6867
+ __init176() {this.domListeners = []}
6868
+ __init177() {this.resizeObserver = null}
6869
+ __init178() {this.domBound = false}
6870
+ __init179() {this.cachedWidth = 100}
6871
+ __init180() {this.cachedHeight = 100}
6872
+ __init181() {this.lastWidth = ""}
6873
+ __init182() {this.lastHeight = ""}
6874
+ __init183() {this.lastTransform = ""}
6875
+ __init184() {this.lastZIndex = ""}
6876
+ __init185() {this.lastOpacity = ""}
6735
6877
  constructor(domElement, width, height, id) {
6736
- super(id);_class11.prototype.__init168.call(this);_class11.prototype.__init169.call(this);_class11.prototype.__init170.call(this);_class11.prototype.__init171.call(this);_class11.prototype.__init172.call(this);_class11.prototype.__init173.call(this);_class11.prototype.__init174.call(this);_class11.prototype.__init175.call(this);_class11.prototype.__init176.call(this);_class11.prototype.__init177.call(this);_class11.prototype.__init178.call(this);;
6878
+ super(id);_class11.prototype.__init175.call(this);_class11.prototype.__init176.call(this);_class11.prototype.__init177.call(this);_class11.prototype.__init178.call(this);_class11.prototype.__init179.call(this);_class11.prototype.__init180.call(this);_class11.prototype.__init181.call(this);_class11.prototype.__init182.call(this);_class11.prototype.__init183.call(this);_class11.prototype.__init184.call(this);_class11.prototype.__init185.call(this);;
6737
6879
  this.domElement = domElement;
6738
6880
  this.width = _nullishCoalesce(width, () => ( 0));
6739
6881
  this.height = _nullishCoalesce(height, () => ( 0));
@@ -6775,7 +6917,7 @@ var DOMPortalEntity = (_class11 = class extends _chunk7PI7LVWWjs.Entity {
6775
6917
  ];
6776
6918
  for (const type of events) {
6777
6919
  const handler = (e) => {
6778
- this.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)(type, this, e));
6920
+ this.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)(type, this, e));
6779
6921
  };
6780
6922
  this.domElement.addEventListener(type, handler);
6781
6923
  this.domListeners.push({ type, handler, capture: false });
@@ -6786,7 +6928,7 @@ var DOMPortalEntity = (_class11 = class extends _chunk7PI7LVWWjs.Entity {
6786
6928
  ];
6787
6929
  for (const { native, vecto } of hoverEvents) {
6788
6930
  const handler = (e) => {
6789
- this.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)(vecto, this, e, false));
6931
+ this.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)(vecto, this, e, false));
6790
6932
  };
6791
6933
  this.domElement.addEventListener(native, handler);
6792
6934
  this.domListeners.push({ type: native, handler, capture: false });
@@ -6794,7 +6936,7 @@ var DOMPortalEntity = (_class11 = class extends _chunk7PI7LVWWjs.Entity {
6794
6936
  const focusEvents = ["focus", "blur"];
6795
6937
  for (const type of focusEvents) {
6796
6938
  const handler = (e) => {
6797
- this.dispatchEvent(new (0, _chunk7PI7LVWWjs.VectoJSEvent)(type, this, e, true));
6939
+ this.dispatchEvent(new (0, _chunkTRT2TRCWjs.VectoJSEvent)(type, this, e, true));
6798
6940
  };
6799
6941
  this.domElement.addEventListener(type, handler, true);
6800
6942
  this.domListeners.push({ type, handler, capture: true });
@@ -6891,4 +7033,5 @@ Scene.registerWebGPUParticleSystemManager(_chunkM73XB4ZKjs.WebGPUParticleSystemM
6891
7033
 
6892
7034
 
6893
7035
 
6894
- exports.CanvasRenderer = _chunkM73XB4ZKjs.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Entity = _chunk7PI7LVWWjs.Entity; exports.GlyphRasterAtlas = _chunkM73XB4ZKjs.GlyphRasterAtlas; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.MSDFTextEntity = _chunk7PI7LVWWjs.MSDFTextEntity; exports.PARTICLE_OFFSET_LIFE = PARTICLE_OFFSET_LIFE; exports.PARTICLE_OFFSET_ORIGIN_X = PARTICLE_OFFSET_ORIGIN_X; exports.PARTICLE_OFFSET_ORIGIN_Y = PARTICLE_OFFSET_ORIGIN_Y; exports.PARTICLE_OFFSET_POSITION_X = PARTICLE_OFFSET_POSITION_X; exports.PARTICLE_OFFSET_POSITION_Y = PARTICLE_OFFSET_POSITION_Y; exports.PARTICLE_OFFSET_SIZE = PARTICLE_OFFSET_SIZE; exports.PARTICLE_OFFSET_VELOCITY_X = PARTICLE_OFFSET_VELOCITY_X; exports.PARTICLE_OFFSET_VELOCITY_Y = PARTICLE_OFFSET_VELOCITY_Y; exports.PARTICLE_STRIDE_FLOATS = PARTICLE_STRIDE_FLOATS; exports.REDUCED_MOTION_FPS = REDUCED_MOTION_FPS; exports.Rect = Rect; exports.SCENE_OPTION_KEYS = SCENE_OPTION_KEYS; exports.SVGEntity = _chunk7PI7LVWWjs.SVGEntity; exports.SVGRenderer = _chunkM73XB4ZKjs.SVGRenderer; exports.Scene = Scene; exports.SplineEntity = SplineEntity; exports.TextEntity = TextEntity; exports.TextRasterCache = _chunkM73XB4ZKjs.TextRasterCache; exports.VECTO_USER_TIMING = VECTO_USER_TIMING; exports.VectoJSEvent = _chunk7PI7LVWWjs.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkM73XB4ZKjs.WebGPUParticleSystemManager; exports.beginVectoUserTiming = beginVectoUserTiming; exports.contentLineInHint = _chunk7PI7LVWWjs.contentLineInHint; exports.createWebGLPointRenderer = _chunkM73XB4ZKjs.createWebGLPointRenderer; exports.endVectoUserTiming = endVectoUserTiming; exports.installRendererDevTraps = _chunkM73XB4ZKjs.installRendererDevTraps; exports.isRendererDevMode = _chunkM73XB4ZKjs.isRendererDevMode; exports.isSafeUrl = _chunkM73XB4ZKjs.isSafeUrl; exports.loadSpline = loadSpline; exports.measureVectoUserTiming = measureVectoUserTiming; exports.parseColorToRGBA = _chunkM73XB4ZKjs.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkM73XB4ZKjs.sanitizeUrl; exports.setRendererDevMode = _chunkM73XB4ZKjs.setRendererDevMode;
7036
+
7037
+ exports.CanvasRenderer = _chunkM73XB4ZKjs.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DEFAULT_CONTENT_SEMANTIC_BUDGET = DEFAULT_CONTENT_SEMANTIC_BUDGET; exports.DOMPortalEntity = DOMPortalEntity; exports.Entity = _chunkTRT2TRCWjs.Entity; exports.GlyphRasterAtlas = _chunkM73XB4ZKjs.GlyphRasterAtlas; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.MSDFTextEntity = _chunkTRT2TRCWjs.MSDFTextEntity; exports.PARTICLE_OFFSET_LIFE = PARTICLE_OFFSET_LIFE; exports.PARTICLE_OFFSET_ORIGIN_X = PARTICLE_OFFSET_ORIGIN_X; exports.PARTICLE_OFFSET_ORIGIN_Y = PARTICLE_OFFSET_ORIGIN_Y; exports.PARTICLE_OFFSET_POSITION_X = PARTICLE_OFFSET_POSITION_X; exports.PARTICLE_OFFSET_POSITION_Y = PARTICLE_OFFSET_POSITION_Y; exports.PARTICLE_OFFSET_SIZE = PARTICLE_OFFSET_SIZE; exports.PARTICLE_OFFSET_VELOCITY_X = PARTICLE_OFFSET_VELOCITY_X; exports.PARTICLE_OFFSET_VELOCITY_Y = PARTICLE_OFFSET_VELOCITY_Y; exports.PARTICLE_STRIDE_FLOATS = PARTICLE_STRIDE_FLOATS; exports.REDUCED_MOTION_FPS = REDUCED_MOTION_FPS; exports.Rect = Rect; exports.SCENE_OPTION_KEYS = SCENE_OPTION_KEYS; exports.SVGEntity = _chunkTRT2TRCWjs.SVGEntity; exports.SVGRenderer = _chunkM73XB4ZKjs.SVGRenderer; exports.Scene = Scene; exports.SplineEntity = SplineEntity; exports.TextEntity = TextEntity; exports.TextRasterCache = _chunkM73XB4ZKjs.TextRasterCache; exports.VECTO_USER_TIMING = VECTO_USER_TIMING; exports.VectoJSEvent = _chunkTRT2TRCWjs.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkM73XB4ZKjs.WebGPUParticleSystemManager; exports.beginVectoUserTiming = beginVectoUserTiming; exports.contentLineInHint = _chunkTRT2TRCWjs.contentLineInHint; exports.createWebGLPointRenderer = _chunkM73XB4ZKjs.createWebGLPointRenderer; exports.endVectoUserTiming = endVectoUserTiming; exports.installRendererDevTraps = _chunkM73XB4ZKjs.installRendererDevTraps; exports.isRendererDevMode = _chunkM73XB4ZKjs.isRendererDevMode; exports.isSafeUrl = _chunkM73XB4ZKjs.isSafeUrl; exports.loadSpline = loadSpline; exports.measureVectoUserTiming = measureVectoUserTiming; exports.parseColorToRGBA = _chunkM73XB4ZKjs.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkM73XB4ZKjs.sanitizeUrl; exports.setRendererDevMode = _chunkM73XB4ZKjs.setRendererDevMode;