@vectojs/core 1.32.6 → 1.33.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-TRT2TRCW.js → chunk-UEIZDNK7.js} +102 -71
- package/dist/{chunk-RWN3ITBD.mjs → chunk-VFQMETOR.mjs} +31 -0
- package/dist/components/SplineEntity.d.ts +28 -4
- package/dist/index.js +3166 -2268
- package/dist/index.mjs +2904 -2006
- package/dist/text.js +2 -2
- package/dist/text.mjs +1 -1
- package/dist/tree/Entity.d.ts +29 -0
- package/dist/tree/Scene.d.ts +215 -465
- package/dist/tree/scene/A11yProjectionManager.d.ts +147 -0
- package/dist/tree/scene/CanvasGeometry.d.ts +106 -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-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`).
|
|
608
|
+
*
|
|
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.
|
|
613
|
+
*/
|
|
614
|
+
private _contentProjection;
|
|
615
|
+
/** Grid carrier materialization (the projection walk's separable leaf). */
|
|
616
|
+
private _gridProjector;
|
|
617
|
+
/**
|
|
618
|
+
* Pending grid-calibration frames, keyed by entity id.
|
|
619
|
+
*
|
|
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).
|
|
626
|
+
*/
|
|
627
|
+
protected get contentGridCalibrationFrames(): ReadonlyMap<string, number>;
|
|
628
|
+
/**
|
|
629
|
+
* Index of the carrier line holding a selection inside `el`, or `null`.
|
|
765
630
|
*
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
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.
|
|
769
635
|
*/
|
|
770
|
-
|
|
636
|
+
protected contentGridSelectionLine(el: HTMLElement): number | null;
|
|
771
637
|
/**
|
|
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.
|
|
638
|
+
* Whether the projected a11y DOM needs reordering on the next pass.
|
|
776
639
|
*
|
|
777
|
-
*
|
|
778
|
-
*
|
|
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.
|
|
779
645
|
*/
|
|
780
|
-
|
|
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,14 +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
|
-
|
|
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();
|
|
802
714
|
private _computeEntities;
|
|
803
715
|
private _computeEntitiesVersion;
|
|
804
716
|
/** Invalidate the resident WASM store layout; the next wasm-mode frame rebuilds
|
|
@@ -837,25 +749,6 @@ export declare class Scene {
|
|
|
837
749
|
* Resolves `true` if WASM is now active, `false` if the JS path remains.
|
|
838
750
|
*/
|
|
839
751
|
enableWasmTransforms(source: WasmModuleSource): Promise<boolean>;
|
|
840
|
-
/**
|
|
841
|
-
* The one WASM instance this Scene's accelerators share.
|
|
842
|
-
*
|
|
843
|
-
* Each `enableWasm*` used to instantiate the binary itself, so enabling all
|
|
844
|
-
* four compiled the same module four times and held four linear memories. The
|
|
845
|
-
* Rust crate already keeps transform/anim/hit/particle in separate statics, so
|
|
846
|
-
* one instance serves all of them without aliasing. The compiled module is
|
|
847
|
-
* cached globally; the instance is per-Scene, which is the isolation that
|
|
848
|
-
* actually matters.
|
|
849
|
-
*/
|
|
850
|
-
private _wasmRuntime;
|
|
851
|
-
/**
|
|
852
|
-
* Load (or reuse) this Scene's shared WASM runtime.
|
|
853
|
-
*
|
|
854
|
-
* Returns `null` on any failure — CSP `wasm-unsafe-eval`, a 404, corrupt bytes,
|
|
855
|
-
* unsupported SIMD — so every caller keeps its JS path. Failure is the default
|
|
856
|
-
* state here, not an error path.
|
|
857
|
-
*/
|
|
858
|
-
private ensureWasmRuntime;
|
|
859
752
|
/**
|
|
860
753
|
* Install a pre-built runtime, so several Scenes can share one compile while
|
|
861
754
|
* each keeps its own stores. Pass `null` to detach (backends already installed
|
|
@@ -864,46 +757,17 @@ export declare class Scene {
|
|
|
864
757
|
setWasmRuntime(runtime: CoreWasmRuntime | null): void;
|
|
865
758
|
/** The shared WASM runtime, if one has been loaded. */
|
|
866
759
|
get wasmRuntime(): CoreWasmRuntime | null;
|
|
867
|
-
private _hitWasm;
|
|
868
|
-
private _hitGridFrame;
|
|
869
|
-
private _hitGridOk;
|
|
870
|
-
private _hitSlotEntity;
|
|
871
|
-
private _hitBoundless;
|
|
872
|
-
/** Reused buffer for the fused gather, so a pointer query allocates nothing. */
|
|
873
|
-
private _hitGatherBuffer;
|
|
874
760
|
/**
|
|
875
|
-
*
|
|
876
|
-
*
|
|
877
|
-
*
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
* Whether `compute_aabbs` has run against the current frame's world matrices.
|
|
882
|
-
* The AABB pass is only meaningful after a `compose_*`, so the fused gather
|
|
883
|
-
* must not read the views before then.
|
|
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.
|
|
884
767
|
*/
|
|
885
|
-
private
|
|
768
|
+
private _hitTester;
|
|
886
769
|
/** Did the last hit-grid build use the fused (WASM-store) gather? */
|
|
887
770
|
get hitGatherPath(): 'fused' | 'js';
|
|
888
|
-
/**
|
|
889
|
-
* Why the transform accelerator did or did not run on the most recent frame.
|
|
890
|
-
* Written by the render walk and `_syncWasmStore`.
|
|
891
|
-
*/
|
|
892
|
-
private _transformReason;
|
|
893
|
-
/** Why the batched-driver accelerator did or did not run. */
|
|
894
|
-
private _animReason;
|
|
895
|
-
/**
|
|
896
|
-
* Why the hit-test accelerator did or did not serve the last pointer query.
|
|
897
|
-
* The grid is built lazily on demand, not every frame, so this describes the
|
|
898
|
-
* most recent BUILD. Starts at `'not-installed'` because that is the truth
|
|
899
|
-
* before a backend exists; `_ensureHitGrid` moves it to `'not-applicable'`
|
|
900
|
-
* once one is installed but nothing has queried yet.
|
|
901
|
-
*/
|
|
902
|
-
private _hitReason;
|
|
903
|
-
/** Why the particle accelerator did or did not run. */
|
|
904
|
-
private _particleReason;
|
|
905
|
-
/** Which particle implementation actually simulated the most recent frame. */
|
|
906
|
-
private _particlePath;
|
|
907
771
|
/**
|
|
908
772
|
* Per-frame status of every invisible accelerator: whether each is installed,
|
|
909
773
|
* whether it actually ran on the most recent frame, and why.
|
|
@@ -918,6 +782,10 @@ export declare class Scene {
|
|
|
918
782
|
*
|
|
919
783
|
* Reflects the most recent main-renderer frame; a secondary renderer (SVG
|
|
920
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.
|
|
921
789
|
*/
|
|
922
790
|
get accelerators(): AcceleratorReport;
|
|
923
791
|
/** Which backend answers `findEntityAt` for the main tree. */
|
|
@@ -934,34 +802,23 @@ export declare class Scene {
|
|
|
934
802
|
*/
|
|
935
803
|
enableWasmHitTest(source: HitModuleSource): Promise<boolean>;
|
|
936
804
|
/**
|
|
937
|
-
*
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
941
|
-
*
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
*
|
|
949
|
-
*
|
|
950
|
-
* `
|
|
951
|
-
*
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
* conclusive: returns the correct entity or `null`, never "inconclusive".
|
|
955
|
-
*/
|
|
956
|
-
private _findEntityAtWasm;
|
|
957
|
-
private _animWasm;
|
|
958
|
-
private _activeDriverEntities;
|
|
959
|
-
private _springEntities;
|
|
960
|
-
private _springProps;
|
|
961
|
-
private _springDrivers;
|
|
962
|
-
private _tweenEntities;
|
|
963
|
-
private _tweenProps;
|
|
964
|
-
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>;
|
|
965
822
|
/**
|
|
966
823
|
* Minimum number of batchable (spring, or named-easing tween) active drivers
|
|
967
824
|
* before a frame engages the WASM batch path at all; below it, every driver
|
|
@@ -1029,7 +886,6 @@ export declare class Scene {
|
|
|
1029
886
|
* Setting {@link animDriverGateCount} overwrites all three, so existing code
|
|
1030
887
|
* that tuned the single knob keeps working unchanged.
|
|
1031
888
|
*/
|
|
1032
|
-
private _animBatchedLastFrame;
|
|
1033
889
|
/**
|
|
1034
890
|
* Whether the WASM batch path actually ran on the most recent frame.
|
|
1035
891
|
*
|
|
@@ -1060,7 +916,6 @@ export declare class Scene {
|
|
|
1060
916
|
* if WASM is now available (not necessarily active every frame).
|
|
1061
917
|
*/
|
|
1062
918
|
enableWasmAnimBatching(source: AnimModuleSource): Promise<boolean>;
|
|
1063
|
-
private _particleWasm;
|
|
1064
919
|
/** Which backend runs the CPU particle simulation. Reflects only whether a
|
|
1065
920
|
* backend is installed (the WebGPU compute path, when active, is used first
|
|
1066
921
|
* regardless). */
|
|
@@ -1113,25 +968,6 @@ export declare class Scene {
|
|
|
1113
968
|
* pre-pass.
|
|
1114
969
|
*/
|
|
1115
970
|
private _tickBatchedDrivers;
|
|
1116
|
-
/**
|
|
1117
|
-
* Compose the whole main tree's world matrices through the resident WASM store
|
|
1118
|
-
* and return the world-matrix views for the render walk to read. Rebuilds the
|
|
1119
|
-
* store layout (slots + runs) only when the tree structure changed since the
|
|
1120
|
-
* last rebuild; otherwise it just gathers current transforms into the resident
|
|
1121
|
-
* input view and runs the kernel. Returns `null` if there is no backend.
|
|
1122
|
-
*/
|
|
1123
|
-
private _syncWasmStore;
|
|
1124
|
-
/**
|
|
1125
|
-
* Run the WASM world-AABB pass over the current frame's world matrices, so the
|
|
1126
|
-
* fused hit gather can read AABBs straight out of the store.
|
|
1127
|
-
*
|
|
1128
|
-
* Local bounds are uploaded here rather than in the per-frame transform sync
|
|
1129
|
-
* because `getBounds()` is a virtual call that allocates a rect on most
|
|
1130
|
-
* entities — paying it every frame for a query that may never come would move
|
|
1131
|
-
* cost onto the render path to save it on hover. Returns `false` if any entity
|
|
1132
|
-
* cannot supply bounds through the store, so the caller uses the JS gather.
|
|
1133
|
-
*/
|
|
1134
|
-
private _ensureWasmAabbs;
|
|
1135
971
|
/**
|
|
1136
972
|
* Authoritative paint order for semantic nodes discovered during the main
|
|
1137
973
|
* render. A node may not have a DOM projection until the following a11y
|
|
@@ -1188,6 +1024,16 @@ export declare class Scene {
|
|
|
1188
1024
|
* else the canvas). Stored so `destroy()` detaches from the same element. */
|
|
1189
1025
|
private pointerEventTarget;
|
|
1190
1026
|
private hasWarnedZeroSize;
|
|
1027
|
+
/**
|
|
1028
|
+
* Latch for {@link Scene.resize}'s invalid-dimension warning.
|
|
1029
|
+
*
|
|
1030
|
+
* Separate from `hasWarnedZeroSize`: that one fires for a tolerated zero-size
|
|
1031
|
+
* scene at `start()`, this one for a rejected resize, and sharing the flag
|
|
1032
|
+
* would let either suppress the other's first (and only) report. Latched
|
|
1033
|
+
* because `resize()` is commonly driven from a `ResizeObserver`, which would
|
|
1034
|
+
* otherwise warn on every frame of a drag.
|
|
1035
|
+
*/
|
|
1036
|
+
private hasWarnedInvalidResize;
|
|
1191
1037
|
private fontLoadHandler;
|
|
1192
1038
|
private static _devMode;
|
|
1193
1039
|
/**
|
|
@@ -1245,48 +1091,22 @@ export declare class Scene {
|
|
|
1245
1091
|
* on the same canvas, restore DPR/size, and repaint.
|
|
1246
1092
|
*/
|
|
1247
1093
|
private setupGLContextRecovery;
|
|
1248
|
-
private endContentSelectionDrag;
|
|
1249
|
-
/**
|
|
1250
|
-
* Index of the carrier line currently holding a selection inside `el`, or
|
|
1251
|
-
* `null`.
|
|
1252
|
-
*
|
|
1253
|
-
* Lets a partial re-materialization decide whether the user's selection is even
|
|
1254
|
-
* affected. Checks the tracked anchor first (it survives a drag) and falls back
|
|
1255
|
-
* to the live DOM selection.
|
|
1256
|
-
*/
|
|
1257
|
-
private contentGridSelectionLine;
|
|
1258
|
-
/**
|
|
1259
|
-
* Does the document hold a selection right now, memoized for this sync walk?
|
|
1260
|
-
*
|
|
1261
|
-
* Pays one forced layout per walk instead of one per rebuilt element — see
|
|
1262
|
-
* {@link Scene.contentSelectionPresentThisSync} for the measurements. When the
|
|
1263
|
-
* answer is `false` no element can own a selection, so every per-element
|
|
1264
|
-
* ownership test can be skipped without touching the object.
|
|
1265
|
-
*/
|
|
1266
|
-
private contentSelectionPresent;
|
|
1267
|
-
private releaseContentSelectionForRebuild;
|
|
1268
|
-
/**
|
|
1269
|
-
* Rebuild a content-projection element's DOM (`rebuild`) while preserving a
|
|
1270
|
-
* text selection the user made inside it. A streaming message replaces its
|
|
1271
|
-
* projection children on every appended chunk; without this, a selection in
|
|
1272
|
-
* the UNCHANGED prefix is wiped on each frame ("can't select text in a
|
|
1273
|
-
* message still receiving tokens"). We snapshot the selection's anchor/focus
|
|
1274
|
-
* as linear character offsets within `el` before the rebuild and re-resolve
|
|
1275
|
-
* them against the new DOM after, clamped to the new text length.
|
|
1276
|
-
*
|
|
1277
|
-
* Only fires when `el` owns the current selection and there is no active drag
|
|
1278
|
-
* (mid-drag the browser is authoritative). The virtualization case — where
|
|
1279
|
-
* `el` itself is removed from the DOM — is out of scope here (the node is
|
|
1280
|
-
* genuinely freed; the browser clears the selection and there is nothing to
|
|
1281
|
-
* restore against).
|
|
1282
|
-
*/
|
|
1283
|
-
private preserveContentSelectionAcrossRebuild;
|
|
1284
1094
|
/**
|
|
1285
1095
|
* Expose the underlying {@link IRenderer} for advanced direct-draw operations.
|
|
1286
1096
|
*
|
|
1287
1097
|
* @returns The active renderer instance.
|
|
1288
1098
|
*/
|
|
1289
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;
|
|
1290
1110
|
/** Convert browser viewport coordinates into this Scene's logical coordinates. */
|
|
1291
1111
|
clientToScene(clientX: number, clientY: number): {
|
|
1292
1112
|
x: number;
|
|
@@ -1300,18 +1120,6 @@ export declare class Scene {
|
|
|
1300
1120
|
* @example scene.add(new CircleEntity());
|
|
1301
1121
|
*/
|
|
1302
1122
|
add(entity: Entity): this;
|
|
1303
|
-
/**
|
|
1304
|
-
* Reset per-grid calibration and bookkeeping before a (re)materialization.
|
|
1305
|
-
*
|
|
1306
|
-
* @param entityId - Owning entity, keyed into the calibration maps.
|
|
1307
|
-
* @param el - The projection element.
|
|
1308
|
-
* @param releaseSelection - Whether to drop a selection this element owns.
|
|
1309
|
-
* Pass `false` when carrier lines are being reused: the selection's DOM nodes
|
|
1310
|
-
* survive the pass, so tearing it down would wipe a user's selection on every
|
|
1311
|
-
* streamed chunk — the exact bug `preserveContentSelectionAcrossRebuild`
|
|
1312
|
-
* exists to prevent on the non-grid path.
|
|
1313
|
-
*/
|
|
1314
|
-
private clearContentGridState;
|
|
1315
1123
|
/**
|
|
1316
1124
|
* Drop any projected elements under `node` without touching the entity tree.
|
|
1317
1125
|
*
|
|
@@ -1376,7 +1184,8 @@ export declare class Scene {
|
|
|
1376
1184
|
/**
|
|
1377
1185
|
* Begin the `requestAnimationFrame` render loop.
|
|
1378
1186
|
*
|
|
1379
|
-
* Idempotent — calling `start()` on an already-running scene is a no-op
|
|
1187
|
+
* Idempotent — calling `start()` on an already-running scene is a no-op, and so
|
|
1188
|
+
* is calling it on a destroyed one.
|
|
1380
1189
|
*/
|
|
1381
1190
|
start(): void;
|
|
1382
1191
|
/** Schedule the next frame, or no-op where `requestAnimationFrame` is absent (SSR). */
|
|
@@ -1465,13 +1274,6 @@ export declare class Scene {
|
|
|
1465
1274
|
* directly rather than rebuilding a tree.
|
|
1466
1275
|
*/
|
|
1467
1276
|
get structureVersion(): number;
|
|
1468
|
-
/**
|
|
1469
|
-
* Record who marked the scene dirty and why.
|
|
1470
|
-
*
|
|
1471
|
-
* Kept separate from {@link markDirty} so the hot path is not a function call
|
|
1472
|
-
* with a branch — V8 inlines the one-field version reliably.
|
|
1473
|
-
*/
|
|
1474
|
-
private recordDirtyReason;
|
|
1475
1277
|
/**
|
|
1476
1278
|
* Start or stop recording dirty attributions.
|
|
1477
1279
|
*
|
|
@@ -1649,49 +1451,15 @@ export declare class Scene {
|
|
|
1649
1451
|
*/
|
|
1650
1452
|
private projectionVisibleLocalYBand;
|
|
1651
1453
|
private syncContentProjection;
|
|
1652
|
-
/**
|
|
1653
|
-
* Materialize a prepared grid in logical source order while positioning each
|
|
1654
|
-
* carrier from the shared canvas geometry. Browser font measurement happens
|
|
1655
|
-
* later in one cold read/write batch, never inside projection synchronization.
|
|
1656
|
-
*/
|
|
1657
|
-
private syncContentGridProjection;
|
|
1658
1454
|
private getContentMetricScaleX;
|
|
1659
|
-
private scheduleContentGridCalibration;
|
|
1660
1455
|
private enforceA11yDomOrder;
|
|
1661
1456
|
/**
|
|
1662
|
-
*
|
|
1663
|
-
*
|
|
1664
|
-
*
|
|
1665
|
-
*
|
|
1666
|
-
*
|
|
1667
|
-
|
|
1668
|
-
* same position keep their scene-graph (collection) order as a tiebreak.
|
|
1669
|
-
*
|
|
1670
|
-
* Those inline values are world coordinates for a top-level mirror but
|
|
1671
|
-
* PARENT-RELATIVE for a nested one, so this list mixes coordinate spaces.
|
|
1672
|
-
* That is sound because the result is only ever applied per DOM parent
|
|
1673
|
-
* ({@link enforceA11yDomOrder} advances a cursor per parent), and all of one
|
|
1674
|
-
* parent's children share one space: a `grid`'s rows are all grid-relative, a
|
|
1675
|
-
* `row`'s cells all row-relative. Comparisons ACROSS spaces do happen while
|
|
1676
|
-
* banding, but they only affect the relative order of elements in different
|
|
1677
|
-
* parents, which no `insertBefore` ever acts on. Normalizing everything back
|
|
1678
|
-
* to world coordinates here would cost a transform per element per frame to
|
|
1679
|
-
* change nothing observable.
|
|
1680
|
-
*
|
|
1681
|
-
* Banding runs **per region** — per nearest `clipChildren` ancestor, recorded
|
|
1682
|
-
* by {@link enforceA11yDomOrder}'s collect walk — rather than once over the
|
|
1683
|
-
* whole scene. Purely visual banding is right for a screen reader but wrong
|
|
1684
|
-
* for selection: a DOM `Selection` covers everything between anchor and focus
|
|
1685
|
-
* in DOM order, so under one global banding a vertical drag through a
|
|
1686
|
-
* transcript also swallowed a sidebar whose headings happened to fall in the
|
|
1687
|
-
* same rows. Regions are laid out side by side, so ordering region-major keeps
|
|
1688
|
-
* each one a contiguous DOM run and a drag stays inside it, while reading
|
|
1689
|
-
* order *within* a region is unchanged. Regions are emitted in the order their
|
|
1690
|
-
* clipper is first reached by the depth-first walk, so a screen reader still
|
|
1691
|
-
* meets them in the author's declared order.
|
|
1692
|
-
*/
|
|
1693
|
-
private sortNormalElementsVisually;
|
|
1694
|
-
/** 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
|
+
*/
|
|
1695
1463
|
private syncOverlayGeometry;
|
|
1696
1464
|
getA11yTree(): A11yTreeNode[];
|
|
1697
1465
|
private renderPortalDOM;
|
|
@@ -1737,11 +1505,12 @@ export declare class Scene {
|
|
|
1737
1505
|
toSVG(): string;
|
|
1738
1506
|
/**
|
|
1739
1507
|
* Manually resize the Scene's viewport.
|
|
1508
|
+
*
|
|
1509
|
+
* Rejects a negative or non-finite dimension, keeping the last known-good
|
|
1510
|
+
* size. `0` is accepted: a zero-size scene is tolerated and warned about at
|
|
1511
|
+
* {@link start} instead, and rejecting it here would contradict that.
|
|
1740
1512
|
*/
|
|
1741
1513
|
resize(width: number, height: number): void;
|
|
1742
|
-
/** Effective device pixel ratio, matching CanvasRenderer: real DPR clamped to
|
|
1743
|
-
* `maxDPR` when set. */
|
|
1744
|
-
private effectiveDPR;
|
|
1745
1514
|
/** Size the WebGPU particle canvas: backing store at logical × DPR, CSS box at
|
|
1746
1515
|
* the logical size. Sizing the backing store in logical px (the old
|
|
1747
1516
|
* behavior) left it rasterized at 1× and CSS-stretched — blurry on HiDPI. */
|
|
@@ -1756,29 +1525,10 @@ export declare class Scene {
|
|
|
1756
1525
|
* Gets the root entity of the scene.
|
|
1757
1526
|
*/
|
|
1758
1527
|
getRoot(): Entity;
|
|
1759
|
-
/**
|
|
1760
|
-
* Finds the topmost interactive entity at the given coordinates.
|
|
1761
|
-
*/
|
|
1762
|
-
findEntityAt(x: number, y: number): Entity | null;
|
|
1763
1528
|
/** Submit one transparent clear pass when particle content lingers on the GPU canvas. */
|
|
1764
1529
|
private clearGPUCanvasIfStale;
|
|
1765
1530
|
private initWebGPUContext;
|
|
1766
1531
|
private setupDeviceLostHandler;
|
|
1767
1532
|
private recreateWebGPUDeviceWithRetry;
|
|
1768
1533
|
private renderCPUParticles;
|
|
1769
|
-
private findHitRecursively;
|
|
1770
|
-
/** Whether `node` opts out of being a pointer hit target: a disabled control
|
|
1771
|
-
* or an explicit `pointerEvents: 'none'` in its a11y attributes. Its children
|
|
1772
|
-
* are still walked (a transparent container can hold hittable descendants). */
|
|
1773
|
-
private isPointerTransparent;
|
|
1774
|
-
/**
|
|
1775
|
-
* Whether a confirmed geometric hit on `node` at world `(x, y)` is a REAL hit,
|
|
1776
|
-
* applying the same visibility/input gating as {@link findHitRecursively} but
|
|
1777
|
-
* from a flat candidate (the WASM grid has no recursion clip-stack): the node
|
|
1778
|
-
* and all ancestors are visible (`opacity > 0`), the point lies inside every
|
|
1779
|
-
* `clipChildren` ancestor's world box, and the node isn't pointer-transparent
|
|
1780
|
-
* (disabled / `pointerEvents: 'none'`). Keeps the WASM and JS hit paths in
|
|
1781
|
-
* lockstep so they return the same entity.
|
|
1782
|
-
*/
|
|
1783
|
-
private isHitEligible;
|
|
1784
1534
|
}
|