@cyberart-io/engine 0.0.6 → 0.0.8
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/README.md +59 -11
- package/dist/headless.d.ts +326 -64
- package/dist/headless.js +1 -1
- package/dist/index.d.ts +294 -70
- package/dist/index.js +1 -1
- package/docs/calculation-carts.md +134 -0
- package/docs/capability-manifest.md +5 -2
- package/docs/compositor.md +8 -3
- package/docs/frame-benchmark.md +107 -0
- package/docs/headless-harness.md +5 -1
- package/docs/runtime-group.md +3 -3
- package/docs/visual-layers.md +151 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@cyberart-io/engine`
|
|
2
2
|
|
|
3
|
-
An engine for building animated, interactive, generative programs for the web. You write a **cart** — a small object with `getDefaultState` (initial state), `update` (advance that state each tick), and `render` (draw it).
|
|
3
|
+
An engine for building animated, interactive, generative programs for the web. You write a **cart** — a small object with `getDefaultState` (initial state), `update` (advance that state each tick), and optional `render` (draw it). A render cart is a state machine in a loop that paints to the screen. A calculation cart runs the same state machine without a canvas, and talks to a sibling that does paint. The engine mounts it into a DOM element you own, runs the loop, and gives you pause, snapshot, events, and save/load.
|
|
4
4
|
|
|
5
5
|
## License
|
|
6
6
|
|
|
@@ -90,6 +90,7 @@ Full API for the event router, deterministic replay, and CI harness (so agents c
|
|
|
90
90
|
- [Events and router](docs/events.md) — mailbox, envelope, typed contracts, `createEventRouter`, hops, idempotency, rejections
|
|
91
91
|
- [Deterministic mode](docs/deterministic-mode.md) — `step` / `schedule`, clocks, `ScriptedAction`, replay diffs
|
|
92
92
|
- [Headless harness](docs/headless-harness.md) — `createHeadlessHarness` from `@cyberart-io/engine/headless`, software Canvas2D, `compareImageData` / `assertPixelsEqual`, inspect / screenshot
|
|
93
|
+
- [Frame benchmarking](docs/frame-benchmark.md) — `benchmarkCartFrames` (headless) and optional `onFrameTiming` (live); zero cost when unset
|
|
93
94
|
- [Presentation adapter](docs/presentation-adapter.md) — host-owned render model, intents, loading / error / unsupported
|
|
94
95
|
- [Asset resolver](docs/asset-resolver.md) — host-pluggable images/audio/fonts/spritesheets, cache, preload, fallbacks
|
|
95
96
|
- [Presentation cue](docs/presentation-cue.md) — deterministic `createPresentationTimeline`, duplicate policy, reduced-motion, lifecycle events
|
|
@@ -97,7 +98,9 @@ Full API for the event router, deterministic replay, and CI harness (so agents c
|
|
|
97
98
|
- [Executable modules](docs/executable-modules.md) — trusted versioned factories, host allowlists, isolation, per-module failures
|
|
98
99
|
- [Normalized geometry](docs/normalized-geometry.md) — coordinate spaces, contain/cover/crop layout, landmarks, hit regions, debug overlay
|
|
99
100
|
- [Runtime group](docs/runtime-group.md) — `createRuntimeGroup`, shared router attach, lockstep clock; `createHeadlessMultiCartHarness` from `@cyberart-io/engine/headless`
|
|
101
|
+
- [Calculation carts](docs/calculation-carts.md) — `kind: 'calculation'`, update + events without paint; sibling render carts still paint
|
|
100
102
|
- [Compositor](docs/compositor.md) — `createCompositor`, transparent stacking, `screen` blend, `writeComposedFrame`
|
|
103
|
+
- [Visual layers](docs/visual-layers.md) — `createVisualLayerController`, versioned overlay `v1`/`v2`, deterministic swaps, `hostState` JSON
|
|
101
104
|
- [Browser harness](docs/browser-harness.md) — `createBrowserHarness`, DOM clicks, viewport/DPR, composed screenshots
|
|
102
105
|
- [Replay inspector](docs/replay-inspector.md) — `createReplayInspector`, causation trees, redacted export/import, headless replay
|
|
103
106
|
- [MIDI](docs/midi.md) — host-owned `MidiManager`, note/CC/pitch in and out, `inject` / fake port, structured `requestAccess`
|
|
@@ -112,18 +115,20 @@ A cart is an `AnimationCart`. Required:
|
|
|
112
115
|
|---|---|
|
|
113
116
|
| `getDefaultState` | Build the initial `state`. Use `R` (`Random`) for anything that should follow the seed. |
|
|
114
117
|
| `update` | Advance `state` each tick. Return the next state. |
|
|
115
|
-
| `render` | Draw into the 2D context (and optional `ImageData`). |
|
|
116
118
|
| `metadata.id` / `name` / `frameRate` | Identity and loop rate. |
|
|
117
119
|
|
|
120
|
+
`render` draws into the 2D context (and optional `ImageData`). Omit it on calculation carts (`createRuntime({ kind: 'calculation' })` or a group participant with `kind: 'calculation'`). The runtime does not call `render` and does not create a canvas for that kind. Render carts (the default) still paint as before.
|
|
121
|
+
|
|
118
122
|
Useful optionals:
|
|
119
123
|
|
|
120
124
|
| Piece | Role |
|
|
121
125
|
|---|---|
|
|
126
|
+
| `render` | Draw into the 2D context. Omit on calculation carts; the runtime will not call a no-op either. |
|
|
122
127
|
| `teardown` | Dispose long-lived resources (Tone nodes, listeners) when the cart unloads. |
|
|
123
128
|
| `metadata.audio` | `'tone'` if the piece needs Web Audio. Omit for a silent cart. |
|
|
124
129
|
| `metadata.generative` | `true` when output is a function of the token hash. Saves then only load on the same seed. |
|
|
125
130
|
|
|
126
|
-
Callbacks also receive `DimensionContext` (`width` / `height` and derived size fields), `KeyboardManager`, `PointerManager`, and an optional `HostChannel`. You do not have to use them. Types live on the package: `AnimationCart`, `Random`, `DimensionContext`, `KeyboardManager`, `PointerManager`, `HostChannel`.
|
|
131
|
+
Callbacks also receive `DimensionContext` (`width` / `height` and derived size fields), `KeyboardManager`, `PointerManager`, and an optional `HostChannel`. You do not have to use them. Types live on the package: `AnimationCart`, `CartKind`, `Random`, `DimensionContext`, `KeyboardManager`, `PointerManager`, `HostChannel`.
|
|
127
132
|
|
|
128
133
|
`Random` is seed-stable: `R.dec(min, max)`, `R.int(min, max)`, `R.bool()`, `R.choose(list)`.
|
|
129
134
|
|
|
@@ -159,6 +164,7 @@ const cart = runtime.mount(artProject, {
|
|
|
159
164
|
| `assets` | off | Host `AssetResolver` plus engine cache/preload. Carts keep logical refs. Leave unset when the piece has no media. |
|
|
160
165
|
| `audioBroker` | off | Shared `createAudioBroker` instance. Optional. Omit when the cart only uses `metadata.audio: 'tone'`. |
|
|
161
166
|
| `audioParticipantId` | none | Group participant id to authorize / teardown on this runtime. |
|
|
167
|
+
| `kind` | `'render'` | `'calculation'` skips canvas construction and paint. `getDefaultState`, `update`, and host-channel events still run. |
|
|
162
168
|
|
|
163
169
|
`CartHandle` (what `mount` returns):
|
|
164
170
|
|
|
@@ -182,9 +188,9 @@ const cart = runtime.mount(artProject, {
|
|
|
182
188
|
| `tokenData` | Live hash and token id. |
|
|
183
189
|
| `getCartState()` | Live object for debug UI. Not JSON-safe — use export/import for saves. |
|
|
184
190
|
|
|
185
|
-
`runtime.destroy()` tears down the runtime. `runtime.unlockAudio()` is for an early click before `mount`. `runtime.onError` receives frame errors (`phase`, `consecutive`, `stopped`).
|
|
191
|
+
`runtime.destroy()` tears down the runtime. `runtime.unlockAudio()` is for an early click before `mount`. `runtime.onError` receives frame errors (`phase`, `consecutive`, `stopped`). `runtime.kind` is `'render'` (default) or `'calculation'`.
|
|
186
192
|
|
|
187
|
-
One cart per runtime. A second `mount` unloads the first. Several pieces on a page means several `createRuntime()` calls, or one `createRuntimeGroup()` that attaches each mailbox to a shared router and locksteps a deterministic clock.
|
|
193
|
+
One cart per runtime. A second `mount` unloads the first. Several pieces on a page means several `createRuntime()` calls, or one `createRuntimeGroup()` that attaches each mailbox to a shared router and locksteps a deterministic clock. Calculation participants (`kind: 'calculation'`) share that group without a canvas; see [calculation carts](docs/calculation-carts.md).
|
|
188
194
|
|
|
189
195
|
## Audio
|
|
190
196
|
|
|
@@ -267,6 +273,8 @@ CI and agents should drive the **same** `createRuntime({ deterministic })` path.
|
|
|
267
273
|
|
|
268
274
|
Full options, `click` clock rule, Node-only `captureFrame`, remount, visual asserts, and the reproduce command: [headless harness](docs/headless-harness.md).
|
|
269
275
|
|
|
276
|
+
Hash / trait cost A/B without a browser: `benchmarkCartFrames` / `formatFrameBenchmarkResult` from the same headless entry. Live overlays: `runtime.onFrameTiming`. Details and the zero-overhead-when-off contract: [frame benchmarking](docs/frame-benchmark.md).
|
|
277
|
+
|
|
270
278
|
```ts
|
|
271
279
|
import { createHeadlessHarness } from '@cyberart-io/engine/headless';
|
|
272
280
|
|
|
@@ -418,17 +426,57 @@ import { createRuntimeGroup } from '@cyberart-io/engine';
|
|
|
418
426
|
const group = createRuntimeGroup({
|
|
419
427
|
origin: 0,
|
|
420
428
|
participants: [
|
|
421
|
-
{ id: '
|
|
422
|
-
{ id: '
|
|
429
|
+
{ id: 'world', cart: worldCart, kind: 'calculation', emit: ['host.intent.*'], subscribe: ['host.state.*'] },
|
|
430
|
+
{ id: 'overlay', cart: overlayCart, subscribe: ['host.intent.*'] },
|
|
423
431
|
],
|
|
424
432
|
});
|
|
425
|
-
group.publish({ type: 'host.state.
|
|
433
|
+
group.publish({ type: 'host.state.scene-changed', kind: 'state', payload: { sceneId: 'alpha' } });
|
|
426
434
|
await group.step(2);
|
|
427
435
|
const { trace } = await group.inspect();
|
|
428
436
|
group.destroy();
|
|
429
437
|
```
|
|
430
438
|
|
|
431
|
-
Headless / CI: `createHeadlessMultiCartHarness` from `@cyberart-io/engine/headless` is the same handle after `installHeadlessCanvas()`. Full options: [runtime group](docs/runtime-group.md). Causation trees, redaction, and tape replay: [replay inspector](docs/replay-inspector.md).
|
|
439
|
+
Headless / CI: `createHeadlessMultiCartHarness` from `@cyberart-io/engine/headless` is the same handle after `installHeadlessCanvas()`. Full options: [runtime group](docs/runtime-group.md). Calculation carts (no canvas / paint): [calculation carts](docs/calculation-carts.md). Causation trees, redaction, and tape replay: [replay inspector](docs/replay-inspector.md).
|
|
440
|
+
|
|
441
|
+
## Visual layers
|
|
442
|
+
|
|
443
|
+
Durable overlay / mask / sprite versions (`v1`, `v2`) with deterministic show, hide, replace, and crossfade. An accepted `host.state.accepted` (`sceneId: 'alpha'`) runs a presentation cue; the compositor reveals a **preloaded** alternate source in one `setLayer`. Failed assets keep the prior valid frame and emit `visual.layer.failed`. Persist `controller.snapshot()` in envelope `hostState` — do not put pixels in the envelope.
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
import {
|
|
447
|
+
ASSET_READY_EVENT,
|
|
448
|
+
HOST_STATE_ACCEPTED_EVENT,
|
|
449
|
+
createVisualLayerController,
|
|
450
|
+
} from '@cyberart-io/engine';
|
|
451
|
+
|
|
452
|
+
const layers = createVisualLayerController({
|
|
453
|
+
compositor,
|
|
454
|
+
sceneId: 'alpha',
|
|
455
|
+
layers: [
|
|
456
|
+
{
|
|
457
|
+
id: 'overlay',
|
|
458
|
+
kind: 'layer',
|
|
459
|
+
initialVersion: 'v1',
|
|
460
|
+
versions: [
|
|
461
|
+
{ id: 'v1', assetId: 'overlay.v1' },
|
|
462
|
+
{ id: 'v2', assetId: 'overlay.v2' },
|
|
463
|
+
],
|
|
464
|
+
},
|
|
465
|
+
],
|
|
466
|
+
onAccepted: [{ layerId: 'overlay', toVersion: 'v2', kind: 'replace', durationFrames: 2 }],
|
|
467
|
+
});
|
|
468
|
+
layers.registerSource('overlay.v1', imageV1);
|
|
469
|
+
layers.registerSource('overlay.v2', imageV2);
|
|
470
|
+
layers.handleHostEvent({ type: ASSET_READY_EVENT, kind: 'state', payload: { id: 'overlay.v2' } });
|
|
471
|
+
layers.handleHostEvent({
|
|
472
|
+
type: HOST_STATE_ACCEPTED_EVENT,
|
|
473
|
+
kind: 'state',
|
|
474
|
+
payload: { sceneId: 'alpha' },
|
|
475
|
+
});
|
|
476
|
+
layers.step(2);
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Headless capture: `captureVisualLayers(layers)` from `@cyberart-io/engine` or `@cyberart-io/engine/headless`. Full API: [visual layers](docs/visual-layers.md).
|
|
432
480
|
|
|
433
481
|
## Normalized geometry
|
|
434
482
|
|
|
@@ -594,7 +642,7 @@ The engine prefers, in order:
|
|
|
594
642
|
2. The container’s first `<canvas>`
|
|
595
643
|
3. A canvas it creates (no `id="canvas"`)
|
|
596
644
|
|
|
597
|
-
A canvas the host adopted is left in place on destroy; a canvas the engine created is removed. Both `cart.destroy()` and `runtime.destroy()` are idempotent.
|
|
645
|
+
A canvas the host adopted is left in place on destroy; a canvas the engine created is removed. Both `cart.destroy()` and `runtime.destroy()` are idempotent. `createRuntime({ kind: 'calculation' })` never creates or adopts a canvas (`cart.canvas` is `undefined`).
|
|
598
646
|
|
|
599
647
|
## Limits
|
|
600
648
|
|
|
@@ -605,7 +653,7 @@ A canvas the host adopted is left in place on destroy; a canvas the engine creat
|
|
|
605
653
|
|
|
606
654
|
## Publishing this package (maintainers)
|
|
607
655
|
|
|
608
|
-
Not part of writing a cart. Engine source lives in `packages/engine/src/` (not mixed into the site). The npm tarball is built from `packages/engine/src/index.ts` and `packages/engine/src/headless.ts` and contains minified `dist/index.js` + `dist/headless.js`, rolled-up `.d.ts` for both, `LICENSE`, `README.md`, `docs/` (including compositor, browser harness, replay inspector, MIDI, executable modules, snapshots, and
|
|
656
|
+
Not part of writing a cart. Engine source lives in `packages/engine/src/` (not mixed into the site). The npm tarball is built from `packages/engine/src/index.ts` and `packages/engine/src/headless.ts` and contains minified `dist/index.js` + `dist/headless.js`, rolled-up `.d.ts` for both, `LICENSE`, `README.md`, `docs/` (including compositor, visual layers, browser harness, replay inspector, MIDI, executable modules, snapshots, audio, and calculation carts), and `package.json`. Site code that still imports `src/ui/lib/...` hits thin re-export shims so those paths keep working.
|
|
609
657
|
|
|
610
658
|
```bash
|
|
611
659
|
pnpm run pack:engine
|
package/dist/headless.d.ts
CHANGED
|
@@ -254,11 +254,16 @@ type AnimationTiming = {
|
|
|
254
254
|
deltaSinceLastUpdate: number;
|
|
255
255
|
deltaSinceLastRender: number;
|
|
256
256
|
};
|
|
257
|
+
type CartKind = 'render' | 'calculation';
|
|
257
258
|
type AnimationCart<T = unknown, TFeatureState = undefined> = {
|
|
258
259
|
getDefaultFeatureState?: (R: Random, dimensionContext: DimensionContext, rawParams: number[], keyboardManager: KeyboardManager, customState?: Partial<T>, pointerManager?: PointerManager, gameManager?: unknown, hostChannel?: HostChannel) => TFeatureState;
|
|
259
260
|
getDefaultState: (R: Random, dimensionContext: DimensionContext, rawParams: number[], keyboardManager: KeyboardManager, customState?: Partial<T>, pointerManager?: PointerManager, gameManager?: unknown, featureState?: Readonly<TFeatureState>, hostChannel?: HostChannel) => T;
|
|
260
261
|
update: (R: Random, framesElapsed: number, rawParams: number[], dimensionContext: DimensionContext, state: T, keyboardManager: KeyboardManager, pointerManager?: PointerManager, gameManager?: unknown, timing?: AnimationTiming, featureState?: Readonly<TFeatureState>, hostChannel?: HostChannel) => T;
|
|
261
|
-
|
|
262
|
+
/**
|
|
263
|
+
* Draw into the 2D context. Optional on calculation carts (`kind:
|
|
264
|
+
* 'calculation'`); the runtime does not call it and does not create a canvas.
|
|
265
|
+
*/
|
|
266
|
+
render?: (R: Random, framesElapsed: number, rawParams: number[], dimensionContext: DimensionContext, state: T, drawingContext: CanvasRenderingContext2D, imageData: ImageData, pointerManager?: PointerManager, gameManager?: unknown, timing?: AnimationTiming, featureState?: Readonly<TFeatureState>, hostChannel?: HostChannel) => void;
|
|
262
267
|
adjust?: Record<string, {
|
|
263
268
|
type: 'switch';
|
|
264
269
|
immediate?: boolean;
|
|
@@ -328,6 +333,73 @@ type CartStateBundle = {
|
|
|
328
333
|
state: unknown;
|
|
329
334
|
};
|
|
330
335
|
|
|
336
|
+
/**
|
|
337
|
+
* Copyright (c) 2026 Aaron Boyarsky
|
|
338
|
+
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
339
|
+
* See packages/engine/LICENSE
|
|
340
|
+
*
|
|
341
|
+
* Host-controlled time, input, and asset completion for deterministic replays.
|
|
342
|
+
* Production kaleidoscope / Art Blocks playback does not enable this mode.
|
|
343
|
+
* Logical asset URLs are resolved by the host preloader (`assetResolver.ts`);
|
|
344
|
+
* this module only times `ASSET_READY_EVENT` / `ASSET_FAILED_EVENT` delivery.
|
|
345
|
+
*/
|
|
346
|
+
|
|
347
|
+
type PointerKind = 'down' | 'move' | 'up';
|
|
348
|
+
type ScriptedAction = {
|
|
349
|
+
atFrame: number;
|
|
350
|
+
} & ({
|
|
351
|
+
type: 'pointer';
|
|
352
|
+
pointer: {
|
|
353
|
+
kind: PointerKind;
|
|
354
|
+
x: number;
|
|
355
|
+
y: number;
|
|
356
|
+
};
|
|
357
|
+
} | {
|
|
358
|
+
type: 'key';
|
|
359
|
+
key: string;
|
|
360
|
+
} | {
|
|
361
|
+
type: 'event';
|
|
362
|
+
event: HostEvent;
|
|
363
|
+
} | {
|
|
364
|
+
type: 'asset';
|
|
365
|
+
id: string;
|
|
366
|
+
status: 'ready' | 'failed';
|
|
367
|
+
/** Optional structured failure or resolved resource. Envelope is unchanged. */
|
|
368
|
+
detail?: unknown;
|
|
369
|
+
});
|
|
370
|
+
type DeterministicRuntimeOptions = {
|
|
371
|
+
/** Virtual clock origin in ms. Default 0. */
|
|
372
|
+
origin?: number;
|
|
373
|
+
/** Actions applied at the start of `atFrame`, before `update`. */
|
|
374
|
+
actions?: ScriptedAction[];
|
|
375
|
+
};
|
|
376
|
+
type ClockSnapshot = {
|
|
377
|
+
now: number;
|
|
378
|
+
framesElapsed: number;
|
|
379
|
+
frameRate: number;
|
|
380
|
+
};
|
|
381
|
+
type ReplayMetadata = {
|
|
382
|
+
seed: string;
|
|
383
|
+
clock: ClockSnapshot;
|
|
384
|
+
rng: RandomState;
|
|
385
|
+
actions: ScriptedAction[];
|
|
386
|
+
applied: AppliedAction[];
|
|
387
|
+
events: HostEvent[];
|
|
388
|
+
state: unknown;
|
|
389
|
+
};
|
|
390
|
+
type AppliedAction = {
|
|
391
|
+
frame: number;
|
|
392
|
+
action: ScriptedAction;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
type FrameTimingSample = {
|
|
396
|
+
frame: number;
|
|
397
|
+
updateMs: number;
|
|
398
|
+
renderMs: number;
|
|
399
|
+
drawMs: number;
|
|
400
|
+
totalMs: number;
|
|
401
|
+
};
|
|
402
|
+
|
|
331
403
|
/**
|
|
332
404
|
* Copyright (c) 2026 Aaron Boyarsky
|
|
333
405
|
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
@@ -398,65 +470,6 @@ type ExportSnapshotOptions = {
|
|
|
398
470
|
runtimeVersion?: string;
|
|
399
471
|
};
|
|
400
472
|
|
|
401
|
-
/**
|
|
402
|
-
* Copyright (c) 2026 Aaron Boyarsky
|
|
403
|
-
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
404
|
-
* See packages/engine/LICENSE
|
|
405
|
-
*
|
|
406
|
-
* Host-controlled time, input, and asset completion for deterministic replays.
|
|
407
|
-
* Production kaleidoscope / Art Blocks playback does not enable this mode.
|
|
408
|
-
* Logical asset URLs are resolved by the host preloader (`assetResolver.ts`);
|
|
409
|
-
* this module only times `ASSET_READY_EVENT` / `ASSET_FAILED_EVENT` delivery.
|
|
410
|
-
*/
|
|
411
|
-
|
|
412
|
-
type PointerKind = 'down' | 'move' | 'up';
|
|
413
|
-
type ScriptedAction = {
|
|
414
|
-
atFrame: number;
|
|
415
|
-
} & ({
|
|
416
|
-
type: 'pointer';
|
|
417
|
-
pointer: {
|
|
418
|
-
kind: PointerKind;
|
|
419
|
-
x: number;
|
|
420
|
-
y: number;
|
|
421
|
-
};
|
|
422
|
-
} | {
|
|
423
|
-
type: 'key';
|
|
424
|
-
key: string;
|
|
425
|
-
} | {
|
|
426
|
-
type: 'event';
|
|
427
|
-
event: HostEvent;
|
|
428
|
-
} | {
|
|
429
|
-
type: 'asset';
|
|
430
|
-
id: string;
|
|
431
|
-
status: 'ready' | 'failed';
|
|
432
|
-
/** Optional structured failure or resolved resource. Envelope is unchanged. */
|
|
433
|
-
detail?: unknown;
|
|
434
|
-
});
|
|
435
|
-
type DeterministicRuntimeOptions = {
|
|
436
|
-
/** Virtual clock origin in ms. Default 0. */
|
|
437
|
-
origin?: number;
|
|
438
|
-
/** Actions applied at the start of `atFrame`, before `update`. */
|
|
439
|
-
actions?: ScriptedAction[];
|
|
440
|
-
};
|
|
441
|
-
type ClockSnapshot = {
|
|
442
|
-
now: number;
|
|
443
|
-
framesElapsed: number;
|
|
444
|
-
frameRate: number;
|
|
445
|
-
};
|
|
446
|
-
type ReplayMetadata = {
|
|
447
|
-
seed: string;
|
|
448
|
-
clock: ClockSnapshot;
|
|
449
|
-
rng: RandomState;
|
|
450
|
-
actions: ScriptedAction[];
|
|
451
|
-
applied: AppliedAction[];
|
|
452
|
-
events: HostEvent[];
|
|
453
|
-
state: unknown;
|
|
454
|
-
};
|
|
455
|
-
type AppliedAction = {
|
|
456
|
-
frame: number;
|
|
457
|
-
action: ScriptedAction;
|
|
458
|
-
};
|
|
459
|
-
|
|
460
473
|
declare const ASSET_KINDS: readonly ["image", "audio", "font", "spritesheet"];
|
|
461
474
|
type AssetKind = (typeof ASSET_KINDS)[number];
|
|
462
475
|
declare const ASSET_FAILURE_CODES: readonly ["timeout", "cors", "not-found", "invalid", "aborted", "resolver"];
|
|
@@ -625,6 +638,7 @@ type FrameErrorInfo = {
|
|
|
625
638
|
consecutive: number;
|
|
626
639
|
stopped: boolean;
|
|
627
640
|
};
|
|
641
|
+
|
|
628
642
|
type CreateRuntimeOptions = {
|
|
629
643
|
/** Required mount point. The runtime creates or adopts a canvas inside this element. */
|
|
630
644
|
container: HTMLElement;
|
|
@@ -669,6 +683,16 @@ type CreateRuntimeOptions = {
|
|
|
669
683
|
* this id does not close Tone for remaining carts.
|
|
670
684
|
*/
|
|
671
685
|
audioParticipantId?: string;
|
|
686
|
+
/**
|
|
687
|
+
* `'calculation'` skips canvas construction and paint. `getDefaultState`,
|
|
688
|
+
* `update`, and host-channel events still run. Default `'render'`.
|
|
689
|
+
*/
|
|
690
|
+
kind?: CartKind;
|
|
691
|
+
/**
|
|
692
|
+
* Optional per-frame update/render/draw timings. Can also be assigned later
|
|
693
|
+
* via `runtime.onFrameTiming`. Unset = no `performance.now` in the draw loop.
|
|
694
|
+
*/
|
|
695
|
+
onFrameTiming?: (sample: FrameTimingSample) => void;
|
|
672
696
|
};
|
|
673
697
|
type MountOptions<T = unknown> = {
|
|
674
698
|
/** Boot overrides passed as `customState` into `getDefaultState`. Not a live-state replay. */
|
|
@@ -747,7 +771,14 @@ type CyberArtRuntime = {
|
|
|
747
771
|
readonly assets: AssetPreloader | undefined;
|
|
748
772
|
/** Shared broker when `createRuntime({ audioBroker })` was set. */
|
|
749
773
|
readonly audioBroker: AudioBroker | undefined;
|
|
774
|
+
/** `'render'` (default) or `'calculation'` (no canvas / paint). */
|
|
775
|
+
readonly kind: CartKind;
|
|
750
776
|
onError?: (error: unknown, info: FrameErrorInfo) => void;
|
|
777
|
+
/**
|
|
778
|
+
* Optional per-frame update/render/draw timings. Unset = zero overhead in the
|
|
779
|
+
* draw loop (single null check). Same pattern as `onError`.
|
|
780
|
+
*/
|
|
781
|
+
onFrameTiming?: (sample: FrameTimingSample) => void;
|
|
751
782
|
};
|
|
752
783
|
|
|
753
784
|
/**
|
|
@@ -838,7 +869,7 @@ type EventRouter = {
|
|
|
838
869
|
* locksteps a deterministic clock. Carts never receive the router object.
|
|
839
870
|
*/
|
|
840
871
|
|
|
841
|
-
type RuntimeGroupKind =
|
|
872
|
+
type RuntimeGroupKind = CartKind;
|
|
842
873
|
/**
|
|
843
874
|
* Optional capability-shaped attach hints. Explicit participant `emit` /
|
|
844
875
|
* `subscribe` / `authoritative` win. Do not import the capability manifest
|
|
@@ -856,7 +887,7 @@ type RuntimeGroupFrameError = {
|
|
|
856
887
|
type RuntimeGroupParticipantConfig<T = unknown> = {
|
|
857
888
|
id: string;
|
|
858
889
|
cart: AnimationCart<T>;
|
|
859
|
-
/** Rendered surface vs calculation cart (
|
|
890
|
+
/** Rendered surface vs calculation cart (update + events, no canvas / paint). */
|
|
860
891
|
kind?: RuntimeGroupKind;
|
|
861
892
|
seed?: CreateRuntimeOptions['seed'];
|
|
862
893
|
container?: HTMLElement;
|
|
@@ -944,6 +975,20 @@ type CompositorBlendMode = (typeof COMPOSITOR_BLEND_MODES)[number];
|
|
|
944
975
|
declare const COMPOSITOR_CLEAR_POLICIES: readonly ["transparent", "opaque"];
|
|
945
976
|
type CompositorClearPolicy = (typeof COMPOSITOR_CLEAR_POLICIES)[number];
|
|
946
977
|
type CompositorPointerEvents = 'auto' | 'none';
|
|
978
|
+
declare const COMPOSITOR_SOURCE_KINDS: readonly ["participant", "image", "canvas"];
|
|
979
|
+
type CompositorSourceKind = (typeof COMPOSITOR_SOURCE_KINDS)[number];
|
|
980
|
+
type CompositorParticipantSource = {
|
|
981
|
+
kind: 'participant';
|
|
982
|
+
};
|
|
983
|
+
type CompositorImageSource = {
|
|
984
|
+
kind: 'image';
|
|
985
|
+
image: ImageData;
|
|
986
|
+
};
|
|
987
|
+
type CompositorCanvasSource = {
|
|
988
|
+
kind: 'canvas';
|
|
989
|
+
canvas: HTMLCanvasElement;
|
|
990
|
+
};
|
|
991
|
+
type CompositorLayerSource = CompositorParticipantSource | CompositorImageSource | CompositorCanvasSource;
|
|
947
992
|
type CompositorClip = {
|
|
948
993
|
x: number;
|
|
949
994
|
y: number;
|
|
@@ -959,6 +1004,11 @@ type CompositorLayerConfig = {
|
|
|
959
1004
|
clip?: CompositorClip;
|
|
960
1005
|
pointerEvents?: CompositorPointerEvents;
|
|
961
1006
|
clearPolicy?: CompositorClearPolicy;
|
|
1007
|
+
/**
|
|
1008
|
+
* Pixel source. Default `participant` reads the runtime-group canvas.
|
|
1009
|
+
* `image` / `canvas` swap atomically via `setLayer` / `addLayer`.
|
|
1010
|
+
*/
|
|
1011
|
+
source?: CompositorLayerSource;
|
|
962
1012
|
};
|
|
963
1013
|
type CompositorLayerInspect = {
|
|
964
1014
|
id: string;
|
|
@@ -969,6 +1019,7 @@ type CompositorLayerInspect = {
|
|
|
969
1019
|
clip: CompositorClip | null;
|
|
970
1020
|
pointerEvents: CompositorPointerEvents;
|
|
971
1021
|
clearPolicy: CompositorClearPolicy;
|
|
1022
|
+
sourceKind: CompositorSourceKind;
|
|
972
1023
|
};
|
|
973
1024
|
type ComposedFrame = {
|
|
974
1025
|
imageData: ImageData;
|
|
@@ -1001,6 +1052,7 @@ type Compositor = {
|
|
|
1001
1052
|
*/
|
|
1002
1053
|
resize(width: number, height: number, dpr?: number): void;
|
|
1003
1054
|
setLayer(id: string, patch: Partial<Omit<CompositorLayerConfig, 'id'>>): void;
|
|
1055
|
+
addLayer(config: CompositorLayerConfig): void;
|
|
1004
1056
|
layer(id: string): CompositorLayerInspect;
|
|
1005
1057
|
layers(): CompositorLayerInspect[];
|
|
1006
1058
|
pointerTarget(x: number, y: number): string | undefined;
|
|
@@ -1411,6 +1463,14 @@ type CueView = {
|
|
|
1411
1463
|
progress: number;
|
|
1412
1464
|
repeatIndex: number;
|
|
1413
1465
|
};
|
|
1466
|
+
type PlayCueResult = {
|
|
1467
|
+
ok: true;
|
|
1468
|
+
cue: CueView;
|
|
1469
|
+
} | {
|
|
1470
|
+
ok: false;
|
|
1471
|
+
reason: 'duplicate' | 'invalid';
|
|
1472
|
+
detail: string;
|
|
1473
|
+
};
|
|
1414
1474
|
|
|
1415
1475
|
/**
|
|
1416
1476
|
* Copyright (c) 2026 Aaron Boyarsky
|
|
@@ -1494,6 +1554,207 @@ declare function createHeadlessAudioAdapter(options?: {
|
|
|
1494
1554
|
originFrame?: number;
|
|
1495
1555
|
}): HeadlessAudioAdapter;
|
|
1496
1556
|
|
|
1557
|
+
declare const VISUAL_LAYER_SNAPSHOT_SCHEMA_VERSION: 1;
|
|
1558
|
+
declare const VISUAL_LAYER_KINDS: readonly ["layer", "mask", "sprite"];
|
|
1559
|
+
type VisualLayerKind = (typeof VISUAL_LAYER_KINDS)[number];
|
|
1560
|
+
declare const VISUAL_LAYER_TRANSITIONS: readonly ["show", "hide", "replace", "crossfade"];
|
|
1561
|
+
type VisualLayerTransitionKind = (typeof VISUAL_LAYER_TRANSITIONS)[number];
|
|
1562
|
+
declare const VISUAL_LAYER_EVENTS: readonly ["visual.layer.revealed", "visual.layer.hidden", "visual.layer.transition-started", "visual.layer.transition-completed", "visual.layer.failed"];
|
|
1563
|
+
type VisualLayerEventType = (typeof VISUAL_LAYER_EVENTS)[number];
|
|
1564
|
+
declare const VISUAL_LAYER_FAILURE_CODES: readonly ["asset-failed", "missing-source", "unknown-layer", "unknown-version", "invalid-snapshot"];
|
|
1565
|
+
type VisualLayerFailureCode = (typeof VISUAL_LAYER_FAILURE_CODES)[number];
|
|
1566
|
+
type VisualLayerAssetStatus = 'pending' | 'ready' | 'failed';
|
|
1567
|
+
type VisualLayerFallbackPolicy = 'keep-prior' | 'hide' | {
|
|
1568
|
+
version: string;
|
|
1569
|
+
};
|
|
1570
|
+
type VisualLayerVersionDeclaration = {
|
|
1571
|
+
id: string;
|
|
1572
|
+
assetId: string;
|
|
1573
|
+
provenance?: AssetProvenance;
|
|
1574
|
+
};
|
|
1575
|
+
type VisualLayerDeclaration = {
|
|
1576
|
+
id: string;
|
|
1577
|
+
kind: VisualLayerKind;
|
|
1578
|
+
versions: readonly VisualLayerVersionDeclaration[];
|
|
1579
|
+
initialVersion?: string;
|
|
1580
|
+
compositorLayerId?: string;
|
|
1581
|
+
incomingLayerId?: string;
|
|
1582
|
+
order?: number;
|
|
1583
|
+
blend?: CompositorBlendMode;
|
|
1584
|
+
clip?: CompositorClip;
|
|
1585
|
+
pointerEvents?: CompositorPointerEvents;
|
|
1586
|
+
clearPolicy?: CompositorClearPolicy;
|
|
1587
|
+
fallback?: VisualLayerFallbackPolicy;
|
|
1588
|
+
};
|
|
1589
|
+
type VisualLayerAcceptedBinding = {
|
|
1590
|
+
layerId: string;
|
|
1591
|
+
toVersion: string;
|
|
1592
|
+
kind?: VisualLayerTransitionKind;
|
|
1593
|
+
durationFrames?: number;
|
|
1594
|
+
delayFrames?: number;
|
|
1595
|
+
easing?: CueEasing;
|
|
1596
|
+
idempotencyKey?: string;
|
|
1597
|
+
};
|
|
1598
|
+
type VisualLayerCueSpec = CueSpec & {
|
|
1599
|
+
layerId: string;
|
|
1600
|
+
kind: VisualLayerTransitionKind;
|
|
1601
|
+
toVersion?: string;
|
|
1602
|
+
fromVersion?: string;
|
|
1603
|
+
};
|
|
1604
|
+
type VisualLayerTransitionInspect = {
|
|
1605
|
+
kind: VisualLayerTransitionKind;
|
|
1606
|
+
progress: number;
|
|
1607
|
+
fromVersion: string | null;
|
|
1608
|
+
toVersion: string | null;
|
|
1609
|
+
cueKey: string;
|
|
1610
|
+
startFrame: number;
|
|
1611
|
+
durationFrames: number;
|
|
1612
|
+
delayFrames: number;
|
|
1613
|
+
easing: CueEasing;
|
|
1614
|
+
};
|
|
1615
|
+
type VisualLayerInspect = {
|
|
1616
|
+
id: string;
|
|
1617
|
+
kind: VisualLayerKind;
|
|
1618
|
+
visible: boolean;
|
|
1619
|
+
activeVersion: string | null;
|
|
1620
|
+
pendingVersion: string | null;
|
|
1621
|
+
committedVersion: string | null;
|
|
1622
|
+
opacity: number;
|
|
1623
|
+
order: number;
|
|
1624
|
+
provenance: AssetProvenance | null;
|
|
1625
|
+
overrideVersion: string | null;
|
|
1626
|
+
transition: VisualLayerTransitionInspect | null;
|
|
1627
|
+
};
|
|
1628
|
+
type VisualLayerEvent = {
|
|
1629
|
+
type: VisualLayerEventType;
|
|
1630
|
+
atFrame: number;
|
|
1631
|
+
layerId: string;
|
|
1632
|
+
version?: string;
|
|
1633
|
+
kind?: VisualLayerTransitionKind;
|
|
1634
|
+
progress: number;
|
|
1635
|
+
code?: VisualLayerFailureCode;
|
|
1636
|
+
};
|
|
1637
|
+
type VisualLayerDiagnostic = {
|
|
1638
|
+
code: VisualLayerFailureCode;
|
|
1639
|
+
layerId: string;
|
|
1640
|
+
version?: string;
|
|
1641
|
+
assetId?: string;
|
|
1642
|
+
message: string;
|
|
1643
|
+
atFrame: number;
|
|
1644
|
+
failure?: AssetFailure;
|
|
1645
|
+
};
|
|
1646
|
+
type VisualLayerSnapshotRow = {
|
|
1647
|
+
id: string;
|
|
1648
|
+
kind: VisualLayerKind;
|
|
1649
|
+
visible: boolean;
|
|
1650
|
+
committedVersion: string | null;
|
|
1651
|
+
pendingVersion: string | null;
|
|
1652
|
+
activeVersion: string | null;
|
|
1653
|
+
opacity: number;
|
|
1654
|
+
order: number;
|
|
1655
|
+
overrideVersion: string | null;
|
|
1656
|
+
provenance: AssetProvenance | null;
|
|
1657
|
+
fallback: VisualLayerFallbackPolicy;
|
|
1658
|
+
transition: VisualLayerTransitionInspect | null;
|
|
1659
|
+
};
|
|
1660
|
+
type VisualLayerControllerSnapshot = {
|
|
1661
|
+
schemaVersion: typeof VISUAL_LAYER_SNAPSHOT_SCHEMA_VERSION;
|
|
1662
|
+
frame: number;
|
|
1663
|
+
sceneId: string | null;
|
|
1664
|
+
reducedMotion: boolean;
|
|
1665
|
+
layers: VisualLayerSnapshotRow[];
|
|
1666
|
+
assets: Record<string, VisualLayerAssetStatus>;
|
|
1667
|
+
events: VisualLayerEvent[];
|
|
1668
|
+
diagnostics: VisualLayerDiagnostic[];
|
|
1669
|
+
};
|
|
1670
|
+
type PlayVisualLayerResult = PlayCueResult;
|
|
1671
|
+
type RestoreVisualLayerResult = {
|
|
1672
|
+
ok: true;
|
|
1673
|
+
snapshot: VisualLayerControllerSnapshot;
|
|
1674
|
+
} | {
|
|
1675
|
+
ok: false;
|
|
1676
|
+
errors: VisualLayerDiagnostic[];
|
|
1677
|
+
};
|
|
1678
|
+
type CreateVisualLayerControllerOptions = {
|
|
1679
|
+
compositor: Compositor;
|
|
1680
|
+
layers: readonly VisualLayerDeclaration[];
|
|
1681
|
+
preloader?: AssetPreloader;
|
|
1682
|
+
originFrame?: number;
|
|
1683
|
+
reducedMotion?: boolean;
|
|
1684
|
+
sceneId?: string;
|
|
1685
|
+
fallback?: VisualLayerFallbackPolicy;
|
|
1686
|
+
onAccepted?: readonly VisualLayerAcceptedBinding[];
|
|
1687
|
+
dispatch?: (event: HostEvent) => void;
|
|
1688
|
+
};
|
|
1689
|
+
type VisualLayerController = {
|
|
1690
|
+
registerSource(assetId: string, source: ImageData | HTMLCanvasElement): void;
|
|
1691
|
+
handleHostEvent(event: HostEvent): void;
|
|
1692
|
+
override(layerId: string, version: string | null): void;
|
|
1693
|
+
play(spec: VisualLayerCueSpec): PlayVisualLayerResult;
|
|
1694
|
+
step(frames?: number): VisualLayerEvent[];
|
|
1695
|
+
snapshot(): VisualLayerControllerSnapshot;
|
|
1696
|
+
restore(input: unknown): RestoreVisualLayerResult;
|
|
1697
|
+
inspect(): VisualLayerInspect[];
|
|
1698
|
+
captureComposedFrame(): ComposedFrame;
|
|
1699
|
+
destroy(): void;
|
|
1700
|
+
readonly frame: number;
|
|
1701
|
+
readonly sceneId: string | null;
|
|
1702
|
+
readonly compositor: Compositor;
|
|
1703
|
+
};
|
|
1704
|
+
type VisualLayerCapture = {
|
|
1705
|
+
frame: ComposedFrame;
|
|
1706
|
+
layers: VisualLayerInspect[];
|
|
1707
|
+
};
|
|
1708
|
+
declare function captureVisualLayers(controller: VisualLayerController): VisualLayerCapture;
|
|
1709
|
+
declare function createVisualLayerController(options: CreateVisualLayerControllerOptions): VisualLayerController;
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* Copyright (c) 2026 Aaron Boyarsky
|
|
1713
|
+
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
1714
|
+
* See packages/engine/LICENSE
|
|
1715
|
+
*
|
|
1716
|
+
* Cart-agnostic update/render frame benchmark for CI and agent workflows.
|
|
1717
|
+
* Prefer this over ad-hoc vitest probes when evaluating hash / trait cost.
|
|
1718
|
+
*/
|
|
1719
|
+
|
|
1720
|
+
type FrameBenchmarkOptions = {
|
|
1721
|
+
/** Measured frames after warmup. Default 30. */
|
|
1722
|
+
frames?: number;
|
|
1723
|
+
/** Discarded frames before measurement. Default 5. */
|
|
1724
|
+
warmupFrames?: number;
|
|
1725
|
+
/** Simulated frame advance in ms. Default 1000/60. */
|
|
1726
|
+
frameStepMs?: number;
|
|
1727
|
+
width?: number;
|
|
1728
|
+
height?: number;
|
|
1729
|
+
tokenId?: string;
|
|
1730
|
+
/**
|
|
1731
|
+
* Mutate state after `getDefaultState` (e.g. skip Tone init in jsdom by
|
|
1732
|
+
* setting `audioContextStarted = true`).
|
|
1733
|
+
*/
|
|
1734
|
+
prepareState?: (state: unknown, featureState: unknown) => void;
|
|
1735
|
+
/** Optional stub drawing context; defaults to a no-op `putImageData`. */
|
|
1736
|
+
drawingContext?: CanvasRenderingContext2D;
|
|
1737
|
+
};
|
|
1738
|
+
type FrameBenchmarkResult = {
|
|
1739
|
+
frames: number;
|
|
1740
|
+
updateAvgMs: number;
|
|
1741
|
+
renderAvgMs: number;
|
|
1742
|
+
totalAvgMs: number;
|
|
1743
|
+
updateMaxMs: number;
|
|
1744
|
+
renderMaxMs: number;
|
|
1745
|
+
estFps: number;
|
|
1746
|
+
updatePct: number;
|
|
1747
|
+
renderPct: number;
|
|
1748
|
+
};
|
|
1749
|
+
/**
|
|
1750
|
+
* Run a cart's update/render loop headlessly and report average / max phase
|
|
1751
|
+
* timings. Does not start audio or mount a live AnimationManager — suitable
|
|
1752
|
+
* for jsdom vitest and agent hash probes.
|
|
1753
|
+
*/
|
|
1754
|
+
declare function benchmarkCartFrames<T, TFeatureState = undefined>(cart: AnimationCart<T, TFeatureState>, hash: string, rawParams: number[], options?: FrameBenchmarkOptions): FrameBenchmarkResult;
|
|
1755
|
+
/** Round timing fields for stable console / snapshot logging. */
|
|
1756
|
+
declare function formatFrameBenchmarkResult(result: FrameBenchmarkResult, digits?: number): Record<string, number>;
|
|
1757
|
+
|
|
1497
1758
|
/**
|
|
1498
1759
|
* Copyright (c) 2026 Aaron Boyarsky
|
|
1499
1760
|
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
@@ -1501,7 +1762,8 @@ declare function createHeadlessAudioAdapter(options?: {
|
|
|
1501
1762
|
*
|
|
1502
1763
|
* Node/jsdom test helpers. Import from `@cyberart-io/engine/headless`.
|
|
1503
1764
|
* Production carts and browser hosts must import `@cyberart-io/engine` instead
|
|
1504
|
-
* so Vite never walks `node:fs/promises`.
|
|
1765
|
+
* so Vite never walks `node:fs/promises`. `createHeadlessMultiCartHarness`
|
|
1766
|
+
* is the same group API as `createRuntimeGroup`, including calculation carts.
|
|
1505
1767
|
*/
|
|
1506
1768
|
|
|
1507
1769
|
type WriteComposedFrameResult = ComposedFrame & {
|
|
@@ -1513,4 +1775,4 @@ type WriteComposedFrameResult = ComposedFrame & {
|
|
|
1513
1775
|
*/
|
|
1514
1776
|
declare function writeComposedFrame(compositor: Compositor, path?: string): Promise<WriteComposedFrameResult>;
|
|
1515
1777
|
|
|
1516
|
-
export { type BoundReplaySession, type CausationTreeNode, type CreateHeadlessHarnessOptions, type CreateHeadlessMultiCartHarnessOptions, type CreateReplayInspectorOptions, DEFAULT_HEADLESS_HEIGHT, DEFAULT_HEADLESS_WIDTH, type GlyphAtlas, HEADLESS_PNG_DATA_URL, type HeadlessAudioAdapter, type HeadlessCanvas2DSettings, type HeadlessFrameError, type HeadlessHarness, type HeadlessImageFixture, type HeadlessInspect, type HeadlessMultiCartHarness, HeadlessUnsupportedOperationError, type InspectorRecord, type InstallHeadlessCanvasOptions, type ReplayCompareResult, type ReplayInspector, type ReplayInspectorExport, type ReplayInspectorReport, type ReplayParticipantSummary, type ReplayTapeAction, type ReplayTraceFilter, UPDATE_GOLDEN_ENV, type VisualArtifactPaths, type VisualArtifacts, type VisualCompareOptions, type VisualCompareResult, type WriteComposedFrameResult, assertPixelsEqual, assertPngDataUrlsEqual, attachHeadlessCanvas2D, compareImageData, compareReplayTraces, createDefaultGlyphAtlas, createHeadlessAudioAdapter, createHeadlessHarness, createHeadlessMultiCartHarness, createImageFixture, createReplayInspector, decodePng, encodePng, encodePngDataUrl, getHeadlessSurface, imageDataFromPngDataUrl, installHeadlessCanvas, makeImageData, replayExportedTrace, setDefaultGlyphAtlas, shouldUpdateGolden, writeComposedFrame, writeVisualArtifacts };
|
|
1778
|
+
export { type BoundReplaySession, type CausationTreeNode, type CreateHeadlessHarnessOptions, type CreateHeadlessMultiCartHarnessOptions, type CreateReplayInspectorOptions, DEFAULT_HEADLESS_HEIGHT, DEFAULT_HEADLESS_WIDTH, type FrameBenchmarkOptions, type FrameBenchmarkResult, type GlyphAtlas, HEADLESS_PNG_DATA_URL, type HeadlessAudioAdapter, type HeadlessCanvas2DSettings, type HeadlessFrameError, type HeadlessHarness, type HeadlessImageFixture, type HeadlessInspect, type HeadlessMultiCartHarness, HeadlessUnsupportedOperationError, type InspectorRecord, type InstallHeadlessCanvasOptions, type ReplayCompareResult, type ReplayInspector, type ReplayInspectorExport, type ReplayInspectorReport, type ReplayParticipantSummary, type ReplayTapeAction, type ReplayTraceFilter, UPDATE_GOLDEN_ENV, type VisualArtifactPaths, type VisualArtifacts, type VisualCompareOptions, type VisualCompareResult, type VisualLayerCapture, type VisualLayerController, type VisualLayerInspect, type WriteComposedFrameResult, assertPixelsEqual, assertPngDataUrlsEqual, attachHeadlessCanvas2D, benchmarkCartFrames, captureVisualLayers, compareImageData, compareReplayTraces, createDefaultGlyphAtlas, createHeadlessAudioAdapter, createHeadlessHarness, createHeadlessMultiCartHarness, createImageFixture, createReplayInspector, createVisualLayerController, decodePng, encodePng, encodePngDataUrl, formatFrameBenchmarkResult, getHeadlessSurface, imageDataFromPngDataUrl, installHeadlessCanvas, makeImageData, replayExportedTrace, setDefaultGlyphAtlas, shouldUpdateGolden, writeComposedFrame, writeVisualArtifacts };
|