/** * WASM batched-animation backend: advances every currently-active `SpringDriver`/ * `TweenDriver` in one call each (`spring_step`/`tween_step`), instead of the JS * per-driver `driver.tick()` loop. This is an invisible accelerator — the JS tick * loop ({@link Entity.tickDrivers}) is the permanent fallback, so a caller that * cannot instantiate WASM, or whose active-driver count never crosses the gate * (see `Scene._tickBatchedDrivers`), simply keeps using it. * * The kernel (`crates/vectojs-core-rs/src/anim.rs`) is bit-identical to * `SpringPhysics.update` for springs, and to the JS tweens too since the * explicit-multiplication rewrite: `easing.ts` and the kernel's `ease()` both * express integer powers as explicit multiplication (no `Math.pow`/`powi`, * neither of which is correctly rounded), so the earlier ~1e-12 ULP gap is * closed. Batched state still needs re-seeding per frame — `elapsed` is * kernel-side state, so every gather re-writes it from the driver rather than * letting the kernel's copy drift. * * Unlike the transform/hit-test stores, this backend holds no cross-frame * residency: every qualifying frame re-gathers ALL currently-active batchable * drivers into a fresh dense pack (see {@link ensure} + the spring/tween input * views), runs the kernel once, and scatters results straight back out. This * keeps the design robust to drivers joining/leaving between frames and to the * gate itself flipping the JS/WASM path frame-to-frame — there is no persistent * wasm-side state to invalidate. */ export interface SpringView { val: Float64Array; target: Float64Array; vel: Float64Array; stiff: Float64Array; damp: Float64Array; mass: Float64Array; } export interface TweenView { from: Float64Array; to: Float64Array; elapsed: Float64Array; dur: Float64Array; delay: Float64Array; ease: Float64Array; val: Float64Array; } export declare class AnimBackend { private readonly ex; private springCap; private tweenCap; private sv; private tv; constructor(instance: WebAssembly.Instance); /** The resident spring SoA input/output views, valid until the next capacity * growth. Write gathered driver state here before calling {@link stepSprings}. */ springView(): SpringView; /** The resident tween SoA input/output views, valid until the next capacity * growth. Write gathered driver state here before calling {@link stepTweens}. */ tweenView(): TweenView; /** * Size (and grow, if needed) capacity for `springCount` springs and * `tweenCount` tweens. Call this BEFORE writing into {@link springView}/ * {@link tweenView} — a capacity growth detaches the previous views, so * writing first and sizing after would write into a stale buffer. */ ensure(springCount: number, tweenCount: number): void; /** * Re-create the typed-array views if another backend's allocation grew the * shared linear memory and detached them (see {@link viewsStale}). Call after * {@link ensure} and before writing into {@link springView}/{@link tweenView}. */ revalidateViews(): void; /** * Advance `count` springs (from index 0) by `dtMs` milliseconds, in place. * Returns `true` when the kernel ran. `false` means it rejected the call * (count beyond the capacity {@link ensure} allocated, or no `anim_init` yet) * and wrote nothing, so the caller must tick those drivers in JS instead of * scattering back a pack the kernel never touched. See {@link lastStatus}. */ stepSprings(dtMs: number, count: number): boolean; /** * Advance `count` tweens (from index 0) by `dtMs` milliseconds, writing `val`. * Returns `true` when the kernel ran; `false` means it rejected the call and * wrote nothing (see {@link stepSprings}). `elapsed` is kernel-side state, so * a rejected tween pack must not be read back — it is unadvanced, not * partially advanced. */ stepTweens(dtMs: number, count: number): boolean; /** * Status of the most recent kernel call — `WASM_STATUS.OK` unless the kernel * declined it. Mirrors {@link TransformBackend.lastStatus}. */ lastStatus: number; private refreshViews; } /** * Instantiate synchronously (Node/tests, or a worker). Rejected on the browser * main thread for modules >4 KB — use {@link instantiateAsync} there. Returns * `null` if compilation/instantiation throws, so callers fall back to JS. */ export declare function instantiateSync(bytes: BufferSource): AnimBackend | null; /** * Instantiate asynchronously (browser main thread). Returns `null` on any * failure — CSP `wasm-unsafe-eval`, unsupported, corrupt/missing bytes — so the * caller keeps using the JS path. */ export declare function instantiateAsync(bytes: BufferSource): Promise; /** Anything the anim core can be loaded from, matching the transform/hit-test * cores' loading ergonomics. */ export type AnimModuleSource = BufferSource | string | URL | Response | Promise; /** * Instantiate from a URL/Response using streaming compilation when the * platform supports it, falling back to fetch → arrayBuffer → instantiate when * unavailable or the response's MIME type is rejected. Returns `null` on any * failure so the caller keeps the JS path. */ export declare function instantiateStreaming(source: string | URL | Response | Promise): Promise;