@vectojs/core 1.38.0 → 1.39.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-QVTCKWDO.mjs → chunk-7PYD5UDX.mjs} +93 -43
- package/dist/{chunk-ZYYP2M5D.js → chunk-KRUDTGNR.js} +168 -76
- package/dist/{chunk-SRXU3ZXK.js → chunk-POPXUPKR.js} +141 -91
- package/dist/{chunk-LWEMD34D.mjs → chunk-RUM2KEDI.mjs} +119 -27
- package/dist/index.js +689 -396
- package/dist/index.mjs +375 -82
- package/dist/renderer/CanvasRenderer.d.ts +6 -0
- package/dist/renderer/SVGRenderer.d.ts +17 -2
- package/dist/renderer/WebGPUParticleSystemManager.d.ts +2 -0
- package/dist/renderer.js +2 -2
- package/dist/renderer.mjs +1 -1
- package/dist/text/MSDFTextEntity.d.ts +0 -1
- package/dist/text.js +2 -2
- package/dist/text.mjs +1 -1
- package/dist/tree/Entity.d.ts +8 -2
- package/dist/tree/Scene.d.ts +106 -0
- package/dist/tree/scene/A11yProjectionManager.d.ts +12 -0
- package/dist/tree/scene/HitTester.d.ts +14 -2
- package/dist/tree/scene/WasmBackendFacade.d.ts +17 -0
- package/dist/tree/scene/keyboard.d.ts +56 -0
- package/dist/wasm/backend.d.ts +7 -7
- package/dist/wasm/vectojs_core.wasm +0 -0
- package/package.json +6 -6
|
@@ -39,6 +39,12 @@ export declare class CanvasRenderer implements IRenderer {
|
|
|
39
39
|
private batchCount;
|
|
40
40
|
private _cachedFont;
|
|
41
41
|
private _cachedFill;
|
|
42
|
+
private _cachedStroke;
|
|
43
|
+
private _cachedLineWidth;
|
|
44
|
+
private _cachedLineCap;
|
|
45
|
+
private _cachedLineJoin;
|
|
46
|
+
private _onContextLost?;
|
|
47
|
+
private _onContextRestored?;
|
|
42
48
|
/** Backend discriminator; see {@link IRenderer.kind}. */
|
|
43
49
|
readonly kind = "canvas2d";
|
|
44
50
|
/**
|
|
@@ -39,7 +39,11 @@ export declare class SVGRenderer implements IRenderer {
|
|
|
39
39
|
private batchActive;
|
|
40
40
|
private gradientCounter;
|
|
41
41
|
private gradientCache;
|
|
42
|
-
|
|
42
|
+
/** Root font size used to resolve `em`/`rem` font sizes (default 16px). */
|
|
43
|
+
private rootFontSize;
|
|
44
|
+
constructor(width: number, height: number, options?: {
|
|
45
|
+
rootFontSize?: number;
|
|
46
|
+
});
|
|
43
47
|
clear(): void;
|
|
44
48
|
save(): void;
|
|
45
49
|
restore(): void;
|
|
@@ -56,6 +60,16 @@ export declare class SVGRenderer implements IRenderer {
|
|
|
56
60
|
roundRect(x: number, y: number, w: number, h: number, radii: number | number[]): void;
|
|
57
61
|
fill(colorOrGradient: string | SVGLinearGradient): void;
|
|
58
62
|
stroke(colorOrGradient: string | SVGLinearGradient, lineWidth?: number): void;
|
|
63
|
+
/**
|
|
64
|
+
* Emit a `<text>` element for a text run.
|
|
65
|
+
*
|
|
66
|
+
* Font-size unit handling: `px` sizes pass through; `em` and `rem` are both
|
|
67
|
+
* scaled against the renderer's `rootFontSize` (constructor option, default
|
|
68
|
+
* 16 — matching the browser default, not necessarily the host page's root,
|
|
69
|
+
* so pass `{ rootFontSize }` when exporting against a non-default root).
|
|
70
|
+
* A percentage size (`'100% Inter'`) has no absolute meaning in this
|
|
71
|
+
* context and silently falls back to the default 16px font size.
|
|
72
|
+
*/
|
|
59
73
|
fillText(text: string, x: number, y: number, font: string, color: string | SVGLinearGradient): void;
|
|
60
74
|
fillCircle(cx: number, cy: number, radius: number, color: string, alpha?: number): void;
|
|
61
75
|
drawImage(source: any, dx: number, dy: number, dw: number, dh: number): void;
|
|
@@ -79,7 +93,8 @@ export declare class SVGRenderer implements IRenderer {
|
|
|
79
93
|
private isSafeRasterDataUrl;
|
|
80
94
|
/**
|
|
81
95
|
* SVGRenderer accumulates strings in memory; nothing external is allocated.
|
|
82
|
-
* Drop the buffers for GC and become idempotent.
|
|
96
|
+
* Drop the buffers for GC and become idempotent. `clear()` already empties
|
|
97
|
+
* the gradient cache, so no second clear is needed here.
|
|
83
98
|
*/
|
|
84
99
|
dispose(): void;
|
|
85
100
|
}
|
|
@@ -3,6 +3,8 @@ export declare class WebGPUParticleSystemManager {
|
|
|
3
3
|
private device;
|
|
4
4
|
private computePipeline;
|
|
5
5
|
private renderPipeline;
|
|
6
|
+
private computeModule;
|
|
7
|
+
private renderModule;
|
|
6
8
|
private computeBindGroupLayout;
|
|
7
9
|
private renderBindGroupLayout;
|
|
8
10
|
constructor(device: GPUDevice);
|
package/dist/renderer.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var _chunkKRUDTGNRjs = require('./chunk-KRUDTGNR.js');
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
@@ -22,4 +22,4 @@ var _chunkZYYP2M5Djs = require('./chunk-ZYYP2M5D.js');
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
exports.CanvasRenderer =
|
|
25
|
+
exports.CanvasRenderer = _chunkKRUDTGNRjs.CanvasRenderer; exports.GlyphRasterAtlas = _chunkKRUDTGNRjs.GlyphRasterAtlas; exports.SVGRenderer = _chunkKRUDTGNRjs.SVGRenderer; exports.TextRasterCache = _chunkKRUDTGNRjs.TextRasterCache; exports.WebGPUParticleSystemManager = _chunkKRUDTGNRjs.WebGPUParticleSystemManager; exports.createWebGLPointRenderer = _chunkKRUDTGNRjs.createWebGLPointRenderer; exports.installRendererDevTraps = _chunkKRUDTGNRjs.installRendererDevTraps; exports.isRendererDevMode = _chunkKRUDTGNRjs.isRendererDevMode; exports.parseColorToRGBA = _chunkKRUDTGNRjs.parseColorToRGBA; exports.setRendererDevMode = _chunkKRUDTGNRjs.setRendererDevMode;
|
package/dist/renderer.mjs
CHANGED
package/dist/text.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkPOPXUPKRjs = require('./chunk-POPXUPKR.js');
|
|
6
6
|
|
|
7
7
|
// src/text/index.ts
|
|
8
8
|
var _text = require('@vectojs/text'); _createStarExport(_text);
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
exports.MSDFTextEntity =
|
|
12
|
+
exports.MSDFTextEntity = _chunkPOPXUPKRjs.MSDFTextEntity; exports.SVGEntity = _chunkPOPXUPKRjs.SVGEntity;
|
package/dist/text.mjs
CHANGED
package/dist/tree/Entity.d.ts
CHANGED
|
@@ -856,8 +856,6 @@ export declare abstract class Entity {
|
|
|
856
856
|
* only by Scene, never application code.
|
|
857
857
|
*/
|
|
858
858
|
_applyDriverTick(prop: AnimatableProp, driver: PropertyDriver): void;
|
|
859
|
-
/** Internal: true if this entity currently has any active property driver. */
|
|
860
|
-
_hasActiveDrivers(): boolean;
|
|
861
859
|
/**
|
|
862
860
|
* Advance the entity's internal state for one frame.
|
|
863
861
|
*
|
|
@@ -1011,6 +1009,14 @@ export declare abstract class Entity {
|
|
|
1011
1009
|
* Accumulated world rotation: this entity's own `rotation` plus
|
|
1012
1010
|
* that of every ancestor.
|
|
1013
1011
|
*
|
|
1012
|
+
* Valid only under positive scales: the sum models the composed matrix
|
|
1013
|
+
* `T*S*R` correctly while every ancestor's `scaleX`/`scaleY` is positive,
|
|
1014
|
+
* but a mirrored (negative-scale) ancestor flips handedness, which an
|
|
1015
|
+
* additive sum cannot represent — the result is then off by the mirror.
|
|
1016
|
+
* For mirror-safe rotation, derive the angle from
|
|
1017
|
+
* {@link getWorldTransform}'s matrix (e.g. `atan2(b, a)`), as SVGEntity's
|
|
1018
|
+
* signed-scale handling already does.
|
|
1019
|
+
*
|
|
1014
1020
|
* @returns The accumulated world rotation in radians.
|
|
1015
1021
|
*/
|
|
1016
1022
|
getWorldRotation(): number;
|
package/dist/tree/Scene.d.ts
CHANGED
|
@@ -22,7 +22,31 @@ import { type OverlayGeometry } from './scene/CanvasGeometry';
|
|
|
22
22
|
import { type DirtyReasonEntry, type DirtySource } from './scene/DirtyTracker';
|
|
23
23
|
import { type RenderPhase, type RenderPhaseEntry } from './scene/PhaseTimer';
|
|
24
24
|
import { type AcceleratorReason, type AcceleratorReport, type AcceleratorStatus } from './scene/WasmBackendFacade';
|
|
25
|
+
import { type SceneKeyEvent, type SceneShortcutSpec } from './scene/keyboard';
|
|
25
26
|
export type { RenderPhase, RenderPhaseEntry };
|
|
27
|
+
export { normalizeChord } from './scene/keyboard';
|
|
28
|
+
export type { SceneKeyEvent, SceneShortcutSpec } from './scene/keyboard';
|
|
29
|
+
/**
|
|
30
|
+
* Roles whose focused element is considered to own the keyboard, so the
|
|
31
|
+
* scene-level keydown/keyup channel stays silent while one of them holds
|
|
32
|
+
* focus (arrow keys must move a slider, typing must reach a textbox, …).
|
|
33
|
+
*
|
|
34
|
+
* {@link INTERACTIVE_A11Y_ROLES} plus the text-selection/list roles that are
|
|
35
|
+
* keyboard-first but not "interactive" in the pointer sense.
|
|
36
|
+
*/
|
|
37
|
+
export declare const KEYBOARD_OWNING_ROLES: ReadonlySet<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Whether `el` (typically `document.activeElement`) currently owns the
|
|
40
|
+
* keyboard and should suppress the scene-level keyboard channel.
|
|
41
|
+
*
|
|
42
|
+
* Never owning: `null`, `document.body`, `document.documentElement`, and the
|
|
43
|
+
* scene's own a11y root. Always owning: `INPUT`/`TEXTAREA`/`SELECT` elements
|
|
44
|
+
* and anything `contentEditable`. Otherwise owning iff its `role` attribute
|
|
45
|
+
* is in {@link KEYBOARD_OWNING_ROLES}. The gate is unconditional by design —
|
|
46
|
+
* even modifier chords (`ctrl+s`) are suppressed while an owner holds focus,
|
|
47
|
+
* because the page behind the canvas expects to keep them.
|
|
48
|
+
*/
|
|
49
|
+
export declare function ownsKeyboard(el: Element | null): boolean;
|
|
26
50
|
export type { DirtyReasonEntry, DirtySource };
|
|
27
51
|
/**
|
|
28
52
|
* Options for {@link Scene}.
|
|
@@ -489,6 +513,9 @@ export declare class Scene {
|
|
|
489
513
|
private a11yPendingSyncAfterAnimation;
|
|
490
514
|
private a11yRoot;
|
|
491
515
|
private a11yElements;
|
|
516
|
+
/** Elements that already have the synthetic Enter/Space activation handler
|
|
517
|
+
* (see the syncA11y refresh pass) — install-once bookkeeping (#694). */
|
|
518
|
+
private readonly keyboardActivatedA11y;
|
|
492
519
|
/** DOM nodes mirroring static text content, keyed by entity id. */
|
|
493
520
|
private contentElements;
|
|
494
521
|
/**
|
|
@@ -973,6 +1000,15 @@ export declare class Scene {
|
|
|
973
1000
|
* entity).
|
|
974
1001
|
*/
|
|
975
1002
|
_registerActiveDriverSubtree(entity: Entity): void;
|
|
1003
|
+
/**
|
|
1004
|
+
* The `dt` of the frame currently executing its update walk (the WASM-mode
|
|
1005
|
+
* pre-pass or the JS-mode interleaved render walk), or `null` outside it.
|
|
1006
|
+
* Read by `Entity._spawnDriver`: a driver spawned mid-walk onto an entity the
|
|
1007
|
+
* batched pass already claimed this frame must be advanced once here, or
|
|
1008
|
+
* `tickDrivers()`'s per-frame stamp would skip it a full frame — a one-frame
|
|
1009
|
+
* JS/WASM divergence. Written in {@link render} next to `_tickBatchedDrivers`.
|
|
1010
|
+
*/
|
|
1011
|
+
_updateWalkDt: number | null;
|
|
976
1012
|
/**
|
|
977
1013
|
* Advance every registered entity's active drivers for this frame, batching
|
|
978
1014
|
* whichever are batchable (`SpringDriver`; `TweenDriver` with a named
|
|
@@ -1045,6 +1081,12 @@ export declare class Scene {
|
|
|
1045
1081
|
/** Element the pointer listeners are bound to (parent container if present,
|
|
1046
1082
|
* else the canvas). Stored so `destroy()` detaches from the same element. */
|
|
1047
1083
|
private pointerEventTarget;
|
|
1084
|
+
private keydownHandlers;
|
|
1085
|
+
private keyupHandlers;
|
|
1086
|
+
/** Chord-normalized shortcut table, matched on keydown only. */
|
|
1087
|
+
private shortcuts;
|
|
1088
|
+
private windowKeyDownHandler;
|
|
1089
|
+
private windowKeyUpHandler;
|
|
1048
1090
|
private hasWarnedZeroSize;
|
|
1049
1091
|
/**
|
|
1050
1092
|
* Latch for {@link Scene.resize}'s invalid-dimension warning.
|
|
@@ -1239,6 +1281,70 @@ export declare class Scene {
|
|
|
1239
1281
|
* Call {@link start} again to resume rendering.
|
|
1240
1282
|
*/
|
|
1241
1283
|
stop(): void;
|
|
1284
|
+
/**
|
|
1285
|
+
* Register a listener on the scene-level keyboard channel.
|
|
1286
|
+
*
|
|
1287
|
+
* Mirrors {@link Entity.on} minus the options parameter (bubble-only, and
|
|
1288
|
+
* there is no capture phase for a single window tap). Handlers fire only
|
|
1289
|
+
* when ALL of these hold:
|
|
1290
|
+
*
|
|
1291
|
+
* 1. the native event was not already `defaultPrevented`,
|
|
1292
|
+
* 2. it is not an auto-repeat (`e.repeat`),
|
|
1293
|
+
* 3. `document.activeElement` does not own the keyboard
|
|
1294
|
+
* (see {@link ownsKeyboard}) — typing in an `<input>` or focusing a
|
|
1295
|
+
* slider-role element suppresses the scene channel, unconditionally,
|
|
1296
|
+
* including modifier chords.
|
|
1297
|
+
*
|
|
1298
|
+
* The listeners are window-level BUBBLE-phase taps, so an entity handler
|
|
1299
|
+
* that calls `nativeEvent.stopPropagation()` keeps the key from ever
|
|
1300
|
+
* reaching this channel. Deliberately not registered in the capture phase:
|
|
1301
|
+
* a window-capture listener would preempt Modal's document-capture trap.
|
|
1302
|
+
*
|
|
1303
|
+
* Listeners attach at `start()` and survive `stop()`; only `destroy()`
|
|
1304
|
+
* removes them.
|
|
1305
|
+
*
|
|
1306
|
+
* @param event - `'keydown'` or `'keyup'`; anything else is rejected with a
|
|
1307
|
+
* dev warning (guards JS callers — TypeScript already narrows this).
|
|
1308
|
+
* @param callback - Handler invoked with a {@link SceneKeyEvent}.
|
|
1309
|
+
* @returns `this` for method chaining.
|
|
1310
|
+
*/
|
|
1311
|
+
on(event: 'keydown' | 'keyup', callback: (e: SceneKeyEvent) => void): this;
|
|
1312
|
+
/**
|
|
1313
|
+
* Remove a listener previously registered with {@link Scene.on}. Silent
|
|
1314
|
+
* no-op for unknown handlers, unsupported event names, or after
|
|
1315
|
+
* {@link Scene.destroy}.
|
|
1316
|
+
*
|
|
1317
|
+
* @returns `this` for method chaining.
|
|
1318
|
+
*/
|
|
1319
|
+
off(event: 'keydown' | 'keyup', callback: (e: SceneKeyEvent) => void): this;
|
|
1320
|
+
/**
|
|
1321
|
+
* Sugar over the keyboard channel: invoke `spec.handler` whenever a
|
|
1322
|
+
* non-repeat `keydown` whose normalized chord matches `spec.chord`
|
|
1323
|
+
* (via {@link normalizeChord}) passes the same gates as {@link Scene.on} —
|
|
1324
|
+
* including the unconditional `ownsKeyboard(activeElement)` suppression.
|
|
1325
|
+
*
|
|
1326
|
+
* @param spec - `{ chord, handler }`; the chord is normalized once at
|
|
1327
|
+
* registration, so `'ctrl+n'`, `'Control+n'` and `'Ctrl+N'` are aliases.
|
|
1328
|
+
* @returns `this` for method chaining.
|
|
1329
|
+
*/
|
|
1330
|
+
registerShortcut(spec: SceneShortcutSpec): this;
|
|
1331
|
+
/**
|
|
1332
|
+
* Remove a shortcut previously registered with {@link Scene.registerShortcut}.
|
|
1333
|
+
* Matches on normalized chord + exact handler reference; silent no-op when
|
|
1334
|
+
* nothing matches.
|
|
1335
|
+
*
|
|
1336
|
+
* @param spec - The same spec object (chord spelling may differ; it is
|
|
1337
|
+
* re-normalized before matching).
|
|
1338
|
+
* @returns `this` for method chaining.
|
|
1339
|
+
*/
|
|
1340
|
+
unregisterShortcut(spec: SceneShortcutSpec): this;
|
|
1341
|
+
/** Attach the window bubble-phase keyboard listeners exactly once. */
|
|
1342
|
+
private attachWindowKeyListeners;
|
|
1343
|
+
/**
|
|
1344
|
+
* Gate a native keyboard event and fan it out to scene handlers +
|
|
1345
|
+
* chord-matched shortcuts. See {@link Scene.on} for the gate contract.
|
|
1346
|
+
*/
|
|
1347
|
+
private dispatchKeyboard;
|
|
1242
1348
|
/**
|
|
1243
1349
|
* Manually advance the scene clock by `dt` milliseconds and render synchronously.
|
|
1244
1350
|
* Essential for deterministic rendering (e.g. video export).
|
|
@@ -89,6 +89,18 @@ export declare class A11yProjectionManager {
|
|
|
89
89
|
* implicit root region. See {@link sortNormalElementsVisually}.
|
|
90
90
|
*/
|
|
91
91
|
private readonly orderRegions;
|
|
92
|
+
/**
|
|
93
|
+
* Decoration records for {@link sortNormalElementsVisually}: one per ordered
|
|
94
|
+
* element, pooled across passes and rewritten in place — the sort runs on
|
|
95
|
+
* structure-change frames, where the module's zero-GC policy applies.
|
|
96
|
+
*/
|
|
97
|
+
private readonly orderDecorated;
|
|
98
|
+
/** Region → decorated elements, reused by {@link sortNormalElementsVisually}. */
|
|
99
|
+
private readonly orderBucketByRegion;
|
|
100
|
+
/** Pool of bucket arrays backing {@link orderBucketByRegion} across passes. */
|
|
101
|
+
private readonly orderBuckets;
|
|
102
|
+
/** Scratch for one visual row inside {@link sortNormalElementsVisually}. */
|
|
103
|
+
private readonly orderRowScratch;
|
|
92
104
|
/** Mark the projected DOM as needing a reorder on the next pass. */
|
|
93
105
|
markNeedsReorder(): void;
|
|
94
106
|
/** Reset the per-pass collections. Zero-GC: length/clear, never reallocate. */
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
* ## What this owns
|
|
24
24
|
*
|
|
25
25
|
* The hit-grid *contents* — the slot→entity table, the boundless list, and the
|
|
26
|
-
* reused fused-gather buffer. The cache *key* (`hitGridFrame`,
|
|
26
|
+
* reused fused-gather buffer. The cache *key* (`hitGridFrame`,
|
|
27
|
+
* `hitGridStructureVersion`, `hitGridOk`) stays
|
|
27
28
|
* on {@link WasmBackendFacade}, because installing a backend has to invalidate
|
|
28
29
|
* it and that is the facade's business.
|
|
29
30
|
*
|
|
@@ -46,7 +47,8 @@
|
|
|
46
47
|
* `root` and `overlayRoot` are held: `Scene` assigns both once in its constructor
|
|
47
48
|
* and never reassigns them. The facade is held because the hit backend is reached
|
|
48
49
|
* only through its public surface (`hit`, `hitReason`, `hitGridFrame`,
|
|
49
|
-
* `hitGridOk`, `ensureAabbs()`, `slotEntity`,
|
|
50
|
+
* `hitGridStructureVersion`, `hitGridOk`, `ensureAabbs()`, `slotEntity`,
|
|
51
|
+
* `hitFusedGather`, `transform`).
|
|
50
52
|
*
|
|
51
53
|
* The frame counter and the viewport size are **per-call arguments** (`DEC-0019`
|
|
52
54
|
* rule 5): `currentFrame` belongs to the render scheduler (extraction 6) and
|
|
@@ -100,6 +102,16 @@ export declare class HitTester {
|
|
|
100
102
|
* or an explicit `pointerEvents: 'none'` in its a11y attributes. Its children
|
|
101
103
|
* are still walked (a transparent container can hold hittable descendants). */
|
|
102
104
|
private isPointerTransparent;
|
|
105
|
+
/**
|
|
106
|
+
* Exact rotation-aware `clipChildren` test shared by BOTH hit paths: the
|
|
107
|
+
* point must lie inside every clipChildren ancestor's local rect — the same
|
|
108
|
+
* shape rendering clips to — not merely inside the ancestor's world AABB.
|
|
109
|
+
* For a rotated clipper those disagree, and until both paths used the exact
|
|
110
|
+
* rect a query's answer depended on which backend was active (#680). The
|
|
111
|
+
* clip-stack AABB intersection in {@link findHitRecursively} remains purely
|
|
112
|
+
* as a subtree-pruning pre-filter; this is the authoritative gate.
|
|
113
|
+
*/
|
|
114
|
+
private isInsideAllClippers;
|
|
103
115
|
/**
|
|
104
116
|
* Whether a confirmed geometric hit on `node` at world `(x, y)` is a REAL hit,
|
|
105
117
|
* applying the same visibility/input gating as {@link findHitRecursively} but
|
|
@@ -73,6 +73,16 @@ export type AcceleratorReason =
|
|
|
73
73
|
| 'below-gate'
|
|
74
74
|
/** Installed and gated in, but the kernel rejected the call and wrote nothing. */
|
|
75
75
|
| 'rejected'
|
|
76
|
+
/**
|
|
77
|
+
* The spring kernel rejected this frame's call (JS fallback for springs) but
|
|
78
|
+
* tweens stepped through the kernel — a partial acceleration, not fully-JS.
|
|
79
|
+
*/
|
|
80
|
+
| 'springs-rejected'
|
|
81
|
+
/**
|
|
82
|
+
* The tween kernel rejected this frame's call (JS fallback for tweens) but
|
|
83
|
+
* springs stepped through the kernel — a partial acceleration, not fully-JS.
|
|
84
|
+
*/
|
|
85
|
+
| 'tweens-rejected'
|
|
76
86
|
/** Not applicable to this pass (e.g. a non-main renderer, or nothing to do). */
|
|
77
87
|
| 'not-applicable';
|
|
78
88
|
/**
|
|
@@ -239,6 +249,13 @@ export declare class WasmBackendFacade {
|
|
|
239
249
|
animBatchedLastFrame: boolean;
|
|
240
250
|
/** Frame the hit grid was last built for; `-1` forces a rebuild. */
|
|
241
251
|
hitGridFrame: number;
|
|
252
|
+
/**
|
|
253
|
+
* Structure version the hit grid was built for; `-1` forces a rebuild.
|
|
254
|
+
* Half of the cache key the comment above promises: without it, a pointer
|
|
255
|
+
* query in the same frame as a structural mutation would resolve against
|
|
256
|
+
* pre-mutation geometry while the JS walk sees live state.
|
|
257
|
+
*/
|
|
258
|
+
hitGridStructureVersion: number;
|
|
242
259
|
/** Whether that build succeeded (did not overflow its item budget). */
|
|
243
260
|
hitGridOk: boolean;
|
|
244
261
|
/**
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scene-level keyboard channel primitives shared by @vectojs/core and
|
|
3
|
+
* @vectojs/desktop.
|
|
4
|
+
*
|
|
5
|
+
* `normalizeChord` was promoted verbatim from @vectojs/desktop's
|
|
6
|
+
* ShortcutRouter so both packages share one chord-normalization
|
|
7
|
+
* implementation; desktop re-imports it from core.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Normalize a keyboard chord to a stable key used in shortcut maps.
|
|
11
|
+
* Order: Ctrl/Control, Alt, Shift, Meta, then the uppercased key.
|
|
12
|
+
*
|
|
13
|
+
* Accepts either a {@link KeyboardEvent} or a pre-written string like
|
|
14
|
+
* `Control+Shift+N`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeChord(input: KeyboardEvent | string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Payload delivered to scene-level `keydown`/`keyup` listeners registered via
|
|
19
|
+
* {@link Scene.on} and to {@link Scene.registerShortcut} handlers.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately NOT a {@link VectoJSEvent}: this channel has no entity target
|
|
22
|
+
* and no tree propagation — it is a single scene-wide window-bubble tap.
|
|
23
|
+
* `stopPropagation()`/`preventDefault()` forward to the native event so
|
|
24
|
+
* handlers written against raw DOM semantics keep working.
|
|
25
|
+
*/
|
|
26
|
+
export interface SceneKeyEvent {
|
|
27
|
+
/** Which phase of the key produced this event. */
|
|
28
|
+
type: 'keydown' | 'keyup';
|
|
29
|
+
/** Native `KeyboardEvent.key` (e.g. `'a'`, `'ArrowLeft'`, `'Enter'`). */
|
|
30
|
+
key: string;
|
|
31
|
+
/** Native `KeyboardEvent.code` (physical key, e.g. `'KeyA'`). */
|
|
32
|
+
code: string;
|
|
33
|
+
/** True while the key is auto-repeating; suppressed by the scene channel gate. */
|
|
34
|
+
repeat: boolean;
|
|
35
|
+
ctrlKey: boolean;
|
|
36
|
+
altKey: boolean;
|
|
37
|
+
shiftKey: boolean;
|
|
38
|
+
metaKey: boolean;
|
|
39
|
+
/** The DOM event target (`window` when dispatched directly at the window). */
|
|
40
|
+
target: EventTarget | null;
|
|
41
|
+
/** The originating browser event. */
|
|
42
|
+
nativeEvent: KeyboardEvent;
|
|
43
|
+
/** Forward to `nativeEvent.stopPropagation()`. */
|
|
44
|
+
stopPropagation(): void;
|
|
45
|
+
/** Forward to `nativeEvent.preventDefault()`. */
|
|
46
|
+
preventDefault(): void;
|
|
47
|
+
}
|
|
48
|
+
/** Spec for {@link Scene.registerShortcut} / {@link Scene.unregisterShortcut}. */
|
|
49
|
+
export interface SceneShortcutSpec {
|
|
50
|
+
/**
|
|
51
|
+
* Chord string like `'ctrl+shift+n'`, matched after normalization via
|
|
52
|
+
* {@link normalizeChord} (`'Control+Shift+N'`), or a live `KeyboardEvent`.
|
|
53
|
+
*/
|
|
54
|
+
chord: string;
|
|
55
|
+
handler: (e: SceneKeyEvent) => void;
|
|
56
|
+
}
|
package/dist/wasm/backend.d.ts
CHANGED
|
@@ -132,19 +132,19 @@ export declare class WasmTransformBackend {
|
|
|
132
132
|
/**
|
|
133
133
|
* Compute world-space AABBs for `store` in WASM (G1+), writing back into its
|
|
134
134
|
* `aminx/aminy/amaxx/amaxy` arrays. Uploads the local bounds, runs the AABB
|
|
135
|
-
* pass, reads results back. Result is bit-identical to `computeAabbsJS(store)
|
|
136
|
-
* `compose` (or `runKernel`) must have populated the world
|
|
137
|
-
* this pass reads them. For the resident (no-copy)
|
|
138
|
-
* via {@link boundsView} and read via
|
|
139
|
-
* {@link runAabbs} instead.
|
|
135
|
+
* pass, reads results back. Result is bit-identical to `computeAabbsJS(store)`
|
|
136
|
+
* for both kernels. `compose` (or `runKernel`) must have populated the world
|
|
137
|
+
* matrices first — this pass reads them. For the resident (no-copy)
|
|
138
|
+
* integration, write bounds via {@link boundsView} and read via
|
|
139
|
+
* {@link aabbView} + call {@link runAabbs} instead.
|
|
140
140
|
*/
|
|
141
|
-
computeAabbs(store: TransformStore): void;
|
|
141
|
+
computeAabbs(store: TransformStore, kernel?: Kernel): void;
|
|
142
142
|
/** Run the AABB pass only, over `count` entities already resident in wasm
|
|
143
143
|
* memory (bounds written via {@link boundsView}, world matrices already
|
|
144
144
|
* composed). No upload/readback — the per-frame resident path. Returns
|
|
145
145
|
* `false` if the kernel rejected `count` (beyond capacity, or uninitialized),
|
|
146
146
|
* in which case {@link aabbView} still holds the previous frame's bounds. */
|
|
147
|
-
runAabbs(count: number): boolean;
|
|
147
|
+
runAabbs(count: number, kernel?: Kernel): boolean;
|
|
148
148
|
/** Resident wasm local-bounds input views (`bx,by,bw,bh`) for the AABB pass. */
|
|
149
149
|
boundsView(): {
|
|
150
150
|
bx: Float64Array;
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vectojs/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.39.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -64,17 +64,17 @@
|
|
|
64
64
|
"test:e2e": "bun e2e/hidpi.e2e.ts && bun e2e/text-projection.e2e.ts && bun e2e/svg-fallback.e2e.ts && bun e2e/msdf-atlas-decode.e2e.ts && bun e2e/layout-worker-fallback.e2e.ts"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@vectojs/animation": "^0.1.
|
|
68
|
-
"@vectojs/layout": "^0.
|
|
69
|
-
"@vectojs/math": "^0.1.
|
|
70
|
-
"@vectojs/text": "^0.4.
|
|
67
|
+
"@vectojs/animation": "^0.1.3",
|
|
68
|
+
"@vectojs/layout": "^0.10.0",
|
|
69
|
+
"@vectojs/math": "^0.1.2",
|
|
70
|
+
"@vectojs/text": "^0.4.2"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@guidepup/virtual-screen-reader": "0.32.1",
|
|
74
74
|
"@vitest/coverage-v8": "^4.1.10",
|
|
75
75
|
"esbuild": "^0.28.1",
|
|
76
76
|
"jsdom": "^30.0.1",
|
|
77
|
-
"puppeteer-core": "^25.
|
|
77
|
+
"puppeteer-core": "^25.7.0",
|
|
78
78
|
"tsup": "^8.3.5",
|
|
79
79
|
"vitest": "^4.1.10"
|
|
80
80
|
}
|