@vectojs/core 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +502 -329
- package/dist/index.mjs +340 -167
- package/dist/tree/ComputeParticleEntity.d.ts +5 -1
- package/dist/tree/Scene.d.ts +89 -0
- package/dist/wasm/anim-backend.d.ts +21 -4
- package/dist/wasm/backend.d.ts +9 -4
- package/dist/wasm/particle-backend.d.ts +12 -1
- package/dist/wasm/vectojs_core.wasm +0 -0
- package/package.json +1 -1
|
@@ -143,8 +143,12 @@ export declare class ComputeParticleEntity extends Entity {
|
|
|
143
143
|
* The backend holds one resident SoA store, so a Scene with multiple particle
|
|
144
144
|
* entities reuses it sequentially — origin is therefore re-gathered each call
|
|
145
145
|
* (not upload-once), a couple of extra f32 reads per particle.
|
|
146
|
+
*
|
|
147
|
+
* Returns `false` if the kernel declined the call and {@link updateCPU} ran
|
|
148
|
+
* instead, so the Scene can report which path actually simulated this frame
|
|
149
|
+
* rather than assuming an installed backend did the work.
|
|
146
150
|
*/
|
|
147
|
-
stepWithBackend(backend: ParticleBackend, dt: number, mouseX: number, mouseY: number, width: number, height: number):
|
|
151
|
+
stepWithBackend(backend: ParticleBackend, dt: number, mouseX: number, mouseY: number, width: number, height: number): boolean;
|
|
148
152
|
destroy(): void;
|
|
149
153
|
/**
|
|
150
154
|
* Frees all GPU resources allocated for WebGPU simulation.
|
package/dist/tree/Scene.d.ts
CHANGED
|
@@ -208,6 +208,60 @@ export interface SceneOptions {
|
|
|
208
208
|
}
|
|
209
209
|
/** Frame-rate the loop is capped to when the OS requests reduced motion. */
|
|
210
210
|
export declare const REDUCED_MOTION_FPS = 30;
|
|
211
|
+
/**
|
|
212
|
+
* Why an accelerator did or did not run on the most recent frame.
|
|
213
|
+
*
|
|
214
|
+
* `'active'` is the only value that means the accelerator ran. Everything else
|
|
215
|
+
* is a distinct decline, kept separate because they call for different actions:
|
|
216
|
+
* `'not-installed'` means enable it, `'below-gate'` means the workload is too
|
|
217
|
+
* small to be worth it (working as designed), and `'rejected'` means the kernel
|
|
218
|
+
* refused its arguments — a fault worth reporting, not a tuning outcome.
|
|
219
|
+
*/
|
|
220
|
+
export type AcceleratorReason =
|
|
221
|
+
/** Ran on this frame. */
|
|
222
|
+
'active'
|
|
223
|
+
/** No backend installed; the JS path is the permanent fallback. */
|
|
224
|
+
| 'not-installed'
|
|
225
|
+
/** Installed, but the per-frame gate chose JS (workload below threshold). */
|
|
226
|
+
| 'below-gate'
|
|
227
|
+
/** Installed and gated in, but the kernel rejected the call and wrote nothing. */
|
|
228
|
+
| 'rejected'
|
|
229
|
+
/** Not applicable to this pass (e.g. a non-main renderer, or nothing to do). */
|
|
230
|
+
| 'not-applicable';
|
|
231
|
+
/**
|
|
232
|
+
* One accelerator's per-frame status, read from {@link Scene.accelerators}.
|
|
233
|
+
*
|
|
234
|
+
* The pair exists because `available` and `activeThisFrame` genuinely differ:
|
|
235
|
+
* before this shape, `transformBackend`/`animBackend` reported only that a
|
|
236
|
+
* backend was *installed*, which invites concluding an accelerator is doing work
|
|
237
|
+
* when its gate never opens. Read `activeThisFrame` for what actually happened
|
|
238
|
+
* and `reason` for why.
|
|
239
|
+
*/
|
|
240
|
+
export interface AcceleratorStatus {
|
|
241
|
+
/** A backend is installed and could run, gate permitting. */
|
|
242
|
+
available: boolean;
|
|
243
|
+
/** It ran on the most recent frame. */
|
|
244
|
+
activeThisFrame: boolean;
|
|
245
|
+
/** Why it did or did not run. */
|
|
246
|
+
reason: AcceleratorReason;
|
|
247
|
+
/** Which implementation actually did the work on the most recent frame. */
|
|
248
|
+
path: string;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Per-frame status of every invisible accelerator, read from
|
|
252
|
+
* {@link Scene.accelerators}. Each is independent: a scene can compose
|
|
253
|
+
* transforms in WASM while ticking drivers in JS.
|
|
254
|
+
*/
|
|
255
|
+
export interface AcceleratorReport {
|
|
256
|
+
/** World-matrix composition (`compose_simd`). */
|
|
257
|
+
transform: AcceleratorStatus;
|
|
258
|
+
/** Batched property drivers (`spring_step`/`tween_step`). */
|
|
259
|
+
animation: AcceleratorStatus;
|
|
260
|
+
/** Hit-test broad phase (`hit_build`/`hit_query`) and its gather source. */
|
|
261
|
+
hitTest: AcceleratorStatus;
|
|
262
|
+
/** Particle simulation — WebGPU compute, the WASM CPU kernel, or JS. */
|
|
263
|
+
particle: AcceleratorStatus;
|
|
264
|
+
}
|
|
211
265
|
/**
|
|
212
266
|
* Live render-loop telemetry, read from {@link Scene.frameStats}. See that
|
|
213
267
|
* getter for how each field is measured.
|
|
@@ -574,6 +628,41 @@ export declare class Scene {
|
|
|
574
628
|
private _wasmAabbsFresh;
|
|
575
629
|
/** Did the last hit-grid build use the fused (WASM-store) gather? */
|
|
576
630
|
get hitGatherPath(): 'fused' | 'js';
|
|
631
|
+
/**
|
|
632
|
+
* Why the transform accelerator did or did not run on the most recent frame.
|
|
633
|
+
* Written by the render walk and `_syncWasmStore`.
|
|
634
|
+
*/
|
|
635
|
+
private _transformReason;
|
|
636
|
+
/** Why the batched-driver accelerator did or did not run. */
|
|
637
|
+
private _animReason;
|
|
638
|
+
/**
|
|
639
|
+
* Why the hit-test accelerator did or did not serve the last pointer query.
|
|
640
|
+
* The grid is built lazily on demand, not every frame, so this describes the
|
|
641
|
+
* most recent BUILD. Starts at `'not-installed'` because that is the truth
|
|
642
|
+
* before a backend exists; `_ensureHitGrid` moves it to `'not-applicable'`
|
|
643
|
+
* once one is installed but nothing has queried yet.
|
|
644
|
+
*/
|
|
645
|
+
private _hitReason;
|
|
646
|
+
/** Why the particle accelerator did or did not run. */
|
|
647
|
+
private _particleReason;
|
|
648
|
+
/** Which particle implementation actually simulated the most recent frame. */
|
|
649
|
+
private _particlePath;
|
|
650
|
+
/**
|
|
651
|
+
* Per-frame status of every invisible accelerator: whether each is installed,
|
|
652
|
+
* whether it actually ran on the most recent frame, and why.
|
|
653
|
+
*
|
|
654
|
+
* This exists because the older per-accelerator getters
|
|
655
|
+
* ({@link transformBackend}, {@link animBackend}, {@link hitTestBackend},
|
|
656
|
+
* {@link particleBackend}) report only that a backend is INSTALLED. Reading
|
|
657
|
+
* `'wasm'` from one of those and concluding the accelerator is doing work is
|
|
658
|
+
* wrong whenever a gate never opens, a kernel rejects its arguments, or a
|
|
659
|
+
* faster backend takes the pass instead. Read {@link AcceleratorStatus.reason}
|
|
660
|
+
* for which of those happened.
|
|
661
|
+
*
|
|
662
|
+
* Reflects the most recent main-renderer frame; a secondary renderer (SVG
|
|
663
|
+
* export, offscreen snapshot) does not overwrite it.
|
|
664
|
+
*/
|
|
665
|
+
get accelerators(): AcceleratorReport;
|
|
577
666
|
/** Which backend answers `findEntityAt` for the main tree. */
|
|
578
667
|
get hitTestBackend(): 'js' | 'wasm';
|
|
579
668
|
/** Install (or clear) a WASM hit-test backend directly. Prefer
|
|
@@ -56,10 +56,27 @@ export declare class AnimBackend {
|
|
|
56
56
|
* writing first and sizing after would write into a stale buffer.
|
|
57
57
|
*/
|
|
58
58
|
ensure(springCount: number, tweenCount: number): void;
|
|
59
|
-
/**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Advance `count` springs (from index 0) by `dtMs` milliseconds, in place.
|
|
61
|
+
* Returns `true` when the kernel ran. `false` means it rejected the call
|
|
62
|
+
* (count beyond the capacity {@link ensure} allocated, or no `anim_init` yet)
|
|
63
|
+
* and wrote nothing, so the caller must tick those drivers in JS instead of
|
|
64
|
+
* scattering back a pack the kernel never touched. See {@link lastStatus}.
|
|
65
|
+
*/
|
|
66
|
+
stepSprings(dtMs: number, count: number): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Advance `count` tweens (from index 0) by `dtMs` milliseconds, writing `val`.
|
|
69
|
+
* Returns `true` when the kernel ran; `false` means it rejected the call and
|
|
70
|
+
* wrote nothing (see {@link stepSprings}). `elapsed` is kernel-side state, so
|
|
71
|
+
* a rejected tween pack must not be read back — it is unadvanced, not
|
|
72
|
+
* partially advanced.
|
|
73
|
+
*/
|
|
74
|
+
stepTweens(dtMs: number, count: number): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Status of the most recent kernel call — `WASM_STATUS.OK` unless the kernel
|
|
77
|
+
* declined it. Mirrors {@link TransformBackend.lastStatus}.
|
|
78
|
+
*/
|
|
79
|
+
lastStatus: number;
|
|
63
80
|
private refreshViews;
|
|
64
81
|
}
|
|
65
82
|
/**
|
package/dist/wasm/backend.d.ts
CHANGED
|
@@ -84,8 +84,11 @@ export declare class WasmTransformBackend {
|
|
|
84
84
|
*/
|
|
85
85
|
runKernel(kernel?: Kernel): number;
|
|
86
86
|
/** Upload only the run table + count (topology), leaving per-entity inputs to
|
|
87
|
-
* the resident views. Call when the tree structure changes, not per frame.
|
|
88
|
-
|
|
87
|
+
* the resident views. Call when the tree structure changes, not per frame.
|
|
88
|
+
* Returns `false` if the crate rejected the run count, in which case the
|
|
89
|
+
* PREVIOUS topology is still published and any kernel run against it would
|
|
90
|
+
* compose the wrong tree — the caller must not proceed. */
|
|
91
|
+
uploadRuns(store: TransformStore): boolean;
|
|
89
92
|
/**
|
|
90
93
|
* Status of the most recent kernel or run-table call. `WASM_STATUS.OK` unless
|
|
91
94
|
* the crate rejected its arguments, in which case that call was a no-op.
|
|
@@ -125,8 +128,10 @@ export declare class WasmTransformBackend {
|
|
|
125
128
|
computeAabbs(store: TransformStore): void;
|
|
126
129
|
/** Run the AABB pass only, over `count` entities already resident in wasm
|
|
127
130
|
* memory (bounds written via {@link boundsView}, world matrices already
|
|
128
|
-
* composed). No upload/readback — the per-frame resident path.
|
|
129
|
-
|
|
131
|
+
* composed). No upload/readback — the per-frame resident path. Returns
|
|
132
|
+
* `false` if the kernel rejected `count` (beyond capacity, or uninitialized),
|
|
133
|
+
* in which case {@link aabbView} still holds the previous frame's bounds. */
|
|
134
|
+
runAabbs(count: number): boolean;
|
|
130
135
|
/** Resident wasm local-bounds input views (`bx,by,bw,bh`) for the AABB pass. */
|
|
131
136
|
boundsView(): {
|
|
132
137
|
bx: Float64Array;
|
|
@@ -71,8 +71,19 @@ export declare class ParticleBackend {
|
|
|
71
71
|
* Advance `count` particles one step in place. Returns `true` when at least
|
|
72
72
|
* one live particle is still moving or off-origin beyond epsilon (the fused
|
|
73
73
|
* `hasPendingAnimations` flag), so the caller need not re-scan the buffer.
|
|
74
|
+
*
|
|
75
|
+
* Returns `null` when the kernel REJECTED the call — `count` beyond the
|
|
76
|
+
* capacity {@link ensure} allocated, or no `particle_init` yet. Nothing was
|
|
77
|
+
* written, so the caller must NOT {@link scatter} (that would write the
|
|
78
|
+
* gathered pre-step values back and freeze the simulation) and should fall
|
|
79
|
+
* back to the JS `updateCPU` path for this frame. See {@link lastStatus}.
|
|
74
80
|
*/
|
|
75
|
-
step(count: number, p: ParticleStepParams): boolean;
|
|
81
|
+
step(count: number, p: ParticleStepParams): boolean | null;
|
|
82
|
+
/**
|
|
83
|
+
* Status of the most recent {@link step} — `WASM_STATUS.OK` unless the kernel
|
|
84
|
+
* declined it. Mirrors {@link TransformBackend.lastStatus}.
|
|
85
|
+
*/
|
|
86
|
+
lastStatus: number;
|
|
76
87
|
/** Transpose the AoS stride-8 buffer into the SoA views (position/velocity/
|
|
77
88
|
* life every frame; origin upload-once when `withOrigin`). */
|
|
78
89
|
gather(data: Float32Array, count: number, withOrigin: boolean): void;
|
|
Binary file
|