@cyberart-io/engine 0.0.2 → 0.0.4
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 +200 -9
- package/dist/headless.d.ts +805 -0
- package/dist/headless.js +8 -0
- package/dist/index.d.ts +832 -64
- package/dist/index.js +1 -1
- package/docs/asset-resolver.md +155 -0
- package/docs/capability-manifest.md +84 -0
- package/docs/events.md +20 -8
- package/docs/headless-harness.md +58 -16
- package/docs/normalized-geometry.md +88 -0
- package/docs/presentation-adapter.md +150 -0
- package/docs/presentation-cue.md +82 -0
- package/docs/runtime-group.md +120 -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,660 @@ 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
|
+
/**
|
|
1123
|
+
* Copyright (c) 2026 Aaron Boyarsky
|
|
1124
|
+
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
1125
|
+
* See packages/engine/LICENSE
|
|
1126
|
+
*
|
|
1127
|
+
* Versioned, JSON-serializable capability manifest for a cart/module.
|
|
1128
|
+
* Definition, parse, and host validation all return structured diagnostics
|
|
1129
|
+
* instead of throwing.
|
|
1130
|
+
*/
|
|
1131
|
+
declare const CAPABILITY_MANIFEST_VERSION: 1;
|
|
1132
|
+
declare const CAPABILITY_PHASES: readonly ["loading", "ready", "error", "unsupported"];
|
|
1133
|
+
type CapabilityPhase = (typeof CAPABILITY_PHASES)[number];
|
|
1134
|
+
declare const CAPABILITY_MANAGERS: readonly ["keyboard", "pointer", "audio", "assets", "hostChannel"];
|
|
1135
|
+
type CapabilityManager = (typeof CAPABILITY_MANAGERS)[number];
|
|
1136
|
+
declare const CAPABILITY_ASSET_KINDS: readonly ["image", "audio", "font", "spritesheet"];
|
|
1137
|
+
type CapabilityAssetKind = (typeof CAPABILITY_ASSET_KINDS)[number];
|
|
1138
|
+
declare const CAPABILITY_INTEGRATIONS: readonly ["tone", "midi"];
|
|
1139
|
+
type CapabilityIntegration = (typeof CAPABILITY_INTEGRATIONS)[number];
|
|
1140
|
+
type CapabilityDiagnostic = {
|
|
1141
|
+
code: string;
|
|
1142
|
+
detail: string;
|
|
1143
|
+
path?: string;
|
|
1144
|
+
};
|
|
1145
|
+
type CapabilityRuntime = {
|
|
1146
|
+
minContractVersion: number;
|
|
1147
|
+
features: string[];
|
|
1148
|
+
};
|
|
1149
|
+
type CapabilityAssetDeclarationSummary = {
|
|
1150
|
+
id: string;
|
|
1151
|
+
kind: CapabilityAssetKind;
|
|
1152
|
+
};
|
|
1153
|
+
type CapabilityAssetSummary = {
|
|
1154
|
+
kinds: CapabilityAssetKind[];
|
|
1155
|
+
declarations: CapabilityAssetDeclarationSummary[];
|
|
1156
|
+
};
|
|
1157
|
+
type CapabilityPermissions = {
|
|
1158
|
+
emit: string[];
|
|
1159
|
+
subscribe: string[];
|
|
1160
|
+
authoritative?: boolean;
|
|
1161
|
+
};
|
|
1162
|
+
type CapabilityManifest = {
|
|
1163
|
+
version: typeof CAPABILITY_MANIFEST_VERSION;
|
|
1164
|
+
id: string;
|
|
1165
|
+
runtime: CapabilityRuntime;
|
|
1166
|
+
phases: CapabilityPhase[];
|
|
1167
|
+
managers: CapabilityManager[];
|
|
1168
|
+
assets: CapabilityAssetSummary;
|
|
1169
|
+
acceptedEvents: string[];
|
|
1170
|
+
emittedEvents: string[];
|
|
1171
|
+
permissions: CapabilityPermissions;
|
|
1172
|
+
integrations: CapabilityIntegration[];
|
|
1173
|
+
};
|
|
1174
|
+
type CapabilityManifestInput = {
|
|
1175
|
+
version?: number;
|
|
1176
|
+
id: string;
|
|
1177
|
+
runtime: CapabilityRuntime;
|
|
1178
|
+
phases: CapabilityPhase[];
|
|
1179
|
+
managers: CapabilityManager[];
|
|
1180
|
+
assets: CapabilityAssetSummary;
|
|
1181
|
+
acceptedEvents: string[];
|
|
1182
|
+
emittedEvents: string[];
|
|
1183
|
+
permissions: CapabilityPermissions;
|
|
1184
|
+
integrations: CapabilityIntegration[];
|
|
1185
|
+
};
|
|
1186
|
+
type HostCapabilities = {
|
|
1187
|
+
contractVersion: number;
|
|
1188
|
+
features: string[];
|
|
1189
|
+
integrations: CapabilityIntegration[];
|
|
1190
|
+
managers?: CapabilityManager[];
|
|
1191
|
+
emit?: string[];
|
|
1192
|
+
subscribe?: string[];
|
|
1193
|
+
};
|
|
1194
|
+
type DefineCapabilityManifestResult = {
|
|
1195
|
+
ok: true;
|
|
1196
|
+
manifest: CapabilityManifest;
|
|
1197
|
+
} | {
|
|
1198
|
+
ok: false;
|
|
1199
|
+
errors: CapabilityDiagnostic[];
|
|
1200
|
+
};
|
|
1201
|
+
type ValidateCapabilityManifestResult = {
|
|
1202
|
+
ok: true;
|
|
1203
|
+
} | {
|
|
1204
|
+
ok: false;
|
|
1205
|
+
errors: CapabilityDiagnostic[];
|
|
1206
|
+
};
|
|
1207
|
+
declare function defineCapabilityManifest(input: unknown): DefineCapabilityManifestResult;
|
|
1208
|
+
declare function parseCapabilityManifest(json: string | unknown): DefineCapabilityManifestResult;
|
|
1209
|
+
declare function toJSON(manifest: CapabilityManifest): CapabilityManifest;
|
|
1210
|
+
declare function validateCapabilityManifest(manifest: CapabilityManifest, hostCapabilities: HostCapabilities): ValidateCapabilityManifestResult;
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Copyright (c) 2026 Aaron Boyarsky
|
|
1214
|
+
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
1215
|
+
* See packages/engine/LICENSE
|
|
1216
|
+
*
|
|
1217
|
+
* Shared normalized coordinate, anchor, and hit-region contract. Hosts and
|
|
1218
|
+
* adapters may adopt this later; pixel `PresentationRegion` is unchanged.
|
|
1219
|
+
*
|
|
1220
|
+
* Coordinate spaces:
|
|
1221
|
+
* - `normalized` — 0–1 of the **content** box (full intrinsic artwork, not letterbox).
|
|
1222
|
+
* - `asset` — intrinsic content pixels (`contentWidth` × `contentHeight`).
|
|
1223
|
+
* - `css` / `viewport` — layout pixels (`viewportWidth` × `viewportHeight`).
|
|
1224
|
+
* - `canvas` — drawing-buffer pixels (`css * devicePixelRatio`). Pointers match
|
|
1225
|
+
* `PointerManager` / harness `click` when the buffer is the drawing canvas.
|
|
1226
|
+
*
|
|
1227
|
+
* Pointer helpers default to **canvas** space. Pass `{ space: 'css' }` for
|
|
1228
|
+
* layout pixels. Round-trip: `ROUND_TRIP_TOLERANCE` (1e-6 normalized) or
|
|
1229
|
+
* `ROUND_TRIP_TOLERANCE_CANVAS_PX` (0.5 canvas px).
|
|
1230
|
+
*/
|
|
1231
|
+
declare const GEOMETRY_CONTRACT_VERSION: 1;
|
|
1232
|
+
/** Maximum |Δ| in normalized units after canvas/css round-trip. */
|
|
1233
|
+
declare const ROUND_TRIP_TOLERANCE = 0.000001;
|
|
1234
|
+
/** Maximum |Δ| in canvas pixels after normalized round-trip. */
|
|
1235
|
+
declare const ROUND_TRIP_TOLERANCE_CANVAS_PX = 0.5;
|
|
1236
|
+
declare const COORDINATE_SPACES: readonly ["normalized", "asset", "canvas", "css", "viewport"];
|
|
1237
|
+
type CoordinateSpace = (typeof COORDINATE_SPACES)[number];
|
|
1238
|
+
type PointerSpace = 'canvas' | 'css';
|
|
1239
|
+
type PresentationFitMode = 'contain' | 'cover' | 'crop';
|
|
1240
|
+
declare const ANCHOR_ORIGINS: readonly ["center", "top-left", "top-right", "bottom-left", "bottom-right", "top", "bottom", "left", "right"];
|
|
1241
|
+
type AnchorOrigin = (typeof ANCHOR_ORIGINS)[number];
|
|
1242
|
+
type NormalizedPoint = {
|
|
1243
|
+
x: number;
|
|
1244
|
+
y: number;
|
|
1245
|
+
};
|
|
1246
|
+
type NormalizedRect = {
|
|
1247
|
+
x: number;
|
|
1248
|
+
y: number;
|
|
1249
|
+
width: number;
|
|
1250
|
+
height: number;
|
|
1251
|
+
};
|
|
1252
|
+
type NormalizedPolygon = readonly NormalizedPoint[];
|
|
1253
|
+
type PixelPoint = {
|
|
1254
|
+
x: number;
|
|
1255
|
+
y: number;
|
|
1256
|
+
};
|
|
1257
|
+
type PixelRect = {
|
|
1258
|
+
x: number;
|
|
1259
|
+
y: number;
|
|
1260
|
+
width: number;
|
|
1261
|
+
height: number;
|
|
1262
|
+
};
|
|
1263
|
+
type GeometryPadding = {
|
|
1264
|
+
top: number;
|
|
1265
|
+
right: number;
|
|
1266
|
+
bottom: number;
|
|
1267
|
+
left: number;
|
|
1268
|
+
};
|
|
1269
|
+
/** Insets from the content edges in normalized units (0–1). */
|
|
1270
|
+
type GeometrySafeArea = GeometryPadding;
|
|
1271
|
+
type GeometryAnchor = {
|
|
1272
|
+
id: string;
|
|
1273
|
+
point: NormalizedPoint;
|
|
1274
|
+
origin?: AnchorOrigin;
|
|
1275
|
+
};
|
|
1276
|
+
type GeometryHitbox = {
|
|
1277
|
+
id: string;
|
|
1278
|
+
rect?: NormalizedRect;
|
|
1279
|
+
polygon?: NormalizedPolygon;
|
|
1280
|
+
};
|
|
1281
|
+
type GeometryDocument = {
|
|
1282
|
+
version: typeof GEOMETRY_CONTRACT_VERSION;
|
|
1283
|
+
landmarks: GeometryAnchor[];
|
|
1284
|
+
regions: GeometryHitbox[];
|
|
1285
|
+
padding?: GeometryPadding;
|
|
1286
|
+
safeArea?: GeometrySafeArea;
|
|
1287
|
+
};
|
|
1288
|
+
type CreatePresentationLayoutInput = {
|
|
1289
|
+
contentWidth: number;
|
|
1290
|
+
contentHeight: number;
|
|
1291
|
+
viewportWidth: number;
|
|
1292
|
+
viewportHeight: number;
|
|
1293
|
+
mode: PresentationFitMode;
|
|
1294
|
+
/** Canvas buffer pixels per CSS pixel. Default 1. */
|
|
1295
|
+
devicePixelRatio?: number;
|
|
1296
|
+
};
|
|
1297
|
+
type PresentationLayout = {
|
|
1298
|
+
mode: PresentationFitMode;
|
|
1299
|
+
contentWidth: number;
|
|
1300
|
+
contentHeight: number;
|
|
1301
|
+
viewportWidth: number;
|
|
1302
|
+
viewportHeight: number;
|
|
1303
|
+
devicePixelRatio: number;
|
|
1304
|
+
/** Content → CSS pixels. */
|
|
1305
|
+
scale: number;
|
|
1306
|
+
/** Letterbox (positive) or crop (negative) offset of content origin in CSS. */
|
|
1307
|
+
offsetX: number;
|
|
1308
|
+
offsetY: number;
|
|
1309
|
+
canvasWidth: number;
|
|
1310
|
+
canvasHeight: number;
|
|
1311
|
+
/** Visible slice of the content box in normalized space. */
|
|
1312
|
+
visibleNormalizedRect: NormalizedRect;
|
|
1313
|
+
};
|
|
1314
|
+
type GeometryDiagnostic = {
|
|
1315
|
+
code: 'out-of-bounds' | 'overlap' | 'duplicate-id' | 'invalid-shape' | 'version-mismatch';
|
|
1316
|
+
id?: string;
|
|
1317
|
+
detail: string;
|
|
1318
|
+
with?: string;
|
|
1319
|
+
};
|
|
1320
|
+
type GeometryValidation = {
|
|
1321
|
+
ok: boolean;
|
|
1322
|
+
diagnostics: GeometryDiagnostic[];
|
|
1323
|
+
};
|
|
1324
|
+
type LandmarkRegisterResult = {
|
|
1325
|
+
ok: true;
|
|
1326
|
+
landmark: GeometryAnchor;
|
|
1327
|
+
} | {
|
|
1328
|
+
ok: false;
|
|
1329
|
+
error: 'duplicate-id';
|
|
1330
|
+
id: string;
|
|
1331
|
+
};
|
|
1332
|
+
type LandmarkRegistry = {
|
|
1333
|
+
register(landmark: GeometryAnchor): LandmarkRegisterResult;
|
|
1334
|
+
get(id: string): GeometryAnchor | undefined;
|
|
1335
|
+
list(): GeometryAnchor[];
|
|
1336
|
+
};
|
|
1337
|
+
type DebugDrawCall = {
|
|
1338
|
+
method: string;
|
|
1339
|
+
id?: string;
|
|
1340
|
+
args: unknown[];
|
|
1341
|
+
};
|
|
1342
|
+
type GeometryDebugContext = {
|
|
1343
|
+
fillStyle?: string;
|
|
1344
|
+
strokeStyle?: string;
|
|
1345
|
+
font?: string;
|
|
1346
|
+
fillRect?(x: number, y: number, w: number, h: number): void;
|
|
1347
|
+
strokeRect?(x: number, y: number, w: number, h: number): void;
|
|
1348
|
+
fillText?(text: string, x: number, y: number): void;
|
|
1349
|
+
beginPath?(): void;
|
|
1350
|
+
moveTo?(x: number, y: number): void;
|
|
1351
|
+
lineTo?(x: number, y: number): void;
|
|
1352
|
+
closePath?(): void;
|
|
1353
|
+
stroke?(): void;
|
|
1354
|
+
fill?(): void;
|
|
1355
|
+
};
|
|
1356
|
+
declare function pointFromOrigin(origin: AnchorOrigin): NormalizedPoint;
|
|
1357
|
+
declare function createPresentationLayout(input: CreatePresentationLayoutInput): PresentationLayout;
|
|
1358
|
+
declare function normalizedToAsset(point: NormalizedPoint, layout: PresentationLayout): PixelPoint;
|
|
1359
|
+
declare function assetToNormalized(point: PixelPoint, layout: PresentationLayout): NormalizedPoint;
|
|
1360
|
+
declare function normalizedToCss(point: NormalizedPoint, layout: PresentationLayout): PixelPoint;
|
|
1361
|
+
declare function cssToNormalized(point: PixelPoint, layout: PresentationLayout): NormalizedPoint;
|
|
1362
|
+
declare function cssToCanvas(point: PixelPoint, layout: PresentationLayout): PixelPoint;
|
|
1363
|
+
declare function canvasToCss(point: PixelPoint, layout: PresentationLayout): PixelPoint;
|
|
1364
|
+
declare function normalizedToCanvas(point: NormalizedPoint, layout: PresentationLayout): PixelPoint;
|
|
1365
|
+
declare function canvasToNormalized(point: PixelPoint, layout: PresentationLayout): NormalizedPoint;
|
|
1366
|
+
declare function rectToCss(rect: NormalizedRect, layout: PresentationLayout): PixelRect;
|
|
1367
|
+
declare function rectToCanvas(rect: NormalizedRect, layout: PresentationLayout): PixelRect;
|
|
1368
|
+
/**
|
|
1369
|
+
* Pointer is in **canvas** pixels unless `{ space: 'css' }` is passed.
|
|
1370
|
+
* Returns the first region whose rect or polygon contains the point, in
|
|
1371
|
+
* document order.
|
|
1372
|
+
*/
|
|
1373
|
+
declare function pointerToRegion(pointer: PixelPoint, layout: PresentationLayout, doc: GeometryDocument, options?: {
|
|
1374
|
+
space?: PointerSpace;
|
|
1375
|
+
}): GeometryHitbox | undefined;
|
|
1376
|
+
/** Visible CSS (viewport) rectangle for a region; polygons use their AABB. */
|
|
1377
|
+
declare function regionToViewport(region: GeometryHitbox, layout: PresentationLayout): PixelRect | undefined;
|
|
1378
|
+
declare function createLandmarkRegistry(initial?: readonly GeometryAnchor[]): LandmarkRegistry;
|
|
1379
|
+
declare function validateGeometry(doc: GeometryDocument): GeometryValidation;
|
|
1380
|
+
/**
|
|
1381
|
+
* Draws labeled region rects and reports validation failures as extra labels.
|
|
1382
|
+
* Tests may pass a stub that records `fillRect` / `strokeRect` / `fillText`.
|
|
1383
|
+
*/
|
|
1384
|
+
declare function drawGeometryDebug(ctx: GeometryDebugContext, layout: PresentationLayout, doc: GeometryDocument, diagnostics?: readonly GeometryDiagnostic[]): DebugDrawCall[];
|
|
1385
|
+
declare function serializeGeometry(doc: GeometryDocument): string;
|
|
1386
|
+
declare function parseGeometry(json: string): GeometryDocument;
|
|
1387
|
+
|
|
1388
|
+
/**
|
|
1389
|
+
* Copyright (c) 2026 Aaron Boyarsky
|
|
1390
|
+
* SPDX-License-Identifier: LicenseRef-CyberArt-Engine
|
|
1391
|
+
* See packages/engine/LICENSE
|
|
1392
|
+
*
|
|
1393
|
+
* First-class multi-cart runtime group. Creates production `createRuntime`
|
|
1394
|
+
* instances, attaches each mailbox to one shared `createEventRouter`, and
|
|
1395
|
+
* locksteps a deterministic clock. Carts never receive the router object.
|
|
1396
|
+
*/
|
|
1397
|
+
|
|
1398
|
+
declare const DEFAULT_GROUP_WIDTH = 320;
|
|
1399
|
+
declare const DEFAULT_GROUP_HEIGHT = 180;
|
|
1400
|
+
type RuntimeGroupKind = 'render' | 'calculation';
|
|
1401
|
+
/**
|
|
1402
|
+
* Optional capability-shaped attach hints. Explicit participant `emit` /
|
|
1403
|
+
* `subscribe` / `authoritative` win. Do not import the capability manifest
|
|
1404
|
+
* module from this file.
|
|
1405
|
+
*/
|
|
1406
|
+
type RuntimeGroupCapability = {
|
|
1407
|
+
emit?: string[];
|
|
1408
|
+
subscribe?: string[];
|
|
1409
|
+
authoritative?: boolean;
|
|
1410
|
+
};
|
|
1411
|
+
type RuntimeGroupFrameError = {
|
|
1412
|
+
error: unknown;
|
|
1413
|
+
info: FrameErrorInfo;
|
|
1414
|
+
};
|
|
1415
|
+
type RuntimeGroupParticipantConfig<T = unknown> = {
|
|
1416
|
+
id: string;
|
|
1417
|
+
cart: AnimationCart<T>;
|
|
1418
|
+
/** Rendered surface vs calculation cart (still a real `AnimationCart`). */
|
|
1419
|
+
kind?: RuntimeGroupKind;
|
|
1420
|
+
seed?: CreateRuntimeOptions['seed'];
|
|
1421
|
+
container?: HTMLElement;
|
|
1422
|
+
width?: number;
|
|
1423
|
+
height?: number;
|
|
1424
|
+
initialState?: Partial<T>;
|
|
1425
|
+
gameManager?: unknown;
|
|
1426
|
+
onEvent?: HostEventListener;
|
|
1427
|
+
emit?: string[];
|
|
1428
|
+
subscribe?: string[];
|
|
1429
|
+
authoritative?: boolean;
|
|
1430
|
+
capability?: RuntimeGroupCapability;
|
|
1431
|
+
};
|
|
1432
|
+
type CreateRuntimeGroupOptions = {
|
|
1433
|
+
participants: RuntimeGroupParticipantConfig[];
|
|
1434
|
+
/** Shared virtual-clock origin (ms). Default 0. */
|
|
1435
|
+
origin?: number;
|
|
1436
|
+
width?: number;
|
|
1437
|
+
height?: number;
|
|
1438
|
+
validate?: EventRouterOptions['validate'];
|
|
1439
|
+
createId?: () => string;
|
|
1440
|
+
now?: () => number;
|
|
1441
|
+
/** Extra router options. Group injects shared `createId` / `now` unless set here. */
|
|
1442
|
+
router?: EventRouterOptions;
|
|
1443
|
+
};
|
|
1444
|
+
type RuntimeGroupParticipantInspect = {
|
|
1445
|
+
state: unknown;
|
|
1446
|
+
events: HostEvent[];
|
|
1447
|
+
errors: RuntimeGroupFrameError[];
|
|
1448
|
+
kind: RuntimeGroupKind;
|
|
1449
|
+
clock: ClockSnapshot;
|
|
1450
|
+
};
|
|
1451
|
+
type RuntimeGroupDiagnostics = {
|
|
1452
|
+
paused: boolean;
|
|
1453
|
+
participantIds: string[];
|
|
1454
|
+
clocks: Record<string, ClockSnapshot>;
|
|
1455
|
+
rejections: unknown[];
|
|
1456
|
+
};
|
|
1457
|
+
type RuntimeGroupInspect = {
|
|
1458
|
+
participants: Record<string, RuntimeGroupParticipantInspect>;
|
|
1459
|
+
trace: EventEnvelope[];
|
|
1460
|
+
diagnostics: RuntimeGroupDiagnostics;
|
|
1461
|
+
};
|
|
1462
|
+
type RuntimeGroupParticipantHandle = {
|
|
1463
|
+
readonly id: string;
|
|
1464
|
+
readonly kind: RuntimeGroupKind;
|
|
1465
|
+
readonly runtime: CyberArtRuntime;
|
|
1466
|
+
readonly container: HTMLElement;
|
|
1467
|
+
readonly events: readonly HostEvent[];
|
|
1468
|
+
readonly errors: readonly RuntimeGroupFrameError[];
|
|
1469
|
+
get cart(): CartHandle;
|
|
1470
|
+
};
|
|
1471
|
+
type RuntimeGroup = {
|
|
1472
|
+
readonly router: EventRouter;
|
|
1473
|
+
readonly origin: number;
|
|
1474
|
+
readonly paused: boolean;
|
|
1475
|
+
participant(id: string): RuntimeGroupParticipantHandle;
|
|
1476
|
+
step(frames?: number): Promise<void>;
|
|
1477
|
+
pause(): void;
|
|
1478
|
+
resume(): void;
|
|
1479
|
+
reset(): void;
|
|
1480
|
+
dispatch(participantId: string, event: HostEvent): void;
|
|
1481
|
+
publish(event: EventInput, extras?: PublishExtras): EventEnvelope | undefined;
|
|
1482
|
+
inspect(): Promise<RuntimeGroupInspect>;
|
|
1483
|
+
destroy(): void;
|
|
1484
|
+
};
|
|
1485
|
+
declare function createRuntimeGroup(options: CreateRuntimeGroupOptions): RuntimeGroup;
|
|
1486
|
+
|
|
1487
|
+
export { ANCHOR_ORIGINS, ASSET_FAILED_EVENT, ASSET_FAILURE_CODES, ASSET_KINDS, ASSET_READY_EVENT, type AnchorOrigin, 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, CAPABILITY_ASSET_KINDS, CAPABILITY_INTEGRATIONS, CAPABILITY_MANAGERS, CAPABILITY_MANIFEST_VERSION, CAPABILITY_PHASES, COORDINATE_SPACES, CUE_CANCELLED_EVENT, CUE_COMPLETED_EVENT, CUE_LIFECYCLE_EVENTS, CUE_REPLACED_EVENT, CUE_STARTED_EVENT, CYBERART_CANVAS_ATTR, type CapabilityAssetDeclarationSummary, type CapabilityAssetKind, type CapabilityAssetSummary, type CapabilityDiagnostic, type CapabilityIntegration, type CapabilityManager, type CapabilityManifest, type CapabilityManifestInput, type CapabilityPermissions, type CapabilityPhase, type CapabilityRuntime, type CartHandle, type CartSnapshot, type CartStateBundle, type CartStateHotkeyOptions, type CartStateMessageHandler, type CartStatePersister, type Clock, type ClockSnapshot, type ContractDiagnostic, type ContractFieldType, type ContractRegistry, type CoordinateSpace, type CreateAssetPreloaderOptions, type CreatePresentationLayoutInput, type CreatePresentationTimelineOptions, type CreateRuntimeGroupOptions, 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_GROUP_HEIGHT, DEFAULT_GROUP_WIDTH, DEFAULT_MAX_HOPS, type DebugDrawCall, type DefineCapabilityManifestResult, 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, GEOMETRY_CONTRACT_VERSION, type GeometryAnchor, type GeometryDebugContext, type GeometryDiagnostic, type GeometryDocument, type GeometryHitbox, type GeometryPadding, type GeometrySafeArea, type GeometryValidation, type HostCapabilities, HostChannel, type HostEvent, type HostEventListener, type HostedAssetResolverOptions, INVALID_PRESENTATION_MODEL_MESSAGE, type ImportCartStateExtras, IncompatibleCartStateError, type InferredPayload, KeyboardManager, type LandmarkRegisterResult, type LandmarkRegistry, type MountOptions, type MountPresentationAdapterOptions, type NormalizeContext, type NormalizeResult, type NormalizedPoint, type NormalizedPolygon, type NormalizedRect, PRESENTATION_ADAPTER_VERSION, PRESENTATION_MODEL_EVENT, PRESENTATION_PHASES, PRESENTATION_SUBSCRIBE_PATTERNS, PRESENTATION_UNSUPPORTED_EVENT, type PayloadFieldSpec, type PayloadSchema, type PayloadValidation, type PixelPoint, type PixelRect, type PlayCueResult, type PointerClick, PointerManager, type PointerSpace, type PresentationAdapter, type PresentationAdapterTarget, type PresentationCartState, type PresentationFitMode, type PresentationLayout, type PresentationModel, type PresentationPhase, type PresentationRegion, type PresentationTimeline, type PresentationView, type PublishExtras, REJECTED_EVENT_TYPE, ROUND_TRIP_TOLERANCE, ROUND_TRIP_TOLERANCE_CANVAS_PX, Random, type RandomState, type RejectionPayload, type RejectionReason, type ReplayMetadata, type ResolvedAsset, type RuntimeGroup, type RuntimeGroupCapability, type RuntimeGroupDiagnostics, type RuntimeGroupFrameError, type RuntimeGroupInspect, type RuntimeGroupKind, type RuntimeGroupParticipantConfig, type RuntimeGroupParticipantHandle, type RuntimeGroupParticipantInspect, SILENT_ASSET_FALLBACK_REF, type SchemaCompatibility, type ScriptedAction, type TokenData, type ValidateCapabilityManifestResult, type ValidateResult, type VirtualClock, applyCueEasing, assetStatusEvent, assetToNormalized, attachCartStatePersistence, attachPresentationAdapter, canonicalizeSeed, canvasToCss, canvasToNormalized, toJSON as capabilityManifestToJSON, comparePayloadSchemas, createAssetFailure, createAssetPreloader, createContractRegistry, createEventRouter, createFixtureAssetResolver, createHostedAssetResolver, createLandmarkRegistry, createPresentationLayout, createPresentationModelEvent, createPresentationTimeline, createReferencePresentationCart, createRuntime, createRuntimeGroup, createVirtualClock, createWallClock, cssToCanvas, cssToNormalized, defineCapabilityManifest, defineDiagnostic, defineIntent, defineStateEvent, deriveAttachOptions, describeReplayMismatch, drawGeometryDebug, familyPatternForType, inferEventKind, isAssetFailure, isAssetFailureCode, isAssetKind, isCueLifecycleType, isPresentationModel, isPresentationPhase, kindSegmentInType, matchEventPattern, mountPresentationAdapter, normalizeEvent, normalizedToAsset, normalizedToCanvas, normalizedToCss, parseCapabilityManifest, parseGeometry, pointFromOrigin, pointerToRegion, rectToCanvas, rectToCss, regionToViewport, registerCartStateHotkeys, resolveRuntimeSeed, rewriteHostedAssetRef, serializeGeometry, validateCapabilityManifest, validateGeometry, verifyAttachOptions };
|