@cyberart-io/engine 0.0.2 → 0.0.3
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 +137 -7
- package/dist/headless.d.ts +637 -0
- package/dist/headless.js +8 -0
- package/dist/index.d.ts +467 -64
- package/dist/index.js +1 -1
- package/docs/asset-resolver.md +155 -0
- package/docs/deterministic-mode.md +1 -1
- package/docs/events.md +79 -10
- package/docs/headless-harness.md +58 -16
- package/docs/presentation-adapter.md +150 -0
- package/docs/presentation-cue.md +82 -0
- package/package.json +13 -2
package/dist/index.d.ts
CHANGED
|
@@ -255,7 +255,9 @@ type NormalizeFailure = {
|
|
|
255
255
|
type NormalizeResult = NormalizeSuccess | NormalizeFailure;
|
|
256
256
|
/**
|
|
257
257
|
* `kind` on the input wins. Otherwise persistence types are intents, then
|
|
258
|
-
* the
|
|
258
|
+
* the first dotted segment that is `intent` | `state` | `diagnostic`.
|
|
259
|
+
* `adventure.presentation.*` does not infer a kind (the presentation segment
|
|
260
|
+
* is not one); put the kind in the name, e.g. `adventure.presentation.intent.*`.
|
|
259
261
|
*/
|
|
260
262
|
declare function inferEventKind(input: EventInput): EventKind | undefined;
|
|
261
263
|
declare function matchEventPattern(pattern: string, type: string): boolean;
|
|
@@ -281,11 +283,18 @@ type HostEventListener = (event: HostEvent) => void;
|
|
|
281
283
|
declare class HostChannel {
|
|
282
284
|
private inbound;
|
|
283
285
|
private listeners;
|
|
286
|
+
private closed;
|
|
284
287
|
dispatch(event: HostEvent): void;
|
|
285
288
|
consume(): HostEvent[];
|
|
286
289
|
emit(event: HostEvent): void;
|
|
287
290
|
onEvent(listener: HostEventListener): () => void;
|
|
291
|
+
/** Drop queued inbound events. Does not remove `onEvent` listeners. */
|
|
292
|
+
clearInbound(): void;
|
|
293
|
+
/** Drop inbound events and listeners. Runtime teardown; not cart unload. */
|
|
288
294
|
clear(): void;
|
|
295
|
+
/** Permanent close. Further dispatch / emit / consume / onEvent throw. */
|
|
296
|
+
close(): void;
|
|
297
|
+
private requireOpen;
|
|
289
298
|
}
|
|
290
299
|
|
|
291
300
|
/**
|
|
@@ -404,6 +413,8 @@ declare class IncompatibleCartStateError extends Error {
|
|
|
404
413
|
*
|
|
405
414
|
* Host-controlled time, input, and asset completion for deterministic replays.
|
|
406
415
|
* Production kaleidoscope / Art Blocks playback does not enable this mode.
|
|
416
|
+
* Logical asset URLs are resolved by the host preloader (`assetResolver.ts`);
|
|
417
|
+
* this module only times `ASSET_READY_EVENT` / `ASSET_FAILED_EVENT` delivery.
|
|
407
418
|
*/
|
|
408
419
|
|
|
409
420
|
declare const ASSET_READY_EVENT = "cyberart.asset.ready";
|
|
@@ -428,6 +439,7 @@ type ScriptedAction = {
|
|
|
428
439
|
type: 'asset';
|
|
429
440
|
id: string;
|
|
430
441
|
status: 'ready' | 'failed';
|
|
442
|
+
/** Optional structured failure or resolved resource. Envelope is unchanged. */
|
|
431
443
|
detail?: unknown;
|
|
432
444
|
});
|
|
433
445
|
type DeterministicRuntimeOptions = {
|
|
@@ -460,6 +472,151 @@ type AppliedAction = {
|
|
|
460
472
|
*/
|
|
461
473
|
declare function describeReplayMismatch(a: ReplayMetadata, b: ReplayMetadata): string[];
|
|
462
474
|
|
|
475
|
+
declare const ASSET_KINDS: readonly ["image", "audio", "font", "spritesheet"];
|
|
476
|
+
type AssetKind = (typeof ASSET_KINDS)[number];
|
|
477
|
+
declare const ASSET_FAILURE_CODES: readonly ["timeout", "cors", "not-found", "invalid", "aborted", "resolver"];
|
|
478
|
+
type AssetFailureCode = (typeof ASSET_FAILURE_CODES)[number];
|
|
479
|
+
type AssetCorsMode = 'anonymous' | 'use-credentials' | 'omit';
|
|
480
|
+
/** Logical silent placeholder. Carts/hosts may treat it as “no media”. */
|
|
481
|
+
declare const SILENT_ASSET_FALLBACK_REF = "cyberart:fallback/silent";
|
|
482
|
+
type AssetProvenance = {
|
|
483
|
+
readonly [key: string]: string | number | boolean | null | undefined;
|
|
484
|
+
};
|
|
485
|
+
type AssetDeclaration = {
|
|
486
|
+
/** Cache key and `ASSET_*_EVENT` payload `id`. */
|
|
487
|
+
id: string;
|
|
488
|
+
/** Logical URI: `https://…`, `moltazine:post/<id>#fragment`, `world:asset/…`, `library:…`. */
|
|
489
|
+
ref: string;
|
|
490
|
+
type: AssetKind;
|
|
491
|
+
integrity?: string;
|
|
492
|
+
provenance?: AssetProvenance;
|
|
493
|
+
/** Per-asset timeout. Ignored when wall-clock timeouts are off (deterministic). */
|
|
494
|
+
timeoutMs?: number;
|
|
495
|
+
/**
|
|
496
|
+
* `'silent'` synthesizes `SILENT_ASSET_FALLBACK_REF`. A string is another
|
|
497
|
+
* logical ref of the same type. A declaration is resolved as-is.
|
|
498
|
+
*/
|
|
499
|
+
fallback?: 'silent' | string | AssetDeclaration;
|
|
500
|
+
};
|
|
501
|
+
type AssetResolveRequest = {
|
|
502
|
+
id: string;
|
|
503
|
+
ref: string;
|
|
504
|
+
type: AssetKind;
|
|
505
|
+
integrity?: string;
|
|
506
|
+
provenance?: AssetProvenance;
|
|
507
|
+
};
|
|
508
|
+
type ResolvedAsset = {
|
|
509
|
+
id: string;
|
|
510
|
+
ref: string;
|
|
511
|
+
type: AssetKind;
|
|
512
|
+
url: string;
|
|
513
|
+
integrity?: string;
|
|
514
|
+
provenance?: AssetProvenance;
|
|
515
|
+
cors?: AssetCorsMode;
|
|
516
|
+
usedFallback?: boolean;
|
|
517
|
+
/** When true, `dispose` / `forget` call `URL.revokeObjectURL`. */
|
|
518
|
+
managed?: boolean;
|
|
519
|
+
};
|
|
520
|
+
type AssetFailure = {
|
|
521
|
+
id: string;
|
|
522
|
+
ref: string;
|
|
523
|
+
code: AssetFailureCode;
|
|
524
|
+
message: string;
|
|
525
|
+
};
|
|
526
|
+
type AssetItemStatus = {
|
|
527
|
+
state: 'pending';
|
|
528
|
+
} | {
|
|
529
|
+
state: 'loading';
|
|
530
|
+
} | {
|
|
531
|
+
state: 'ready';
|
|
532
|
+
resource: ResolvedAsset;
|
|
533
|
+
failure?: AssetFailure;
|
|
534
|
+
} | {
|
|
535
|
+
state: 'failed';
|
|
536
|
+
failure: AssetFailure;
|
|
537
|
+
};
|
|
538
|
+
type AssetPreloadSnapshot = {
|
|
539
|
+
total: number;
|
|
540
|
+
pending: number;
|
|
541
|
+
ready: number;
|
|
542
|
+
failed: number;
|
|
543
|
+
fallbacks: number;
|
|
544
|
+
items: Record<string, AssetItemStatus>;
|
|
545
|
+
failures: AssetFailure[];
|
|
546
|
+
};
|
|
547
|
+
type AssetResolver = {
|
|
548
|
+
resolve(request: AssetResolveRequest, signal?: AbortSignal): Promise<ResolvedAsset>;
|
|
549
|
+
};
|
|
550
|
+
type CreateAssetPreloaderOptions = {
|
|
551
|
+
resolver: AssetResolver;
|
|
552
|
+
timeoutMs?: number;
|
|
553
|
+
/**
|
|
554
|
+
* Dispatch `ASSET_READY_EVENT` / `ASSET_FAILED_EVENT` as loads settle.
|
|
555
|
+
* Default true. Deterministic runtimes pass false so scripted `asset`
|
|
556
|
+
* actions own delivery timing.
|
|
557
|
+
*/
|
|
558
|
+
emitEvents?: boolean;
|
|
559
|
+
/**
|
|
560
|
+
* Apply `timeoutMs` with `setTimeout`. Default true. Deterministic
|
|
561
|
+
* runtimes pass false so tests do not wait on wall-clock fetch.
|
|
562
|
+
*/
|
|
563
|
+
wallClockTimeout?: boolean;
|
|
564
|
+
dispatch?: (event: HostEvent) => void;
|
|
565
|
+
};
|
|
566
|
+
type AssetRuntimeOptions = {
|
|
567
|
+
resolver: AssetResolver;
|
|
568
|
+
timeoutMs?: number;
|
|
569
|
+
emitEvents?: boolean;
|
|
570
|
+
};
|
|
571
|
+
type AssetPreloader = {
|
|
572
|
+
preload(declarations: readonly AssetDeclaration[]): Promise<AssetPreloadSnapshot>;
|
|
573
|
+
get(id: string): ResolvedAsset | undefined;
|
|
574
|
+
getProgress(): AssetPreloadSnapshot;
|
|
575
|
+
onProgress(listener: (snapshot: AssetPreloadSnapshot) => void): () => void;
|
|
576
|
+
abort(id?: string): void;
|
|
577
|
+
forget(id?: string): void;
|
|
578
|
+
dispose(): void;
|
|
579
|
+
};
|
|
580
|
+
type FixtureAssetRecord = {
|
|
581
|
+
url: string;
|
|
582
|
+
integrity?: string;
|
|
583
|
+
cors?: AssetCorsMode;
|
|
584
|
+
provenance?: AssetProvenance;
|
|
585
|
+
} | {
|
|
586
|
+
error: AssetFailureCode;
|
|
587
|
+
message?: string;
|
|
588
|
+
};
|
|
589
|
+
type FixtureAssetCatalog = Readonly<Record<string, FixtureAssetRecord>>;
|
|
590
|
+
type HostedAssetResolverOptions = {
|
|
591
|
+
/** Prefix for rewritten logical refs. `http(s)` / `data:` / `blob:` pass through. */
|
|
592
|
+
cdnBase: string;
|
|
593
|
+
/** Authored refs that fail with a structured code. No network. */
|
|
594
|
+
failures?: Readonly<Record<string, AssetFailureCode | {
|
|
595
|
+
code: AssetFailureCode;
|
|
596
|
+
message?: string;
|
|
597
|
+
}>>;
|
|
598
|
+
};
|
|
599
|
+
declare function isAssetKind(value: unknown): value is AssetKind;
|
|
600
|
+
declare function isAssetFailureCode(value: unknown): value is AssetFailureCode;
|
|
601
|
+
declare function isAssetFailure(value: unknown): value is AssetFailure;
|
|
602
|
+
declare function createAssetFailure(input: {
|
|
603
|
+
id: string;
|
|
604
|
+
ref: string;
|
|
605
|
+
code: AssetFailureCode;
|
|
606
|
+
message?: string;
|
|
607
|
+
}): AssetFailure;
|
|
608
|
+
declare function assetStatusEvent(status: 'ready' | 'failed', payload: {
|
|
609
|
+
id: string;
|
|
610
|
+
ref?: string;
|
|
611
|
+
resource?: ResolvedAsset;
|
|
612
|
+
failure?: AssetFailure;
|
|
613
|
+
}): HostEvent;
|
|
614
|
+
/** Map a logical ref through a hosted CDN prefix. Ordinary URLs are unchanged. */
|
|
615
|
+
declare function rewriteHostedAssetRef(ref: string, cdnBase: string): string;
|
|
616
|
+
declare function createFixtureAssetResolver(catalog: FixtureAssetCatalog): AssetResolver;
|
|
617
|
+
declare function createHostedAssetResolver(options: HostedAssetResolverOptions): AssetResolver;
|
|
618
|
+
declare function createAssetPreloader(options: CreateAssetPreloaderOptions): AssetPreloader;
|
|
619
|
+
|
|
463
620
|
/**
|
|
464
621
|
* Copyright (c) 2026 Aaron Boyarsky
|
|
465
622
|
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
@@ -497,6 +654,13 @@ type CreateRuntimeOptions = {
|
|
|
497
654
|
* token hash drive the piece as they do today.
|
|
498
655
|
*/
|
|
499
656
|
deterministic?: boolean | DeterministicRuntimeOptions;
|
|
657
|
+
/**
|
|
658
|
+
* Host-pluggable asset resolver/preloader. Carts request logical refs;
|
|
659
|
+
* the host maps them to loadable URLs or blobs. Leave unset when unused.
|
|
660
|
+
* In deterministic mode, preload does not dispatch `ASSET_*` events —
|
|
661
|
+
* scripted `{ type: 'asset' }` actions own delivery timing.
|
|
662
|
+
*/
|
|
663
|
+
assets?: AssetRuntimeOptions;
|
|
500
664
|
};
|
|
501
665
|
type MountOptions<T = unknown> = {
|
|
502
666
|
/** Boot overrides passed as `customState` into `getDefaultState`. Not a live-state replay. */
|
|
@@ -558,72 +722,20 @@ type CyberArtRuntime = {
|
|
|
558
722
|
unlockAudio(): Promise<void>;
|
|
559
723
|
destroy(): void;
|
|
560
724
|
readonly tokenData: TokenData;
|
|
725
|
+
/**
|
|
726
|
+
* This runtime's mailbox. Attach it to `createEventRouter` from the host;
|
|
727
|
+
* carts never receive the router. Survives cart remount; `destroy()` clears it.
|
|
728
|
+
*/
|
|
729
|
+
readonly hostChannel: HostChannel;
|
|
730
|
+
/**
|
|
731
|
+
* Preloader for this runtime. Undefined when `assets` was omitted.
|
|
732
|
+
* Survives cart remount; `destroy()` disposes it.
|
|
733
|
+
*/
|
|
734
|
+
readonly assets: AssetPreloader | undefined;
|
|
561
735
|
onError?: (error: unknown, info: FrameErrorInfo) => void;
|
|
562
736
|
};
|
|
563
737
|
declare function createRuntime(options: CreateRuntimeOptions): CyberArtRuntime;
|
|
564
738
|
|
|
565
|
-
/**
|
|
566
|
-
* Copyright (c) 2026 Aaron Boyarsky
|
|
567
|
-
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
568
|
-
* See packages/engine/LICENSE
|
|
569
|
-
*
|
|
570
|
-
* CI / agent harness around production `createRuntime({ deterministic })`.
|
|
571
|
-
* `installHeadlessCanvas` is test-only — do not call it from Player or kaleidoscope.
|
|
572
|
-
*/
|
|
573
|
-
|
|
574
|
-
/** 1×1 PNG so `captureFrame(path)` writes a file that actually opens. */
|
|
575
|
-
declare const HEADLESS_PNG_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";
|
|
576
|
-
declare const DEFAULT_HEADLESS_WIDTH = 320;
|
|
577
|
-
declare const DEFAULT_HEADLESS_HEIGHT = 180;
|
|
578
|
-
/**
|
|
579
|
-
* Documented jsdom canvas install. Mutates `HTMLCanvasElement.prototype`.
|
|
580
|
-
* Idempotent. Not for production playback.
|
|
581
|
-
*/
|
|
582
|
-
declare function installHeadlessCanvas(): void;
|
|
583
|
-
type HeadlessFrameError = {
|
|
584
|
-
error: unknown;
|
|
585
|
-
info: FrameErrorInfo;
|
|
586
|
-
};
|
|
587
|
-
type HeadlessInspect = {
|
|
588
|
-
state: unknown;
|
|
589
|
-
events: HostEvent[];
|
|
590
|
-
errors: HeadlessFrameError[];
|
|
591
|
-
replay: ReplayMetadata;
|
|
592
|
-
clock: ClockSnapshot;
|
|
593
|
-
};
|
|
594
|
-
type CreateHeadlessHarnessOptions<T = unknown> = {
|
|
595
|
-
cart: AnimationCart<T>;
|
|
596
|
-
seed?: CreateRuntimeOptions['seed'];
|
|
597
|
-
width?: number;
|
|
598
|
-
height?: number;
|
|
599
|
-
/** Virtual clock origin in ms. Default 0. */
|
|
600
|
-
origin?: number;
|
|
601
|
-
actions?: ScriptedAction[];
|
|
602
|
-
initialState?: Partial<T>;
|
|
603
|
-
gameManager?: unknown;
|
|
604
|
-
onEvent?: HostEventListener;
|
|
605
|
-
onError?: (error: unknown, info: FrameErrorInfo) => void;
|
|
606
|
-
};
|
|
607
|
-
type HeadlessHarness<T = unknown> = {
|
|
608
|
-
readonly runtime: CyberArtRuntime;
|
|
609
|
-
readonly container: HTMLElement;
|
|
610
|
-
readonly events: readonly HostEvent[];
|
|
611
|
-
readonly errors: readonly HeadlessFrameError[];
|
|
612
|
-
readonly cart: CartHandle;
|
|
613
|
-
step(frames?: number): Promise<void>;
|
|
614
|
-
advance(ms: number): Promise<void>;
|
|
615
|
-
schedule(action: ScriptedAction): void;
|
|
616
|
-
dispatch(event: HostEvent): void;
|
|
617
|
-
key(key: string): void;
|
|
618
|
-
/** Pointer-down at the next frame. Use `schedule` for move/up. Canvas pixels, not CSS. */
|
|
619
|
-
click(x: number, y: number): void;
|
|
620
|
-
inspect(): Promise<HeadlessInspect>;
|
|
621
|
-
captureFrame(path?: string): Promise<CartSnapshot>;
|
|
622
|
-
remount(options?: MountOptions<T>): CartHandle;
|
|
623
|
-
destroy(): void;
|
|
624
|
-
};
|
|
625
|
-
declare function createHeadlessHarness<T>(options: CreateHeadlessHarnessOptions<T>): HeadlessHarness<T>;
|
|
626
|
-
|
|
627
739
|
/**
|
|
628
740
|
* Copyright (c) 2026 Aaron Boyarsky
|
|
629
741
|
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
@@ -716,4 +828,295 @@ type EventRouter = {
|
|
|
716
828
|
};
|
|
717
829
|
declare function createEventRouter(options?: EventRouterOptions): EventRouter;
|
|
718
830
|
|
|
719
|
-
|
|
831
|
+
/**
|
|
832
|
+
* Copyright (c) 2026 Aaron Boyarsky
|
|
833
|
+
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
834
|
+
* See packages/engine/LICENSE
|
|
835
|
+
*
|
|
836
|
+
* One contract definition drives TypeScript payload types, runtime
|
|
837
|
+
* validation, router permission checks, and machine-readable manifests.
|
|
838
|
+
* Kind must appear as a dotted segment of `type` so names like
|
|
839
|
+
* `adventure.presentation.cue.started` fail at definition time instead of
|
|
840
|
+
* silently inferring a bogus kind.
|
|
841
|
+
*/
|
|
842
|
+
|
|
843
|
+
type ContractFieldType = 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
844
|
+
type PayloadFieldSpec = {
|
|
845
|
+
type: ContractFieldType;
|
|
846
|
+
optional?: boolean;
|
|
847
|
+
};
|
|
848
|
+
type PayloadSchema = {
|
|
849
|
+
/** Payload schema version. Bump on any field change. */
|
|
850
|
+
version: number;
|
|
851
|
+
fields: Record<string, PayloadFieldSpec>;
|
|
852
|
+
};
|
|
853
|
+
type ContractDiagnostic = {
|
|
854
|
+
code: string;
|
|
855
|
+
detail: string;
|
|
856
|
+
path?: string;
|
|
857
|
+
};
|
|
858
|
+
type EventContractManifest = {
|
|
859
|
+
type: string;
|
|
860
|
+
kind: EventKind;
|
|
861
|
+
version: number;
|
|
862
|
+
fields: Record<string, {
|
|
863
|
+
type: ContractFieldType;
|
|
864
|
+
optional: boolean;
|
|
865
|
+
}>;
|
|
866
|
+
emitPattern: string;
|
|
867
|
+
subscribePattern: string;
|
|
868
|
+
};
|
|
869
|
+
type PayloadValidation = {
|
|
870
|
+
ok: true;
|
|
871
|
+
payload: unknown;
|
|
872
|
+
} | {
|
|
873
|
+
ok: false;
|
|
874
|
+
errors: ContractDiagnostic[];
|
|
875
|
+
};
|
|
876
|
+
type EventContract = {
|
|
877
|
+
type: string;
|
|
878
|
+
kind: EventKind;
|
|
879
|
+
payloadSchema: PayloadSchema;
|
|
880
|
+
emitPattern: string;
|
|
881
|
+
subscribePattern: string;
|
|
882
|
+
toManifest(): EventContractManifest;
|
|
883
|
+
validatePayload(payload: unknown): PayloadValidation;
|
|
884
|
+
};
|
|
885
|
+
type DefineContractResult = {
|
|
886
|
+
ok: true;
|
|
887
|
+
contract: EventContract;
|
|
888
|
+
} | {
|
|
889
|
+
ok: false;
|
|
890
|
+
errors: ContractDiagnostic[];
|
|
891
|
+
};
|
|
892
|
+
type SchemaCompatibility = 'identical' | 'backward-compatible' | 'breaking';
|
|
893
|
+
type FieldTs<T extends ContractFieldType> = T extends 'string' ? string : T extends 'number' ? number : T extends 'boolean' ? boolean : T extends 'array' ? unknown[] : Record<string, unknown>;
|
|
894
|
+
type OptionalFieldKeys<S extends PayloadSchema> = {
|
|
895
|
+
[K in keyof S['fields']]: S['fields'][K] extends {
|
|
896
|
+
optional: true;
|
|
897
|
+
} ? K : never;
|
|
898
|
+
}[keyof S['fields']];
|
|
899
|
+
type RequiredFieldKeys<S extends PayloadSchema> = Exclude<keyof S['fields'], OptionalFieldKeys<S>>;
|
|
900
|
+
type InferredPayload<S extends PayloadSchema> = {
|
|
901
|
+
[K in RequiredFieldKeys<S>]: FieldTs<S['fields'][K]['type']>;
|
|
902
|
+
} & {
|
|
903
|
+
[K in OptionalFieldKeys<S>]?: FieldTs<S['fields'][K]['type']>;
|
|
904
|
+
};
|
|
905
|
+
/** First dotted segment that is `intent` | `state` | `diagnostic`. */
|
|
906
|
+
declare function kindSegmentInType(type: string): EventKind | undefined;
|
|
907
|
+
declare function familyPatternForType(type: string): string;
|
|
908
|
+
declare function defineIntent(type: string, schema: PayloadSchema): DefineContractResult;
|
|
909
|
+
declare function defineStateEvent(type: string, schema: PayloadSchema): DefineContractResult;
|
|
910
|
+
declare function defineDiagnostic(type: string, schema: PayloadSchema): DefineContractResult;
|
|
911
|
+
declare function comparePayloadSchemas(from: PayloadSchema, to: PayloadSchema): SchemaCompatibility;
|
|
912
|
+
declare function deriveAttachOptions(contracts: EventContract[], role: 'cart' | 'authoritative'): AttachOptions;
|
|
913
|
+
declare function verifyAttachOptions(options: AttachOptions, contracts: EventContract[]): {
|
|
914
|
+
ok: true;
|
|
915
|
+
} | {
|
|
916
|
+
ok: false;
|
|
917
|
+
errors: ContractDiagnostic[];
|
|
918
|
+
};
|
|
919
|
+
type ContractRegistry = {
|
|
920
|
+
get(type: string): EventContract | undefined;
|
|
921
|
+
manifest(): EventContractManifest[];
|
|
922
|
+
validateEnvelope(event: EventEnvelope): PayloadValidation;
|
|
923
|
+
asRouterValidate(event: EventEnvelope): ValidateResult;
|
|
924
|
+
};
|
|
925
|
+
declare function createContractRegistry(contracts: EventContract[]): ContractRegistry;
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* Copyright (c) 2026 Aaron Boyarsky
|
|
929
|
+
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
930
|
+
* See packages/engine/LICENSE
|
|
931
|
+
*
|
|
932
|
+
* Versioned presentation-adapter contract. Hosts own canonical state and
|
|
933
|
+
* push a render model; Cyberart presents it and emits interaction intents.
|
|
934
|
+
* Adventure Kit concepts stay in the host.
|
|
935
|
+
*/
|
|
936
|
+
|
|
937
|
+
declare const PRESENTATION_ADAPTER_VERSION: 1;
|
|
938
|
+
/** Host → cart render model. Kind is `state`. */
|
|
939
|
+
declare const PRESENTATION_MODEL_EVENT = "presentation.state.model";
|
|
940
|
+
/**
|
|
941
|
+
* Cart → host when a model cannot be presented. Kind is `intent` so a
|
|
942
|
+
* non-authoritative cart can emit it through the router.
|
|
943
|
+
*/
|
|
944
|
+
declare const PRESENTATION_UNSUPPORTED_EVENT = "presentation.intent.unsupported";
|
|
945
|
+
declare const PRESENTATION_PHASES: readonly ["loading", "ready", "error", "unsupported"];
|
|
946
|
+
type PresentationPhase = (typeof PRESENTATION_PHASES)[number];
|
|
947
|
+
/**
|
|
948
|
+
* Recommended router `subscribe` for a presentation cart. Intent type names
|
|
949
|
+
* are host-owned (`adventure.intent.*`); do not put domain objects in `target`.
|
|
950
|
+
*/
|
|
951
|
+
declare const PRESENTATION_SUBSCRIBE_PATTERNS: readonly ["presentation.state.*", "cyberart.diagnostic.rejected"];
|
|
952
|
+
declare const INVALID_PRESENTATION_MODEL_MESSAGE = "Presentation adapter: model is invalid or not JSON-serializable";
|
|
953
|
+
type PresentationRegion = {
|
|
954
|
+
id: string;
|
|
955
|
+
/** Drawing-space pixels — same space as `PointerManager` / harness `click`. */
|
|
956
|
+
x: number;
|
|
957
|
+
y: number;
|
|
958
|
+
width: number;
|
|
959
|
+
height: number;
|
|
960
|
+
/** Emitted on click while `phase === 'ready'`. Prefer `*.intent.*` type names. */
|
|
961
|
+
intent: EventInput;
|
|
962
|
+
};
|
|
963
|
+
type PresentationView = {
|
|
964
|
+
background?: string;
|
|
965
|
+
title?: string;
|
|
966
|
+
regions?: readonly PresentationRegion[];
|
|
967
|
+
};
|
|
968
|
+
type PresentationModel<TView = PresentationView> = {
|
|
969
|
+
contractVersion: typeof PRESENTATION_ADAPTER_VERSION;
|
|
970
|
+
phase: PresentationPhase;
|
|
971
|
+
/** Host-owned render model. The engine does not interpret domain fields. */
|
|
972
|
+
view?: TView;
|
|
973
|
+
/** Machine-readable when `phase` is `loading` | `error` | `unsupported`. */
|
|
974
|
+
reason?: string;
|
|
975
|
+
};
|
|
976
|
+
type PresentationCartState<TView = PresentationView> = {
|
|
977
|
+
model: PresentationModel<TView>;
|
|
978
|
+
};
|
|
979
|
+
type PresentationAdapterTarget = {
|
|
980
|
+
dispatch(event: HostEvent): void;
|
|
981
|
+
start(): Promise<void>;
|
|
982
|
+
pause(): void;
|
|
983
|
+
resume(): void;
|
|
984
|
+
destroy(): void;
|
|
985
|
+
readonly paused?: boolean;
|
|
986
|
+
};
|
|
987
|
+
type PresentationAdapter<TView = PresentationView, TTarget extends PresentationAdapterTarget = PresentationAdapterTarget> = {
|
|
988
|
+
readonly version: typeof PRESENTATION_ADAPTER_VERSION;
|
|
989
|
+
readonly target: TTarget;
|
|
990
|
+
/** Last model this session presented (or the boot model). A copy — mutating it does not update the cart. */
|
|
991
|
+
readonly model: PresentationModel<TView>;
|
|
992
|
+
readonly phase: PresentationPhase;
|
|
993
|
+
readonly paused: boolean;
|
|
994
|
+
present(model: PresentationModel<TView>): void;
|
|
995
|
+
start(): Promise<void>;
|
|
996
|
+
pause(): void;
|
|
997
|
+
resume(): void;
|
|
998
|
+
/** Point at a new handle after `runtime.mount` / `harness.remount`. */
|
|
999
|
+
retarget(target: TTarget): void;
|
|
1000
|
+
destroy(): void;
|
|
1001
|
+
};
|
|
1002
|
+
type AttachPresentationAdapterOptions<TView = PresentationView> = {
|
|
1003
|
+
model?: PresentationModel<TView>;
|
|
1004
|
+
/**
|
|
1005
|
+
* Dispatch `model` onto the mailbox. Default `true` when `model` is set,
|
|
1006
|
+
* `false` otherwise (leave the cart's current state alone).
|
|
1007
|
+
*/
|
|
1008
|
+
present?: boolean;
|
|
1009
|
+
};
|
|
1010
|
+
type MountPresentationAdapterOptions<TView = PresentationView> = {
|
|
1011
|
+
cart?: AnimationCart<PresentationCartState<TView>>;
|
|
1012
|
+
onEvent?: HostEventListener;
|
|
1013
|
+
model?: PresentationModel<TView>;
|
|
1014
|
+
initialState?: MountOptions<PresentationCartState<TView>>['initialState'];
|
|
1015
|
+
};
|
|
1016
|
+
declare function isPresentationPhase(value: unknown): value is PresentationPhase;
|
|
1017
|
+
declare function isPresentationModel(value: unknown): value is PresentationModel;
|
|
1018
|
+
declare function createPresentationModelEvent<TView = PresentationView>(model: PresentationModel<TView>, extras?: Pick<EventInput, 'correlationId' | 'causationId' | 'idempotencyKey'>): EventInput;
|
|
1019
|
+
/**
|
|
1020
|
+
* Minimal presentation cart. Hit-tests `view.regions` while `phase === 'ready'`.
|
|
1021
|
+
* Hosts with a custom view shape may pass their own cart to `mountPresentationAdapter`.
|
|
1022
|
+
* `title` is inspectable state; only `background` is painted.
|
|
1023
|
+
*/
|
|
1024
|
+
declare function createReferencePresentationCart<TView = PresentationView>(): AnimationCart<PresentationCartState<TView>>;
|
|
1025
|
+
declare function attachPresentationAdapter<TView = PresentationView, TTarget extends PresentationAdapterTarget = PresentationAdapterTarget>(target: TTarget, options?: AttachPresentationAdapterOptions<TView>): PresentationAdapter<TView, TTarget>;
|
|
1026
|
+
/** Mount a presentation cart and return the host-facing adapter. */
|
|
1027
|
+
declare function mountPresentationAdapter<TView = PresentationView>(runtime: CyberArtRuntime, options?: MountPresentationAdapterOptions<TView>): PresentationAdapter<TView, CartHandle>;
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Copyright (c) 2026 Aaron Boyarsky
|
|
1031
|
+
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
1032
|
+
* See packages/engine/LICENSE
|
|
1033
|
+
*
|
|
1034
|
+
* Deterministic presentation cue / timeline. Carts step this with a frame
|
|
1035
|
+
* index; there are no wall-clock timers. Lifecycle event type names are
|
|
1036
|
+
* stable for later contract registries.
|
|
1037
|
+
*/
|
|
1038
|
+
declare const CUE_STARTED_EVENT: "cue.started";
|
|
1039
|
+
declare const CUE_COMPLETED_EVENT: "cue.completed";
|
|
1040
|
+
declare const CUE_CANCELLED_EVENT: "cue.cancelled";
|
|
1041
|
+
declare const CUE_REPLACED_EVENT: "cue.replaced";
|
|
1042
|
+
declare const CUE_LIFECYCLE_EVENTS: readonly ["cue.started", "cue.completed", "cue.cancelled", "cue.replaced"];
|
|
1043
|
+
type CueLifecycleType = (typeof CUE_LIFECYCLE_EVENTS)[number];
|
|
1044
|
+
type CueEasing = 'linear' | 'ease-out';
|
|
1045
|
+
type CueDuplicatePolicy = 'ignore' | 'replace' | 'reject';
|
|
1046
|
+
type CueRepeatPolicy = {
|
|
1047
|
+
count: number;
|
|
1048
|
+
} | {
|
|
1049
|
+
forever: true;
|
|
1050
|
+
};
|
|
1051
|
+
type CueReducedMotionPolicy = 'skip' | 'complete' | {
|
|
1052
|
+
durationFrames: number;
|
|
1053
|
+
};
|
|
1054
|
+
type CueSpec = {
|
|
1055
|
+
name: string;
|
|
1056
|
+
idempotencyKey: string;
|
|
1057
|
+
/** Frame when the cue is eligible to start (before delay). Default: play frame. */
|
|
1058
|
+
startFrame?: number;
|
|
1059
|
+
durationFrames: number;
|
|
1060
|
+
delayFrames?: number;
|
|
1061
|
+
easing?: CueEasing;
|
|
1062
|
+
repeat?: CueRepeatPolicy;
|
|
1063
|
+
/**
|
|
1064
|
+
* When the timeline is in reduced-motion mode: skip (complete immediately),
|
|
1065
|
+
* complete (same), or a shorter duration. Default `complete`.
|
|
1066
|
+
*/
|
|
1067
|
+
reducedMotion?: CueReducedMotionPolicy;
|
|
1068
|
+
onDuplicate?: CueDuplicatePolicy;
|
|
1069
|
+
};
|
|
1070
|
+
type CuePhase = 'scheduled' | 'active' | 'completed' | 'cancelled';
|
|
1071
|
+
type CueView = {
|
|
1072
|
+
name: string;
|
|
1073
|
+
idempotencyKey: string;
|
|
1074
|
+
phase: CuePhase;
|
|
1075
|
+
startFrame: number;
|
|
1076
|
+
durationFrames: number;
|
|
1077
|
+
delayFrames: number;
|
|
1078
|
+
easing: CueEasing;
|
|
1079
|
+
progress: number;
|
|
1080
|
+
repeatIndex: number;
|
|
1081
|
+
};
|
|
1082
|
+
type CueLifecycleEvent = {
|
|
1083
|
+
type: CueLifecycleType;
|
|
1084
|
+
atFrame: number;
|
|
1085
|
+
name: string;
|
|
1086
|
+
idempotencyKey: string;
|
|
1087
|
+
progress: number;
|
|
1088
|
+
};
|
|
1089
|
+
type CueTimelineSnapshot = {
|
|
1090
|
+
frame: number;
|
|
1091
|
+
reducedMotion: boolean;
|
|
1092
|
+
cues: CueView[];
|
|
1093
|
+
events: CueLifecycleEvent[];
|
|
1094
|
+
};
|
|
1095
|
+
type PlayCueResult = {
|
|
1096
|
+
ok: true;
|
|
1097
|
+
cue: CueView;
|
|
1098
|
+
} | {
|
|
1099
|
+
ok: false;
|
|
1100
|
+
reason: 'duplicate' | 'invalid';
|
|
1101
|
+
detail: string;
|
|
1102
|
+
};
|
|
1103
|
+
type CreatePresentationTimelineOptions = {
|
|
1104
|
+
/** Host-controlled reduced-motion / reduced-sensory flag. Not a CSS query. */
|
|
1105
|
+
reducedMotion?: boolean;
|
|
1106
|
+
originFrame?: number;
|
|
1107
|
+
};
|
|
1108
|
+
type PresentationTimeline = {
|
|
1109
|
+
play(spec: CueSpec): PlayCueResult;
|
|
1110
|
+
step(frames?: number): CueLifecycleEvent[];
|
|
1111
|
+
cancel(idempotencyKey: string): boolean;
|
|
1112
|
+
reset(): void;
|
|
1113
|
+
snapshot(): CueTimelineSnapshot;
|
|
1114
|
+
get(idempotencyKey: string): CueView | undefined;
|
|
1115
|
+
readonly frame: number;
|
|
1116
|
+
readonly reducedMotion: boolean;
|
|
1117
|
+
};
|
|
1118
|
+
declare function isCueLifecycleType(value: unknown): value is CueLifecycleType;
|
|
1119
|
+
declare function applyCueEasing(t: number, easing: CueEasing): number;
|
|
1120
|
+
declare function createPresentationTimeline(options?: CreatePresentationTimelineOptions): PresentationTimeline;
|
|
1121
|
+
|
|
1122
|
+
export { ASSET_FAILED_EVENT, ASSET_FAILURE_CODES, ASSET_KINDS, ASSET_READY_EVENT, type AnimationCart, type AnimationTiming, type AppliedAction, type AssetCorsMode, type AssetDeclaration, type AssetFailure, type AssetFailureCode, type AssetItemStatus, type AssetKind, type AssetPreloadSnapshot, type AssetPreloader, type AssetProvenance, type AssetResolveRequest, type AssetResolver, type AssetRuntimeOptions, type AttachOptions, type AttachPresentationAdapterOptions, type AudioLibraryId, type AudioLibrarySpec, CUE_CANCELLED_EVENT, CUE_COMPLETED_EVENT, CUE_LIFECYCLE_EVENTS, CUE_REPLACED_EVENT, CUE_STARTED_EVENT, CYBERART_CANVAS_ATTR, type CartHandle, type CartSnapshot, type CartStateBundle, type CartStateHotkeyOptions, type CartStateMessageHandler, type CartStatePersister, type Clock, type ClockSnapshot, type ContractDiagnostic, type ContractFieldType, type ContractRegistry, type CreateAssetPreloaderOptions, type CreatePresentationTimelineOptions, type CreateRuntimeOptions, type CueDuplicatePolicy, type CueEasing, type CueLifecycleEvent, type CueLifecycleType, type CuePhase, type CueReducedMotionPolicy, type CueRepeatPolicy, type CueSpec, type CueTimelineSnapshot, type CueView, type CyberArtRuntime, DEFAULT_MAX_HOPS, type DefineContractResult, type DeterministicRuntimeOptions, type DimensionContext, EVENT_ENVELOPE_VERSION, type EventContract, type EventContractManifest, type EventEnvelope, type EventInput, type EventKind, type EventRouter, type EventRouterOptions, type FixtureAssetCatalog, type FixtureAssetRecord, type FrameErrorInfo, HostChannel, type HostEvent, type HostEventListener, type HostedAssetResolverOptions, INVALID_PRESENTATION_MODEL_MESSAGE, type ImportCartStateExtras, IncompatibleCartStateError, type InferredPayload, KeyboardManager, type MountOptions, type MountPresentationAdapterOptions, type NormalizeContext, type NormalizeResult, PRESENTATION_ADAPTER_VERSION, PRESENTATION_MODEL_EVENT, PRESENTATION_PHASES, PRESENTATION_SUBSCRIBE_PATTERNS, PRESENTATION_UNSUPPORTED_EVENT, type PayloadFieldSpec, type PayloadSchema, type PayloadValidation, type PlayCueResult, type PointerClick, PointerManager, type PresentationAdapter, type PresentationAdapterTarget, type PresentationCartState, type PresentationModel, type PresentationPhase, type PresentationRegion, type PresentationTimeline, type PresentationView, type PublishExtras, REJECTED_EVENT_TYPE, Random, type RandomState, type RejectionPayload, type RejectionReason, type ReplayMetadata, type ResolvedAsset, SILENT_ASSET_FALLBACK_REF, type SchemaCompatibility, type ScriptedAction, type TokenData, type ValidateResult, type VirtualClock, applyCueEasing, assetStatusEvent, attachCartStatePersistence, attachPresentationAdapter, canonicalizeSeed, comparePayloadSchemas, createAssetFailure, createAssetPreloader, createContractRegistry, createEventRouter, createFixtureAssetResolver, createHostedAssetResolver, createPresentationModelEvent, createPresentationTimeline, createReferencePresentationCart, createRuntime, createVirtualClock, createWallClock, defineDiagnostic, defineIntent, defineStateEvent, deriveAttachOptions, describeReplayMismatch, familyPatternForType, inferEventKind, isAssetFailure, isAssetFailureCode, isAssetKind, isCueLifecycleType, isPresentationModel, isPresentationPhase, kindSegmentInType, matchEventPattern, mountPresentationAdapter, normalizeEvent, registerCartStateHotkeys, resolveRuntimeSeed, rewriteHostedAssetRef, verifyAttachOptions };
|