@vectojs/core 1.32.7 → 1.34.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/{chunk-FQ2565IT.js → chunk-UEIZDNK7.js} +57 -30
- package/dist/{chunk-YTGGL4I4.mjs → chunk-VFQMETOR.mjs} +27 -0
- package/dist/index.js +3082 -2280
- package/dist/index.mjs +2834 -2032
- package/dist/text.js +2 -2
- package/dist/text.mjs +1 -1
- package/dist/tree/Entity.d.ts +41 -0
- package/dist/tree/Scene.d.ts +199 -472
- package/dist/tree/scene/A11yProjectionManager.d.ts +147 -0
- package/dist/tree/scene/CanvasGeometry.d.ts +117 -0
- package/dist/tree/scene/ContentGridProjector.d.ts +63 -0
- package/dist/tree/scene/ContentProjectionManager.d.ts +217 -0
- package/dist/tree/scene/DirtyTracker.d.ts +107 -0
- package/dist/tree/scene/DriverTicker.d.ts +101 -0
- package/dist/tree/scene/HitTester.d.ts +113 -0
- package/dist/tree/scene/PhaseTimer.d.ts +114 -0
- package/dist/tree/scene/WasmBackendFacade.d.ts +271 -0
- package/dist/tree/scene/a11y-dom.d.ts +78 -0
- package/dist/tree/scene/content-break-carrier.d.ts +77 -0
- package/dist/tree/scene/content-caret.d.ts +28 -0
- package/dist/tree/scene/content-line-window.d.ts +64 -0
- package/package.json +1 -1
package/dist/tree/Scene.d.ts
CHANGED
|
@@ -14,90 +14,16 @@ import { Entity } from './Entity';
|
|
|
14
14
|
import { IRenderer } from '../renderer/IRenderer';
|
|
15
15
|
import type { WebGLDrawStats } from '../renderer/WebGLPointRenderer';
|
|
16
16
|
import { type WasmModuleSource, type WasmTransformBackend } from '../wasm/backend';
|
|
17
|
-
import {
|
|
17
|
+
import type { CoreWasmRuntime } from '../wasm/runtime';
|
|
18
18
|
import { type HitModuleSource, type HitTestBackend } from '../wasm/hit-backend';
|
|
19
19
|
import { type AnimModuleSource, type AnimBackend } from '../wasm/anim-backend';
|
|
20
20
|
import { type ParticleModuleSource, type ParticleBackend } from '../wasm/particle-backend';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* siblings of it, not children.
|
|
28
|
-
*/
|
|
29
|
-
export type RenderPhase = 'render' | 'transform' | 'drawWalk' | 'flush' | 'a11ySync'
|
|
30
|
-
/**
|
|
31
|
-
* Time inside {@link Scene.syncContentGridProjection} materializing DOM
|
|
32
|
-
* carriers, nested inside `a11ySync`.
|
|
33
|
-
*
|
|
34
|
-
* Split out because `a11ySync` for a streaming code block measured 1661-1875 ms
|
|
35
|
-
* against a 210-671 ms render, and attributing that to grid materialization was
|
|
36
|
-
* an assumption. Nothing should be optimised here on the strength of the parent
|
|
37
|
-
* phase alone.
|
|
38
|
-
*/
|
|
39
|
-
| 'gridMaterialize'
|
|
40
|
-
/**
|
|
41
|
-
* Whole of {@link Scene.syncContentProjection}, nested inside `a11ySync`.
|
|
42
|
-
*
|
|
43
|
-
* Measured at 99.8-99.9% of `a11ySync` for a streaming code block, so per-node
|
|
44
|
-
* a11y attribute and geometry work is not where that phase's cost lives.
|
|
45
|
-
*/
|
|
46
|
-
| 'contentProjection'
|
|
47
|
-
/** Per-node a11y attribute/geometry work, excluding content projection and descendants. */
|
|
48
|
-
| 'a11yNodes'
|
|
49
|
-
/** Whole of `syncContentGridProjection`, of which `gridMaterialize` is one part. */
|
|
50
|
-
| 'gridSync'
|
|
51
|
-
/**
|
|
52
|
-
* Synchronous part of `scheduleContentGridCalibration` — building the probe DOM.
|
|
53
|
-
*
|
|
54
|
-
* The measurement itself is deferred to a rAF, but the probe is constructed
|
|
55
|
-
* here. Measured at 77-80% of `gridSync` on Chrome (3.7-4.5 ms per frame, i.e.
|
|
56
|
-
* the entire 240Hz budget) against about 1 ms on Firefox, making it the largest
|
|
57
|
-
* remaining cost of projecting a streaming code block once carrier reuse landed.
|
|
58
|
-
*/
|
|
59
|
-
| 'gridCalibrateSchedule'
|
|
60
|
-
/** The `querySelectorAll` + per-cell scan inside calibration scheduling. */
|
|
61
|
-
| 'calibScan'
|
|
62
|
-
/** Probe DOM construction and insertion inside calibration scheduling. */
|
|
63
|
-
| 'calibProbeBuild' | 'a11yOrder'
|
|
64
|
-
/** Sum of every entity's own render(), nested inside drawWalk. */
|
|
65
|
-
| 'entityPaint';
|
|
66
|
-
export interface RenderPhaseEntry {
|
|
67
|
-
phase: RenderPhase;
|
|
68
|
-
totalMs: number;
|
|
69
|
-
calls: number;
|
|
70
|
-
avgMs: number;
|
|
71
|
-
/** Worst single sample — a spiky phase is a different problem from a slow one. */
|
|
72
|
-
maxMs: number;
|
|
73
|
-
/** Percent of the measured total, or `null` for the enclosing `render` phase. */
|
|
74
|
-
share: number | null;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Who marked the scene dirty, and why.
|
|
78
|
-
*
|
|
79
|
-
* Every field is optional except `reason` so a call site can be as specific as it
|
|
80
|
-
* cheaply can — an entity id costs nothing to pass, a property name is often
|
|
81
|
-
* already in scope.
|
|
82
|
-
*/
|
|
83
|
-
export interface DirtySource {
|
|
84
|
-
/** Entity id responsible, when one is. Omitted for scene-level invalidation. */
|
|
85
|
-
entity?: string;
|
|
86
|
-
/** Short, stable category — e.g. `'text-changed'`, `'animation'`, `'resize'`. */
|
|
87
|
-
reason: string;
|
|
88
|
-
/** Property that changed, when the reason alone is ambiguous. */
|
|
89
|
-
property?: string;
|
|
90
|
-
}
|
|
91
|
-
/** An aggregated dirty attribution. */
|
|
92
|
-
export interface DirtyReasonEntry {
|
|
93
|
-
entity?: string;
|
|
94
|
-
reason: string;
|
|
95
|
-
property?: string;
|
|
96
|
-
/** How many times this exact attribution was recorded. */
|
|
97
|
-
count: number;
|
|
98
|
-
firstFrame: number;
|
|
99
|
-
lastFrame: number;
|
|
100
|
-
}
|
|
21
|
+
import { type OverlayGeometry } from './scene/CanvasGeometry';
|
|
22
|
+
import { type DirtyReasonEntry, type DirtySource } from './scene/DirtyTracker';
|
|
23
|
+
import { type RenderPhase, type RenderPhaseEntry } from './scene/PhaseTimer';
|
|
24
|
+
import { type AcceleratorReason, type AcceleratorReport, type AcceleratorStatus } from './scene/WasmBackendFacade';
|
|
25
|
+
export type { RenderPhase, RenderPhaseEntry };
|
|
26
|
+
export type { DirtyReasonEntry, DirtySource };
|
|
101
27
|
/**
|
|
102
28
|
* Options for {@link Scene}.
|
|
103
29
|
*/
|
|
@@ -301,60 +227,7 @@ export interface SceneOptions {
|
|
|
301
227
|
export declare const SCENE_OPTION_KEYS: readonly ['a11ySyncInterval', 'autoThrottle', 'contentProjection', 'contentProjectionMargin', 'contentSemanticBudget', 'contentSemanticMargin', 'debugA11y', 'disableWindowResize', 'maxDPR', 'maxFPS', 'particleBackend', 'pointBackend', 'readingDirection', 'renderer', 'renderMode', 'respectReducedMotion', 'userTiming'];
|
|
302
228
|
/** Frame-rate the loop is capped to when the OS requests reduced motion. */
|
|
303
229
|
export declare const REDUCED_MOTION_FPS = 30;
|
|
304
|
-
|
|
305
|
-
* Why an accelerator did or did not run on the most recent frame.
|
|
306
|
-
*
|
|
307
|
-
* `'active'` is the only value that means the accelerator ran. Everything else
|
|
308
|
-
* is a distinct decline, kept separate because they call for different actions:
|
|
309
|
-
* `'not-installed'` means enable it, `'below-gate'` means the workload is too
|
|
310
|
-
* small to be worth it (working as designed), and `'rejected'` means the kernel
|
|
311
|
-
* refused its arguments — a fault worth reporting, not a tuning outcome.
|
|
312
|
-
*/
|
|
313
|
-
export type AcceleratorReason =
|
|
314
|
-
/** Ran on this frame. */
|
|
315
|
-
'active'
|
|
316
|
-
/** No backend installed; the JS path is the permanent fallback. */
|
|
317
|
-
| 'not-installed'
|
|
318
|
-
/** Installed, but the per-frame gate chose JS (workload below threshold). */
|
|
319
|
-
| 'below-gate'
|
|
320
|
-
/** Installed and gated in, but the kernel rejected the call and wrote nothing. */
|
|
321
|
-
| 'rejected'
|
|
322
|
-
/** Not applicable to this pass (e.g. a non-main renderer, or nothing to do). */
|
|
323
|
-
| 'not-applicable';
|
|
324
|
-
/**
|
|
325
|
-
* One accelerator's per-frame status, read from {@link Scene.accelerators}.
|
|
326
|
-
*
|
|
327
|
-
* The pair exists because `available` and `activeThisFrame` genuinely differ:
|
|
328
|
-
* before this shape, `transformBackend`/`animBackend` reported only that a
|
|
329
|
-
* backend was *installed*, which invites concluding an accelerator is doing work
|
|
330
|
-
* when its gate never opens. Read `activeThisFrame` for what actually happened
|
|
331
|
-
* and `reason` for why.
|
|
332
|
-
*/
|
|
333
|
-
export interface AcceleratorStatus {
|
|
334
|
-
/** A backend is installed and could run, gate permitting. */
|
|
335
|
-
available: boolean;
|
|
336
|
-
/** It ran on the most recent frame. */
|
|
337
|
-
activeThisFrame: boolean;
|
|
338
|
-
/** Why it did or did not run. */
|
|
339
|
-
reason: AcceleratorReason;
|
|
340
|
-
/** Which implementation actually did the work on the most recent frame. */
|
|
341
|
-
path: string;
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Per-frame status of every invisible accelerator, read from
|
|
345
|
-
* {@link Scene.accelerators}. Each is independent: a scene can compose
|
|
346
|
-
* transforms in WASM while ticking drivers in JS.
|
|
347
|
-
*/
|
|
348
|
-
export interface AcceleratorReport {
|
|
349
|
-
/** World-matrix composition (`compose_simd`). */
|
|
350
|
-
transform: AcceleratorStatus;
|
|
351
|
-
/** Batched property drivers (`spring_step`/`tween_step`). */
|
|
352
|
-
animation: AcceleratorStatus;
|
|
353
|
-
/** Hit-test broad phase (`hit_build`/`hit_query`) and its gather source. */
|
|
354
|
-
hitTest: AcceleratorStatus;
|
|
355
|
-
/** Particle simulation — WebGPU compute, the WASM CPU kernel, or JS. */
|
|
356
|
-
particle: AcceleratorStatus;
|
|
357
|
-
}
|
|
230
|
+
export type { AcceleratorReason, AcceleratorStatus, AcceleratorReport };
|
|
358
231
|
/**
|
|
359
232
|
* Live render-loop telemetry, read from {@link Scene.frameStats}. See that
|
|
360
233
|
* getter for how each field is measured.
|
|
@@ -470,11 +343,16 @@ export declare class Scene {
|
|
|
470
343
|
* event-driven UIs where idle frames should cost ~0.
|
|
471
344
|
*/
|
|
472
345
|
renderMode: 'always' | 'onDemand';
|
|
473
|
-
/**
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
346
|
+
/**
|
|
347
|
+
* Per-phase frame timing and the browser User Timing flag.
|
|
348
|
+
*
|
|
349
|
+
* Extracted ahead of extraction 3 because the content-grid calibration pass is
|
|
350
|
+
* instrumented (`calibScan`, `calibProbeBuild`) and could not move while its
|
|
351
|
+
* only remaining dependency was a `Scene` private. Nine methods across four
|
|
352
|
+
* domains write phases, so this is a shared leaf rather than any one domain's
|
|
353
|
+
* property — see `DEC-0021`.
|
|
354
|
+
*/
|
|
355
|
+
private readonly phases;
|
|
478
356
|
/**
|
|
479
357
|
* Start or stop per-phase render timing.
|
|
480
358
|
*
|
|
@@ -500,15 +378,6 @@ export declare class Scene {
|
|
|
500
378
|
setUserTiming(enabled: boolean): void;
|
|
501
379
|
/** Whether browser User Timing phase instrumentation is enabled. */
|
|
502
380
|
get userTiming(): boolean;
|
|
503
|
-
/**
|
|
504
|
-
* Accumulate one phase sample.
|
|
505
|
-
*
|
|
506
|
-
* Totals rather than a per-frame log: the question is always "which phase owns
|
|
507
|
-
* the frame", and a log of thousands of samples answers it less directly while
|
|
508
|
-
* costing far more memory. `maxMs` is kept because a phase that is cheap on
|
|
509
|
-
* average but spikes is a different problem from one that is uniformly slow.
|
|
510
|
-
*/
|
|
511
|
-
private _recordPhase;
|
|
512
381
|
/**
|
|
513
382
|
* Recorded phase timings, most expensive first, with each phase's share of the
|
|
514
383
|
* measured total.
|
|
@@ -519,9 +388,24 @@ export declare class Scene {
|
|
|
519
388
|
get renderPhases(): RenderPhaseEntry[];
|
|
520
389
|
/** Drop recorded phase timings, keeping timing enabled. */
|
|
521
390
|
clearRenderPhases(): void;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
391
|
+
/**
|
|
392
|
+
* The dirty flag and its opt-in attribution (extraction 6, `DEC-0025`).
|
|
393
|
+
*
|
|
394
|
+
* A field initializer rather than a constructor assignment: it needs no
|
|
395
|
+
* injected input, so it follows {@link phases} and {@link a11yOrder} rather
|
|
396
|
+
* than the definite-assignment collaborators.
|
|
397
|
+
*/
|
|
398
|
+
private readonly _dirty;
|
|
399
|
+
/**
|
|
400
|
+
* The redraw-pending flag, under its original name.
|
|
401
|
+
*
|
|
402
|
+
* `Scene.test.ts:2153` assigns `false` and `:2158` reads it, and the suite is
|
|
403
|
+
* unedited (`DEC-0019` rule 4). `private` is correct here rather than
|
|
404
|
+
* `protected` — unlike the extraction 1/3/4 accessors, this one still has
|
|
405
|
+
* in-class readers (`loop`, `step`, `frameStats`).
|
|
406
|
+
*/
|
|
407
|
+
private get dirty();
|
|
408
|
+
private set dirty(value);
|
|
525
409
|
/** Whether to throttle rendering to 2 FPS when the scene is static to save power. */
|
|
526
410
|
autoThrottle: boolean;
|
|
527
411
|
/** Wall-clock ms spent inside the last `render()` call. */
|
|
@@ -594,33 +478,6 @@ export declare class Scene {
|
|
|
594
478
|
* {@link Entity.getContentEpoch}. (carryctx CTX-0199)
|
|
595
479
|
*/
|
|
596
480
|
private contentSyncState;
|
|
597
|
-
/** Pending cold font-calibration frame per projected grid entity. */
|
|
598
|
-
private contentGridCalibrationFrames;
|
|
599
|
-
/** Detached, untransformed font probes used by the cold calibration pass. */
|
|
600
|
-
private contentGridCalibrationProbes;
|
|
601
|
-
/**
|
|
602
|
-
* Monotonic stamp identifying the conditions grid cells were calibrated under.
|
|
603
|
-
*
|
|
604
|
-
* Calibration measures the difference between the advance the canvas grid assigns
|
|
605
|
-
* a cluster and the width the browser lays it out at, then writes a per-cell
|
|
606
|
-
* `scaleX`. That result stays valid until the font or the page scale changes, and
|
|
607
|
-
* it lives on the cell element — so a cell carrying this stamp needs no further
|
|
608
|
-
* work.
|
|
609
|
-
*
|
|
610
|
-
* The scan that feeds calibration was O(cells) on every revision bump: for a
|
|
611
|
-
* streaming code block it re-derived a measurement key for every cell in the
|
|
612
|
-
* block each frame in order to produce only ~20 distinct keys, costing about
|
|
613
|
-
* 2.5 ms/frame after the `style.font` fix and still over half of `a11ySync`. Since
|
|
614
|
-
* carrier reuse (#244) leaves untouched lines — and therefore their calibrated
|
|
615
|
-
* transforms — in place, cells stamped with the current generation can simply be
|
|
616
|
-
* skipped, making the scan O(new cells) instead.
|
|
617
|
-
*
|
|
618
|
-
* A plain incrementing integer rather than the descriptive calibration key,
|
|
619
|
-
* because it goes into an attribute selector and must not need escaping.
|
|
620
|
-
*/
|
|
621
|
-
private contentGridCalibrationGeneration;
|
|
622
|
-
/** The `(fontEpoch, pageScale)` pair the current generation corresponds to. */
|
|
623
|
-
private contentGridCalibrationStamp;
|
|
624
481
|
/** Invalidates grid font calibration after browser font availability changes. */
|
|
625
482
|
private contentFontEpoch;
|
|
626
483
|
/**
|
|
@@ -681,37 +538,6 @@ export declare class Scene {
|
|
|
681
538
|
private contentSemanticBudget;
|
|
682
539
|
private contentSemanticBudgetLeft;
|
|
683
540
|
private contentSemanticDeferred;
|
|
684
|
-
/**
|
|
685
|
-
* Per-sync memo of "does the document hold a selection at all".
|
|
686
|
-
*
|
|
687
|
-
* Reading ANY property of a `Selection` (`anchorNode`, `rangeCount`, `type`,
|
|
688
|
-
* `isCollapsed`) forces a synchronous layout, because Blink validates the
|
|
689
|
-
* selection against current box geometry before answering. Measured in real
|
|
690
|
-
* Chrome against a 1000-carrier subtree with layout dirtied between reads:
|
|
691
|
-
* `anchorNode` 0.5ms, `rangeCount` 0.4ms, `type` 0.5ms, `isCollapsed` 0.5ms —
|
|
692
|
-
* all indistinguishable from `offsetHeight` (0.5ms), against a 0ms floor for
|
|
693
|
-
* mutating without reading. So there is no cheap property to probe with; the
|
|
694
|
-
* only way to avoid the layout is to not touch the object at all.
|
|
695
|
-
*
|
|
696
|
-
* Materializing a block rebuilds its carriers, which asks whether the rebuild
|
|
697
|
-
* would destroy a selection. Once per block, that read cost a forced layout
|
|
698
|
-
* over the whole (and growing) projection subtree, which is what made
|
|
699
|
-
* per-block cost rise with resident count: profiled at 1973 forced layouts
|
|
700
|
-
* totalling 633ms of an 847ms 1000-block drain (75%).
|
|
701
|
-
*
|
|
702
|
-
* A selection is a single document-wide object and a sync walk cannot yield to
|
|
703
|
-
* the user, so its presence cannot change mid-walk. Resolving it once per walk
|
|
704
|
-
* turns O(blocks) forced layouts into O(1). `null` = not yet resolved.
|
|
705
|
-
*/
|
|
706
|
-
private contentSelectionPresentThisSync;
|
|
707
|
-
/**
|
|
708
|
-
* True while a text-selection drag that started on a projection's blank
|
|
709
|
-
* region (no text node under the press) is being driven manually — the
|
|
710
|
-
* browser has no native anchor for it, so mousemove extends the Selection
|
|
711
|
-
* from the position we resolved ourselves.
|
|
712
|
-
*/
|
|
713
|
-
private blankRegionSelectionDrag;
|
|
714
|
-
private contentSelectionAnchor;
|
|
715
541
|
private contentSelectionEndListener;
|
|
716
542
|
private frameHadAnimation;
|
|
717
543
|
private frameHadInteractive;
|
|
@@ -729,10 +555,25 @@ export declare class Scene {
|
|
|
729
555
|
private canvasResizeObserver;
|
|
730
556
|
private dprChangeHandler;
|
|
731
557
|
private focusedA11yElement;
|
|
732
|
-
/**
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
|
|
558
|
+
/**
|
|
559
|
+
* Canvas box geometry: the CSS↔logical mapping, overlay layer alignment, and
|
|
560
|
+
* the DPR math (extraction 5, `DEC-0024`).
|
|
561
|
+
*
|
|
562
|
+
* Definite-assignment because it holds `a11yRoot` and `portalRoot`, which the
|
|
563
|
+
* constructor only decides partway through — the same shape as
|
|
564
|
+
* {@link _contentProjection}.
|
|
565
|
+
*/
|
|
566
|
+
private _geometry;
|
|
567
|
+
/**
|
|
568
|
+
* The overlay memo, for the unedited suite.
|
|
569
|
+
*
|
|
570
|
+
* `OverlayGeometrySkip.test.ts:75,143` assigns `null` to force the next sync,
|
|
571
|
+
* so the setter delegates to `invalidateOverlay()`. `protected` rather than
|
|
572
|
+
* `private` because it has no in-class reader and `noUnusedLocals` fails the
|
|
573
|
+
* build on a private with none (`DEC-0019` rule 4).
|
|
574
|
+
*/
|
|
575
|
+
protected get _overlayGeometry(): OverlayGeometry | null;
|
|
576
|
+
protected set _overlayGeometry(value: OverlayGeometry | null);
|
|
736
577
|
/** Shadow elements the pointer is currently inside. Lets a removal that happens
|
|
737
578
|
* mid-hover synthesize the `pointerleave` the browser never sends for a
|
|
738
579
|
* detached element, so the entity doesn't keep its hover state. */
|
|
@@ -751,33 +592,60 @@ export declare class Scene {
|
|
|
751
592
|
* screen-reader virtual cursor inside the scene's a11y region. */
|
|
752
593
|
private focusSentinel;
|
|
753
594
|
private caretBlinkTimer;
|
|
754
|
-
a11yNeedsReorder: boolean;
|
|
755
|
-
private portalRoot;
|
|
756
|
-
private fullViewportElements;
|
|
757
|
-
private normalElements;
|
|
758
|
-
private activeIds;
|
|
759
|
-
/** Per-parent insertion cursor, reused by `enforceA11yDomOrder`. */
|
|
760
|
-
private a11yOrderCursors;
|
|
761
|
-
/** Membership set for the elements being ordered, reused per reorder pass. */
|
|
762
|
-
private a11yOrderMembers;
|
|
763
595
|
/**
|
|
764
|
-
*
|
|
596
|
+
* The projected DOM's ordering engine — the reorder flag, the per-pass scratch
|
|
597
|
+
* collections, the visual reading-order sort and the cursor-based
|
|
598
|
+
* `insertBefore` pass (extraction 2, `DEC-0020`).
|
|
599
|
+
*
|
|
600
|
+
* `a11yNeedsReorder` and `enforceA11yDomOrder` keep their names on `Scene` and
|
|
601
|
+
* delegate here; the collect-and-prune walk stays behind because it needs
|
|
602
|
+
* {@link shouldProjectA11y} and the focus/caret state.
|
|
603
|
+
*/
|
|
604
|
+
private readonly a11yOrder;
|
|
605
|
+
/**
|
|
606
|
+
* The content projection's selection preservation and grid calibration
|
|
607
|
+
* (extraction 3, `DEC-0022`).
|
|
765
608
|
*
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
609
|
+
* Definite-assignment because it needs `a11yRoot`, which the constructor
|
|
610
|
+
* creates partway through — the same shape as {@link _wasmBackend}. Every
|
|
611
|
+
* constructor use is inside a deferred event listener, so it is always
|
|
612
|
+
* assigned before anything can reach it.
|
|
769
613
|
*/
|
|
770
|
-
private
|
|
614
|
+
private _contentProjection;
|
|
615
|
+
/** Grid carrier materialization (the projection walk's separable leaf). */
|
|
616
|
+
private _gridProjector;
|
|
771
617
|
/**
|
|
772
|
-
*
|
|
773
|
-
* per pass. Written by `enforceA11yDomOrder`'s collect walk, which already has
|
|
774
|
-
* the entity in hand, so a region costs one comparison per node rather than an
|
|
775
|
-
* ancestor walk per element.
|
|
618
|
+
* Pending grid-calibration frames, keyed by entity id.
|
|
776
619
|
*
|
|
777
|
-
*
|
|
778
|
-
*
|
|
620
|
+
* Delegates to {@link ContentProjectionManager}. Kept on `Scene` under its
|
|
621
|
+
* original name because the text-projection e2e reads
|
|
622
|
+
* `scene.contentGridCalibrationFrames.size` to assert calibration is not left
|
|
623
|
+
* in flight after a rebuild. `protected` rather than `private`: there is no
|
|
624
|
+
* in-class reader, and `private` plus no reader fails `noUnusedLocals`
|
|
625
|
+
* (`DEC-0019` rule 4).
|
|
779
626
|
*/
|
|
780
|
-
|
|
627
|
+
protected get contentGridCalibrationFrames(): ReadonlyMap<string, number>;
|
|
628
|
+
/**
|
|
629
|
+
* Index of the carrier line holding a selection inside `el`, or `null`.
|
|
630
|
+
*
|
|
631
|
+
* Delegates to {@link ContentProjectionManager}. Kept under its original name
|
|
632
|
+
* because `ContentGridSelectionWindow.test.ts` calls it through a cast to
|
|
633
|
+
* assert the selection-window behaviour. `protected` per `DEC-0019` rule 4 —
|
|
634
|
+
* the in-class callers now go through the manager directly.
|
|
635
|
+
*/
|
|
636
|
+
protected contentGridSelectionLine(el: HTMLElement): number | null;
|
|
637
|
+
/**
|
|
638
|
+
* Whether the projected a11y DOM needs reordering on the next pass.
|
|
639
|
+
*
|
|
640
|
+
* Delegates to {@link A11yProjectionManager}. Kept on `Scene` under its
|
|
641
|
+
* original name — and with a setter — because `Entity` assigns to
|
|
642
|
+
* `scene.a11yNeedsReorder` as a public cross-class contract (`Entity.ts` sets
|
|
643
|
+
* it when `interactive` flips and when a child is added or removed), and the
|
|
644
|
+
* unedited suite writes it directly too.
|
|
645
|
+
*/
|
|
646
|
+
get a11yNeedsReorder(): boolean;
|
|
647
|
+
set a11yNeedsReorder(value: boolean);
|
|
648
|
+
private portalRoot;
|
|
781
649
|
private activePortalsThisFrame;
|
|
782
650
|
private activePortalsPrevFrame;
|
|
783
651
|
private portalEntities;
|
|
@@ -791,22 +659,58 @@ export declare class Scene {
|
|
|
791
659
|
* `_setWorldCache` are: it is a cross-class render-internal contract.
|
|
792
660
|
*/
|
|
793
661
|
currentFrame: number;
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
662
|
+
/**
|
|
663
|
+
* The four invisible WASM accelerators and the resident transform store.
|
|
664
|
+
*
|
|
665
|
+
* Extraction 1 of this file's decomposition. Every public member below keeps
|
|
666
|
+
* its name, signature and behaviour and delegates here, so the public API is
|
|
667
|
+
* byte-identical; only where the state lives changed.
|
|
668
|
+
*
|
|
669
|
+
* Constructed in the constructor rather than initialized here because it needs
|
|
670
|
+
* {@link root}, which is itself assigned there.
|
|
671
|
+
*/
|
|
672
|
+
private _wasmBackend;
|
|
673
|
+
/**
|
|
674
|
+
* The transform backend object itself.
|
|
675
|
+
*
|
|
676
|
+
* Kept under its original name and delegating, rather than deleted:
|
|
677
|
+
* `test/wasm/scene-accelerators.test.ts` reaches for `scene._wasm` to
|
|
678
|
+
* monkey-patch a kernel into rejecting, and that unedited suite is this
|
|
679
|
+
* refactor's gate — rewriting it to match the new shape would be marking our
|
|
680
|
+
* own homework. Same reasoning for `_animWasm`, `_wasmUploadRejections`,
|
|
681
|
+
* `_storeStructureVersion` and `_structureVersion` below.
|
|
682
|
+
*
|
|
683
|
+
* `protected` rather than `private` since extraction 4: the hit-grid build was
|
|
684
|
+
* this getter's last in-class reader, and `private` plus no reader fails
|
|
685
|
+
* `noUnusedLocals` (`DEC-0019` rule 4).
|
|
686
|
+
* @internal
|
|
687
|
+
*/
|
|
688
|
+
protected get _wasm(): WasmTransformBackend | null;
|
|
689
|
+
/** @internal Read by the WASM anim suites; see {@link _wasm}. */
|
|
690
|
+
private get _animWasm();
|
|
691
|
+
/**
|
|
692
|
+
* @internal
|
|
693
|
+
* `protected`, not `private`, and that is the one deliberate access change in
|
|
694
|
+
* this extraction. Both of these are read by a test and by nothing inside this
|
|
695
|
+
* class, so `private` makes them dead code and `noUnusedLocals` rejects the
|
|
696
|
+
* build. `protected` is the honest encoding of "exists to be read from
|
|
697
|
+
* outside, never from in here" — and it is invisible to API consumers, who
|
|
698
|
+
* cannot reach a protected member either. `Scene` has no subclasses in this
|
|
699
|
+
* repo and is not documented as subclassable.
|
|
700
|
+
*
|
|
701
|
+
* Read by the run-table fallback suite; see {@link _wasm}.
|
|
702
|
+
*/
|
|
703
|
+
protected get _wasmUploadRejections(): number;
|
|
704
|
+
/** @internal Read by the resident-store suite; see {@link _wasmUploadRejections}. */
|
|
705
|
+
protected get _storeStructureVersion(): number;
|
|
706
|
+
/**
|
|
707
|
+
* Tree topology version, bumped by every add/remove/reparent.
|
|
708
|
+
*
|
|
709
|
+
* Lives on the facade because the resident store layout is keyed by it, but is
|
|
710
|
+
* read here by the compute-entity cache below and by `Scene.test.ts`.
|
|
711
|
+
* @internal
|
|
712
|
+
*/
|
|
713
|
+
private get _structureVersion();
|
|
810
714
|
private _computeEntities;
|
|
811
715
|
private _computeEntitiesVersion;
|
|
812
716
|
/** Invalidate the resident WASM store layout; the next wasm-mode frame rebuilds
|
|
@@ -845,25 +749,6 @@ export declare class Scene {
|
|
|
845
749
|
* Resolves `true` if WASM is now active, `false` if the JS path remains.
|
|
846
750
|
*/
|
|
847
751
|
enableWasmTransforms(source: WasmModuleSource): Promise<boolean>;
|
|
848
|
-
/**
|
|
849
|
-
* The one WASM instance this Scene's accelerators share.
|
|
850
|
-
*
|
|
851
|
-
* Each `enableWasm*` used to instantiate the binary itself, so enabling all
|
|
852
|
-
* four compiled the same module four times and held four linear memories. The
|
|
853
|
-
* Rust crate already keeps transform/anim/hit/particle in separate statics, so
|
|
854
|
-
* one instance serves all of them without aliasing. The compiled module is
|
|
855
|
-
* cached globally; the instance is per-Scene, which is the isolation that
|
|
856
|
-
* actually matters.
|
|
857
|
-
*/
|
|
858
|
-
private _wasmRuntime;
|
|
859
|
-
/**
|
|
860
|
-
* Load (or reuse) this Scene's shared WASM runtime.
|
|
861
|
-
*
|
|
862
|
-
* Returns `null` on any failure — CSP `wasm-unsafe-eval`, a 404, corrupt bytes,
|
|
863
|
-
* unsupported SIMD — so every caller keeps its JS path. Failure is the default
|
|
864
|
-
* state here, not an error path.
|
|
865
|
-
*/
|
|
866
|
-
private ensureWasmRuntime;
|
|
867
752
|
/**
|
|
868
753
|
* Install a pre-built runtime, so several Scenes can share one compile while
|
|
869
754
|
* each keeps its own stores. Pass `null` to detach (backends already installed
|
|
@@ -872,46 +757,17 @@ export declare class Scene {
|
|
|
872
757
|
setWasmRuntime(runtime: CoreWasmRuntime | null): void;
|
|
873
758
|
/** The shared WASM runtime, if one has been loaded. */
|
|
874
759
|
get wasmRuntime(): CoreWasmRuntime | null;
|
|
875
|
-
private _hitWasm;
|
|
876
|
-
private _hitGridFrame;
|
|
877
|
-
private _hitGridOk;
|
|
878
|
-
private _hitSlotEntity;
|
|
879
|
-
private _hitBoundless;
|
|
880
|
-
/** Reused buffer for the fused gather, so a pointer query allocates nothing. */
|
|
881
|
-
private _hitGatherBuffer;
|
|
882
|
-
/**
|
|
883
|
-
* Whether the last grid build sourced its AABBs from the WASM transform store
|
|
884
|
-
* rather than recomputing them in JS. Diagnostic only — both paths must
|
|
885
|
-
* produce the same entity for a given point.
|
|
886
|
-
*/
|
|
887
|
-
private _hitFusedGather;
|
|
888
760
|
/**
|
|
889
|
-
*
|
|
890
|
-
*
|
|
891
|
-
*
|
|
761
|
+
* The pointer hit-test: the WASM broad-phase grid, the permanent JS
|
|
762
|
+
* depth-first walk, and the eligibility gating that keeps the two in lockstep
|
|
763
|
+
* (extraction 4, `DEC-0023`).
|
|
764
|
+
*
|
|
765
|
+
* Definite-assignment because it needs {@link _wasmBackend}, which is built
|
|
766
|
+
* partway through the constructor.
|
|
892
767
|
*/
|
|
893
|
-
private
|
|
768
|
+
private _hitTester;
|
|
894
769
|
/** Did the last hit-grid build use the fused (WASM-store) gather? */
|
|
895
770
|
get hitGatherPath(): 'fused' | 'js';
|
|
896
|
-
/**
|
|
897
|
-
* Why the transform accelerator did or did not run on the most recent frame.
|
|
898
|
-
* Written by the render walk and `_syncWasmStore`.
|
|
899
|
-
*/
|
|
900
|
-
private _transformReason;
|
|
901
|
-
/** Why the batched-driver accelerator did or did not run. */
|
|
902
|
-
private _animReason;
|
|
903
|
-
/**
|
|
904
|
-
* Why the hit-test accelerator did or did not serve the last pointer query.
|
|
905
|
-
* The grid is built lazily on demand, not every frame, so this describes the
|
|
906
|
-
* most recent BUILD. Starts at `'not-installed'` because that is the truth
|
|
907
|
-
* before a backend exists; `_ensureHitGrid` moves it to `'not-applicable'`
|
|
908
|
-
* once one is installed but nothing has queried yet.
|
|
909
|
-
*/
|
|
910
|
-
private _hitReason;
|
|
911
|
-
/** Why the particle accelerator did or did not run. */
|
|
912
|
-
private _particleReason;
|
|
913
|
-
/** Which particle implementation actually simulated the most recent frame. */
|
|
914
|
-
private _particlePath;
|
|
915
771
|
/**
|
|
916
772
|
* Per-frame status of every invisible accelerator: whether each is installed,
|
|
917
773
|
* whether it actually ran on the most recent frame, and why.
|
|
@@ -926,6 +782,10 @@ export declare class Scene {
|
|
|
926
782
|
*
|
|
927
783
|
* Reflects the most recent main-renderer frame; a secondary renderer (SVG
|
|
928
784
|
* export, offscreen snapshot) does not overwrite it.
|
|
785
|
+
*
|
|
786
|
+
* `webgpuActive` is handed to the facade rather than read by it: WebGPU device
|
|
787
|
+
* state belongs to the context/resize domain (extraction 5), and this getter
|
|
788
|
+
* is the only place the two domains have to agree.
|
|
929
789
|
*/
|
|
930
790
|
get accelerators(): AcceleratorReport;
|
|
931
791
|
/** Which backend answers `findEntityAt` for the main tree. */
|
|
@@ -942,34 +802,23 @@ export declare class Scene {
|
|
|
942
802
|
*/
|
|
943
803
|
enableWasmHitTest(source: HitModuleSource): Promise<boolean>;
|
|
944
804
|
/**
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
*
|
|
948
|
-
*
|
|
949
|
-
*
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
*
|
|
957
|
-
*
|
|
958
|
-
* `
|
|
959
|
-
*
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
* conclusive: returns the correct entity or `null`, never "inconclusive".
|
|
963
|
-
*/
|
|
964
|
-
private _findEntityAtWasm;
|
|
965
|
-
private _animWasm;
|
|
966
|
-
private _activeDriverEntities;
|
|
967
|
-
private _springEntities;
|
|
968
|
-
private _springProps;
|
|
969
|
-
private _springDrivers;
|
|
970
|
-
private _tweenEntities;
|
|
971
|
-
private _tweenProps;
|
|
972
|
-
private _tweenDrivers;
|
|
805
|
+
* The batched driver tick and its candidate registry (extraction 6,
|
|
806
|
+
* `DEC-0025`).
|
|
807
|
+
*
|
|
808
|
+
* Definite-assignment because it holds {@link _wasmBackend}, which is built
|
|
809
|
+
* partway through the constructor — the same shape as {@link _hitTester}.
|
|
810
|
+
*/
|
|
811
|
+
private _driverTicker;
|
|
812
|
+
/**
|
|
813
|
+
* The candidate set, for the unedited suite.
|
|
814
|
+
*
|
|
815
|
+
* `test/wasm/scene-anim-batch.test.ts` reads it through a cast at four sites to
|
|
816
|
+
* assert the registry self-prunes, unregisters a removed subtree, and
|
|
817
|
+
* re-registers a re-added one. `protected` rather than `private` because it has
|
|
818
|
+
* no in-class reader and `noUnusedLocals` fails the build on a private with
|
|
819
|
+
* none (`DEC-0019` rule 4).
|
|
820
|
+
*/
|
|
821
|
+
protected get _activeDriverEntities(): Set<Entity>;
|
|
973
822
|
/**
|
|
974
823
|
* Minimum number of batchable (spring, or named-easing tween) active drivers
|
|
975
824
|
* before a frame engages the WASM batch path at all; below it, every driver
|
|
@@ -1037,7 +886,6 @@ export declare class Scene {
|
|
|
1037
886
|
* Setting {@link animDriverGateCount} overwrites all three, so existing code
|
|
1038
887
|
* that tuned the single knob keeps working unchanged.
|
|
1039
888
|
*/
|
|
1040
|
-
private _animBatchedLastFrame;
|
|
1041
889
|
/**
|
|
1042
890
|
* Whether the WASM batch path actually ran on the most recent frame.
|
|
1043
891
|
*
|
|
@@ -1068,7 +916,6 @@ export declare class Scene {
|
|
|
1068
916
|
* if WASM is now available (not necessarily active every frame).
|
|
1069
917
|
*/
|
|
1070
918
|
enableWasmAnimBatching(source: AnimModuleSource): Promise<boolean>;
|
|
1071
|
-
private _particleWasm;
|
|
1072
919
|
/** Which backend runs the CPU particle simulation. Reflects only whether a
|
|
1073
920
|
* backend is installed (the WebGPU compute path, when active, is used first
|
|
1074
921
|
* regardless). */
|
|
@@ -1121,25 +968,6 @@ export declare class Scene {
|
|
|
1121
968
|
* pre-pass.
|
|
1122
969
|
*/
|
|
1123
970
|
private _tickBatchedDrivers;
|
|
1124
|
-
/**
|
|
1125
|
-
* Compose the whole main tree's world matrices through the resident WASM store
|
|
1126
|
-
* and return the world-matrix views for the render walk to read. Rebuilds the
|
|
1127
|
-
* store layout (slots + runs) only when the tree structure changed since the
|
|
1128
|
-
* last rebuild; otherwise it just gathers current transforms into the resident
|
|
1129
|
-
* input view and runs the kernel. Returns `null` if there is no backend.
|
|
1130
|
-
*/
|
|
1131
|
-
private _syncWasmStore;
|
|
1132
|
-
/**
|
|
1133
|
-
* Run the WASM world-AABB pass over the current frame's world matrices, so the
|
|
1134
|
-
* fused hit gather can read AABBs straight out of the store.
|
|
1135
|
-
*
|
|
1136
|
-
* Local bounds are uploaded here rather than in the per-frame transform sync
|
|
1137
|
-
* because `getBounds()` is a virtual call that allocates a rect on most
|
|
1138
|
-
* entities — paying it every frame for a query that may never come would move
|
|
1139
|
-
* cost onto the render path to save it on hover. Returns `false` if any entity
|
|
1140
|
-
* cannot supply bounds through the store, so the caller uses the JS gather.
|
|
1141
|
-
*/
|
|
1142
|
-
private _ensureWasmAabbs;
|
|
1143
971
|
/**
|
|
1144
972
|
* Authoritative paint order for semantic nodes discovered during the main
|
|
1145
973
|
* render. A node may not have a DOM projection until the following a11y
|
|
@@ -1263,48 +1091,22 @@ export declare class Scene {
|
|
|
1263
1091
|
* on the same canvas, restore DPR/size, and repaint.
|
|
1264
1092
|
*/
|
|
1265
1093
|
private setupGLContextRecovery;
|
|
1266
|
-
private endContentSelectionDrag;
|
|
1267
|
-
/**
|
|
1268
|
-
* Index of the carrier line currently holding a selection inside `el`, or
|
|
1269
|
-
* `null`.
|
|
1270
|
-
*
|
|
1271
|
-
* Lets a partial re-materialization decide whether the user's selection is even
|
|
1272
|
-
* affected. Checks the tracked anchor first (it survives a drag) and falls back
|
|
1273
|
-
* to the live DOM selection.
|
|
1274
|
-
*/
|
|
1275
|
-
private contentGridSelectionLine;
|
|
1276
|
-
/**
|
|
1277
|
-
* Does the document hold a selection right now, memoized for this sync walk?
|
|
1278
|
-
*
|
|
1279
|
-
* Pays one forced layout per walk instead of one per rebuilt element — see
|
|
1280
|
-
* {@link Scene.contentSelectionPresentThisSync} for the measurements. When the
|
|
1281
|
-
* answer is `false` no element can own a selection, so every per-element
|
|
1282
|
-
* ownership test can be skipped without touching the object.
|
|
1283
|
-
*/
|
|
1284
|
-
private contentSelectionPresent;
|
|
1285
|
-
private releaseContentSelectionForRebuild;
|
|
1286
|
-
/**
|
|
1287
|
-
* Rebuild a content-projection element's DOM (`rebuild`) while preserving a
|
|
1288
|
-
* text selection the user made inside it. A streaming message replaces its
|
|
1289
|
-
* projection children on every appended chunk; without this, a selection in
|
|
1290
|
-
* the UNCHANGED prefix is wiped on each frame ("can't select text in a
|
|
1291
|
-
* message still receiving tokens"). We snapshot the selection's anchor/focus
|
|
1292
|
-
* as linear character offsets within `el` before the rebuild and re-resolve
|
|
1293
|
-
* them against the new DOM after, clamped to the new text length.
|
|
1294
|
-
*
|
|
1295
|
-
* Only fires when `el` owns the current selection and there is no active drag
|
|
1296
|
-
* (mid-drag the browser is authoritative). The virtualization case — where
|
|
1297
|
-
* `el` itself is removed from the DOM — is out of scope here (the node is
|
|
1298
|
-
* genuinely freed; the browser clears the selection and there is nothing to
|
|
1299
|
-
* restore against).
|
|
1300
|
-
*/
|
|
1301
|
-
private preserveContentSelectionAcrossRebuild;
|
|
1302
1094
|
/**
|
|
1303
1095
|
* Expose the underlying {@link IRenderer} for advanced direct-draw operations.
|
|
1304
1096
|
*
|
|
1305
1097
|
* @returns The active renderer instance.
|
|
1306
1098
|
*/
|
|
1307
1099
|
getRenderer(): IRenderer;
|
|
1100
|
+
/**
|
|
1101
|
+
* Finds the topmost interactive entity at the given coordinates.
|
|
1102
|
+
*
|
|
1103
|
+
* Delegates to {@link HitTester}. The frame stamp and the logical size are
|
|
1104
|
+
* passed in rather than reached for: `currentFrame` is the scheduler's
|
|
1105
|
+
* (extraction 6) and `width`/`height` are mutated by `resize`
|
|
1106
|
+
* (extraction 5), so neither can be captured at construction
|
|
1107
|
+
* (`DEC-0019` rule 5).
|
|
1108
|
+
*/
|
|
1109
|
+
findEntityAt(x: number, y: number): Entity | null;
|
|
1308
1110
|
/** Convert browser viewport coordinates into this Scene's logical coordinates. */
|
|
1309
1111
|
clientToScene(clientX: number, clientY: number): {
|
|
1310
1112
|
x: number;
|
|
@@ -1318,18 +1120,6 @@ export declare class Scene {
|
|
|
1318
1120
|
* @example scene.add(new CircleEntity());
|
|
1319
1121
|
*/
|
|
1320
1122
|
add(entity: Entity): this;
|
|
1321
|
-
/**
|
|
1322
|
-
* Reset per-grid calibration and bookkeeping before a (re)materialization.
|
|
1323
|
-
*
|
|
1324
|
-
* @param entityId - Owning entity, keyed into the calibration maps.
|
|
1325
|
-
* @param el - The projection element.
|
|
1326
|
-
* @param releaseSelection - Whether to drop a selection this element owns.
|
|
1327
|
-
* Pass `false` when carrier lines are being reused: the selection's DOM nodes
|
|
1328
|
-
* survive the pass, so tearing it down would wipe a user's selection on every
|
|
1329
|
-
* streamed chunk — the exact bug `preserveContentSelectionAcrossRebuild`
|
|
1330
|
-
* exists to prevent on the non-grid path.
|
|
1331
|
-
*/
|
|
1332
|
-
private clearContentGridState;
|
|
1333
1123
|
/**
|
|
1334
1124
|
* Drop any projected elements under `node` without touching the entity tree.
|
|
1335
1125
|
*
|
|
@@ -1484,13 +1274,6 @@ export declare class Scene {
|
|
|
1484
1274
|
* directly rather than rebuilding a tree.
|
|
1485
1275
|
*/
|
|
1486
1276
|
get structureVersion(): number;
|
|
1487
|
-
/**
|
|
1488
|
-
* Record who marked the scene dirty and why.
|
|
1489
|
-
*
|
|
1490
|
-
* Kept separate from {@link markDirty} so the hot path is not a function call
|
|
1491
|
-
* with a branch — V8 inlines the one-field version reliably.
|
|
1492
|
-
*/
|
|
1493
|
-
private recordDirtyReason;
|
|
1494
1277
|
/**
|
|
1495
1278
|
* Start or stop recording dirty attributions.
|
|
1496
1279
|
*
|
|
@@ -1668,49 +1451,15 @@ export declare class Scene {
|
|
|
1668
1451
|
*/
|
|
1669
1452
|
private projectionVisibleLocalYBand;
|
|
1670
1453
|
private syncContentProjection;
|
|
1671
|
-
/**
|
|
1672
|
-
* Materialize a prepared grid in logical source order while positioning each
|
|
1673
|
-
* carrier from the shared canvas geometry. Browser font measurement happens
|
|
1674
|
-
* later in one cold read/write batch, never inside projection synchronization.
|
|
1675
|
-
*/
|
|
1676
|
-
private syncContentGridProjection;
|
|
1677
1454
|
private getContentMetricScaleX;
|
|
1678
|
-
private scheduleContentGridCalibration;
|
|
1679
1455
|
private enforceA11yDomOrder;
|
|
1680
1456
|
/**
|
|
1681
|
-
*
|
|
1682
|
-
*
|
|
1683
|
-
*
|
|
1684
|
-
*
|
|
1685
|
-
*
|
|
1686
|
-
|
|
1687
|
-
* same position keep their scene-graph (collection) order as a tiebreak.
|
|
1688
|
-
*
|
|
1689
|
-
* Those inline values are world coordinates for a top-level mirror but
|
|
1690
|
-
* PARENT-RELATIVE for a nested one, so this list mixes coordinate spaces.
|
|
1691
|
-
* That is sound because the result is only ever applied per DOM parent
|
|
1692
|
-
* ({@link enforceA11yDomOrder} advances a cursor per parent), and all of one
|
|
1693
|
-
* parent's children share one space: a `grid`'s rows are all grid-relative, a
|
|
1694
|
-
* `row`'s cells all row-relative. Comparisons ACROSS spaces do happen while
|
|
1695
|
-
* banding, but they only affect the relative order of elements in different
|
|
1696
|
-
* parents, which no `insertBefore` ever acts on. Normalizing everything back
|
|
1697
|
-
* to world coordinates here would cost a transform per element per frame to
|
|
1698
|
-
* change nothing observable.
|
|
1699
|
-
*
|
|
1700
|
-
* Banding runs **per region** — per nearest `clipChildren` ancestor, recorded
|
|
1701
|
-
* by {@link enforceA11yDomOrder}'s collect walk — rather than once over the
|
|
1702
|
-
* whole scene. Purely visual banding is right for a screen reader but wrong
|
|
1703
|
-
* for selection: a DOM `Selection` covers everything between anchor and focus
|
|
1704
|
-
* in DOM order, so under one global banding a vertical drag through a
|
|
1705
|
-
* transcript also swallowed a sidebar whose headings happened to fall in the
|
|
1706
|
-
* same rows. Regions are laid out side by side, so ordering region-major keeps
|
|
1707
|
-
* each one a contiguous DOM run and a drag stays inside it, while reading
|
|
1708
|
-
* order *within* a region is unchanged. Regions are emitted in the order their
|
|
1709
|
-
* clipper is first reached by the depth-first walk, so a screen reader still
|
|
1710
|
-
* meets them in the author's declared order.
|
|
1711
|
-
*/
|
|
1712
|
-
private sortNormalElementsVisually;
|
|
1713
|
-
/** Keep DOM/WebGL overlay layers aligned with the canvas's CSS box. */
|
|
1457
|
+
* Keep DOM/WebGL overlay layers aligned with the canvas's CSS box.
|
|
1458
|
+
*
|
|
1459
|
+
* The logical size and the lazily-created layers are threaded through rather
|
|
1460
|
+
* than held: `resize` mutates `width`/`height`, and `gpuCanvas` does not exist
|
|
1461
|
+
* until the WebGPU particle path first runs (`DEC-0019` rule 5).
|
|
1462
|
+
*/
|
|
1714
1463
|
private syncOverlayGeometry;
|
|
1715
1464
|
getA11yTree(): A11yTreeNode[];
|
|
1716
1465
|
private renderPortalDOM;
|
|
@@ -1762,9 +1511,6 @@ export declare class Scene {
|
|
|
1762
1511
|
* {@link start} instead, and rejecting it here would contradict that.
|
|
1763
1512
|
*/
|
|
1764
1513
|
resize(width: number, height: number): void;
|
|
1765
|
-
/** Effective device pixel ratio, matching CanvasRenderer: real DPR clamped to
|
|
1766
|
-
* `maxDPR` when set. */
|
|
1767
|
-
private effectiveDPR;
|
|
1768
1514
|
/** Size the WebGPU particle canvas: backing store at logical × DPR, CSS box at
|
|
1769
1515
|
* the logical size. Sizing the backing store in logical px (the old
|
|
1770
1516
|
* behavior) left it rasterized at 1× and CSS-stretched — blurry on HiDPI. */
|
|
@@ -1779,29 +1525,10 @@ export declare class Scene {
|
|
|
1779
1525
|
* Gets the root entity of the scene.
|
|
1780
1526
|
*/
|
|
1781
1527
|
getRoot(): Entity;
|
|
1782
|
-
/**
|
|
1783
|
-
* Finds the topmost interactive entity at the given coordinates.
|
|
1784
|
-
*/
|
|
1785
|
-
findEntityAt(x: number, y: number): Entity | null;
|
|
1786
1528
|
/** Submit one transparent clear pass when particle content lingers on the GPU canvas. */
|
|
1787
1529
|
private clearGPUCanvasIfStale;
|
|
1788
1530
|
private initWebGPUContext;
|
|
1789
1531
|
private setupDeviceLostHandler;
|
|
1790
1532
|
private recreateWebGPUDeviceWithRetry;
|
|
1791
1533
|
private renderCPUParticles;
|
|
1792
|
-
private findHitRecursively;
|
|
1793
|
-
/** Whether `node` opts out of being a pointer hit target: a disabled control
|
|
1794
|
-
* or an explicit `pointerEvents: 'none'` in its a11y attributes. Its children
|
|
1795
|
-
* are still walked (a transparent container can hold hittable descendants). */
|
|
1796
|
-
private isPointerTransparent;
|
|
1797
|
-
/**
|
|
1798
|
-
* Whether a confirmed geometric hit on `node` at world `(x, y)` is a REAL hit,
|
|
1799
|
-
* applying the same visibility/input gating as {@link findHitRecursively} but
|
|
1800
|
-
* from a flat candidate (the WASM grid has no recursion clip-stack): the node
|
|
1801
|
-
* and all ancestors are visible (`opacity > 0`), the point lies inside every
|
|
1802
|
-
* `clipChildren` ancestor's world box, and the node isn't pointer-transparent
|
|
1803
|
-
* (disabled / `pointerEvents: 'none'`). Keeps the WASM and JS hit paths in
|
|
1804
|
-
* lockstep so they return the same entity.
|
|
1805
|
-
*/
|
|
1806
|
-
private isHitEligible;
|
|
1807
1534
|
}
|