@forgeax/engine-app 0.1.3 → 0.1.6

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.
Files changed (145) hide show
  1. package/README.md +20 -14
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/create-app-error-retention.integration.test.d.ts +2 -0
  4. package/dist/__tests__/create-app-error-retention.integration.test.d.ts.map +1 -0
  5. package/dist/__tests__/create-app-physics-plugin-failure.integration.test.d.ts +2 -0
  6. package/dist/__tests__/create-app-physics-plugin-failure.integration.test.d.ts.map +1 -0
  7. package/dist/animation-asset-lookup.d.ts +1 -2
  8. package/dist/animation-asset-lookup.d.ts.map +1 -1
  9. package/dist/create-app.d.ts +31 -10
  10. package/dist/create-app.d.ts.map +1 -1
  11. package/dist/engine-worker-runtime.mjs +72 -129
  12. package/dist/engine-worker-runtime.mjs.map +1 -1
  13. package/dist/errors.d.ts +3 -12
  14. package/dist/errors.d.ts.map +1 -1
  15. package/dist/execution/attached-world-swap.d.ts +1 -12
  16. package/dist/execution/attached-world-swap.d.ts.map +1 -1
  17. package/dist/execution/bootstrap-url.d.ts +5 -0
  18. package/dist/execution/bootstrap-url.d.ts.map +1 -0
  19. package/dist/execution/control.d.ts +0 -2
  20. package/dist/execution/control.d.ts.map +1 -1
  21. package/dist/execution/engine-worker.d.ts +1 -0
  22. package/dist/execution/engine-worker.d.ts.map +1 -1
  23. package/dist/execution/host-controller.d.ts.map +1 -1
  24. package/dist/execution/index.d.ts +1 -1
  25. package/dist/execution/index.d.ts.map +1 -1
  26. package/dist/execution/protocol.d.ts +4 -1
  27. package/dist/execution/protocol.d.ts.map +1 -1
  28. package/dist/execution/types.d.ts +17 -1
  29. package/dist/execution/types.d.ts.map +1 -1
  30. package/dist/game-context.d.ts +1 -1
  31. package/dist/game-context.d.ts.map +1 -1
  32. package/dist/index.d.ts +4 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.mjs +332 -366
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/internal/assembled-engine-profile.d.ts.map +1 -1
  37. package/dist/internal/assets-world-plugin.d.ts +3 -17
  38. package/dist/internal/assets-world-plugin.d.ts.map +1 -1
  39. package/dist/internal/browser-remote-bridge.d.ts +1 -2
  40. package/dist/internal/browser-remote-bridge.d.ts.map +1 -1
  41. package/dist/internal/browser-rhi-debug-runtime.d.ts +1 -1
  42. package/dist/internal/browser-rhi-debug-runtime.d.ts.map +1 -1
  43. package/dist/internal/debug-draw.d.ts +9 -0
  44. package/dist/internal/debug-draw.d.ts.map +1 -0
  45. package/dist/internal/engine-profile-common.d.ts +2 -2
  46. package/dist/internal/engine-profile-common.d.ts.map +1 -1
  47. package/dist/internal/frame-loop.d.ts +7 -4
  48. package/dist/internal/frame-loop.d.ts.map +1 -1
  49. package/dist/internal/main-engine-profile.d.ts +4 -0
  50. package/dist/internal/main-engine-profile.d.ts.map +1 -1
  51. package/dist/internal/remote-serve-flag.d.ts +3 -7
  52. package/dist/internal/remote-serve-flag.d.ts.map +1 -1
  53. package/dist/internal/rhi-capture.d.ts +1 -1
  54. package/dist/internal/rhi-capture.d.ts.map +1 -1
  55. package/dist/internal/worker-engine-profile.d.ts +2 -0
  56. package/dist/internal/worker-engine-profile.d.ts.map +1 -1
  57. package/dist/renderer-plugin.d.ts +25 -0
  58. package/dist/renderer-plugin.d.ts.map +1 -0
  59. package/dist/tool-preview/bootstrap.d.ts.map +1 -1
  60. package/dist/types.d.ts +21 -61
  61. package/dist/types.d.ts.map +1 -1
  62. package/package.json +25 -26
  63. package/src/__tests__/callback-inference.test-d.ts +7 -3
  64. package/src/__tests__/consumer-migration.unit.test.ts +13 -0
  65. package/src/__tests__/create-app-error-retention.integration.test.ts +125 -0
  66. package/src/__tests__/create-app-features.test.ts +21 -10
  67. package/src/__tests__/create-app-listener-sync.test.ts +23 -19
  68. package/src/__tests__/create-app-physics-plugin-failure.integration.test.ts +142 -0
  69. package/src/__tests__/create-app-stop.test.ts +4 -12
  70. package/src/__tests__/create-app.test-d.ts +12 -11
  71. package/src/__tests__/create-app.test.ts +1 -60
  72. package/src/__tests__/create-renderer-error.integration.test.ts +3 -2
  73. package/src/__tests__/create-renderer-lifecycle.integration.test.ts +10 -5
  74. package/src/__tests__/draw-source-injected-world-update-visibility.test.ts +7 -13
  75. package/src/__tests__/draw-source-single-world-regression.test.ts +23 -24
  76. package/src/__tests__/engine-worker-bootstrap-channel.unit.test.ts +8 -0
  77. package/src/__tests__/engine-worker-world-swap.unit.test.ts +15 -22
  78. package/src/__tests__/errors-pointer-lock-failed.test.ts +4 -7
  79. package/src/__tests__/execution-bootstrap-isolation.unit.test.ts +5 -6
  80. package/src/__tests__/execution-frame-order.unit.test.ts +2 -2
  81. package/src/__tests__/execution-frame-protocol.unit.test.ts +3 -4
  82. package/src/__tests__/execution-public-api.test-d.ts +4 -0
  83. package/src/__tests__/frame-loop-time-elapsed.test.ts +1 -1
  84. package/src/__tests__/frame-loop-time.unit.test.ts +1 -1
  85. package/src/__tests__/frame-loop-world-array.test.ts +82 -73
  86. package/src/__tests__/plugin-profiles.unit.test.ts +3 -3
  87. package/src/__tests__/profiler-default-off.test.ts +1 -1
  88. package/src/__tests__/profiler-frame-token.test.ts +17 -30
  89. package/src/__tests__/profiler-phase-integration.test.ts +15 -27
  90. package/src/__tests__/surface-handoff.test.ts +1 -4
  91. package/src/__tests__/visibility-remote.integration.test.ts +2 -5
  92. package/src/__tests__/worker-execution-stop.test.ts +64 -7
  93. package/src/animation-asset-lookup.ts +2 -2
  94. package/src/create-app.ts +197 -296
  95. package/src/errors.ts +27 -39
  96. package/src/execution/attached-world-swap.ts +4 -38
  97. package/src/execution/bootstrap-url.ts +25 -0
  98. package/src/execution/control.ts +3 -7
  99. package/src/execution/engine-worker-runtime.ts +23 -40
  100. package/src/execution/engine-worker.ts +2 -0
  101. package/src/execution/host-controller.ts +8 -2
  102. package/src/execution/index.ts +1 -0
  103. package/src/execution/protocol.ts +4 -1
  104. package/src/execution/types.ts +18 -1
  105. package/src/game-context.ts +1 -1
  106. package/src/index.ts +11 -4
  107. package/src/internal/assembled-engine-profile.ts +3 -11
  108. package/src/internal/assets-world-plugin.ts +7 -53
  109. package/src/internal/browser-remote-bridge.ts +12 -10
  110. package/src/internal/browser-rhi-debug-runtime.ts +1 -1
  111. package/src/internal/debug-draw.ts +38 -0
  112. package/src/internal/engine-profile-common.ts +2 -3
  113. package/src/internal/frame-loop.ts +77 -63
  114. package/src/internal/main-engine-profile.ts +21 -17
  115. package/src/internal/remote-serve-flag.ts +5 -14
  116. package/src/internal/rhi-capture.ts +1 -1
  117. package/src/internal/worker-engine-profile.ts +10 -10
  118. package/src/renderer-plugin.ts +96 -0
  119. package/src/tool-preview/bootstrap.ts +1 -14
  120. package/src/types.ts +22 -77
  121. package/src/vite-env.d.ts +0 -2
  122. package/dist/__tests__/app-rebuild.test.d.ts +0 -2
  123. package/dist/__tests__/app-rebuild.test.d.ts.map +0 -1
  124. package/dist/__tests__/asset-registry-types.test-d.d.ts +0 -2
  125. package/dist/__tests__/asset-registry-types.test-d.d.ts.map +0 -1
  126. package/dist/__tests__/assets-runtime-assembly.integration.test.d.ts +0 -2
  127. package/dist/__tests__/assets-runtime-assembly.integration.test.d.ts.map +0 -1
  128. package/dist/__tests__/draw-source-headless-full-chain.test.d.ts +0 -2
  129. package/dist/__tests__/draw-source-headless-full-chain.test.d.ts.map +0 -1
  130. package/dist/__tests__/ecs-import.unit.test.d.ts +0 -2
  131. package/dist/__tests__/ecs-import.unit.test.d.ts.map +0 -1
  132. package/dist/__tests__/execution-world-health-owner.test-d.d.ts +0 -2
  133. package/dist/__tests__/execution-world-health-owner.test-d.d.ts.map +0 -1
  134. package/dist/__tests__/remote-serve-flag.test.d.ts +0 -2
  135. package/dist/__tests__/remote-serve-flag.test.d.ts.map +0 -1
  136. package/dist/assets-runtime-assembly.d.ts +0 -19
  137. package/dist/assets-runtime-assembly.d.ts.map +0 -1
  138. package/src/__tests__/app-rebuild.test.ts +0 -31
  139. package/src/__tests__/asset-registry-types.test-d.ts +0 -16
  140. package/src/__tests__/assets-runtime-assembly.integration.test.ts +0 -68
  141. package/src/__tests__/draw-source-headless-full-chain.test.ts +0 -226
  142. package/src/__tests__/ecs-import.unit.test.ts +0 -40
  143. package/src/__tests__/execution-world-health-owner.test-d.ts +0 -9
  144. package/src/__tests__/remote-serve-flag.test.ts +0 -24
  145. package/src/assets-runtime-assembly.ts +0 -70
@@ -0,0 +1,96 @@
1
+ import type { Plugin } from '@forgeax/engine-plugin';
2
+ import type { RenderError, Renderer, RenderFeature, RenderResult } from '@forgeax/engine-render';
3
+ import type { RendererFeatureAssemblyHost } from '@forgeax/engine-render/internal/construct-renderer';
4
+
5
+ export interface RenderFeatureHost {
6
+ installFeature(
7
+ feature: RenderFeature<unknown>,
8
+ ): Promise<RenderResult<RenderFeatureLease, RenderError>>;
9
+ }
10
+
11
+ export interface RenderFeatureLease {
12
+ release(): Promise<RenderResult<void, RenderError>>;
13
+ }
14
+
15
+ export function createRenderFeatureHost(host: RendererFeatureAssemblyHost): RenderFeatureHost {
16
+ return {
17
+ async installFeature(feature) {
18
+ const installed = await host.installRenderFeature(feature);
19
+ if (!installed.ok) return installed;
20
+ let released = false;
21
+ return {
22
+ ok: true,
23
+ value: {
24
+ release: async () => {
25
+ if (released) return { ok: true, value: undefined };
26
+ released = true;
27
+ return host.uninstallRenderFeature(feature);
28
+ },
29
+ },
30
+ };
31
+ },
32
+ };
33
+ }
34
+
35
+ declare module '@forgeax/engine-plugin' {
36
+ interface EngineContextServices {
37
+ renderer?: Renderer;
38
+ renderFeatureHost?: RenderFeatureHost;
39
+ }
40
+ }
41
+
42
+ /** Provide the renderer without transferring its host-owned lifetime. */
43
+ export function rendererPlugin(renderer: Renderer): Plugin {
44
+ return {
45
+ name: 'renderer',
46
+ provide: 'renderer',
47
+ apply(ctx) {
48
+ ctx.provide('renderer', renderer);
49
+ },
50
+ };
51
+ }
52
+
53
+ /** Provide an App/Worker-owned Renderer and release it after dependent Fibers. */
54
+ export function ownedRendererPlugin(renderer: Renderer): Plugin {
55
+ return {
56
+ name: 'renderer',
57
+ provide: 'renderer',
58
+ apply(ctx) {
59
+ ctx.provide('renderer', renderer);
60
+ ctx.effect(() => () => renderer.dispose(), 'render/renderer');
61
+ },
62
+ };
63
+ }
64
+
65
+ /** Provide the App-owned late RenderFeature assembly capability. */
66
+ export function renderFeatureHostPlugin(host: RenderFeatureHost): Plugin {
67
+ return {
68
+ name: 'render-feature-host',
69
+ provide: 'renderFeatureHost',
70
+ apply(ctx) {
71
+ ctx.provide('renderFeatureHost', host);
72
+ },
73
+ };
74
+ }
75
+
76
+ /** Install a producer feature under the same Cordis Fiber that owns the caller. */
77
+ export function renderFeaturePlugin(feature: RenderFeature<unknown>): Plugin {
78
+ return {
79
+ name: `render-feature:${feature.identity}`,
80
+ inject: ['renderFeatureHost'],
81
+ async apply(ctx) {
82
+ if (ctx.renderFeatureHost === undefined) {
83
+ throw new Error('render-feature host capability is unavailable in this App realm');
84
+ }
85
+ const installed = await ctx.renderFeatureHost.installFeature(feature);
86
+ if (!installed.ok) throw installed.error;
87
+ ctx.effect(
88
+ () => async () => {
89
+ const removed = await installed.value.release();
90
+ if (!removed.ok) throw removed.error;
91
+ },
92
+ `render-feature/${feature.identity}`,
93
+ );
94
+ },
95
+ };
96
+ }
@@ -586,19 +586,6 @@ export async function createToolPreviewHost(
586
586
  const app = appResult.value;
587
587
  const appErrors: unknown[] = [];
588
588
  const unsubscribeAppErrors = app.onError((error) => appErrors.push(error));
589
- const rendererReady = await app.renderer.ready;
590
- if (!rendererReady.ok) {
591
- unsubscribeAppErrors();
592
- await app.dispose();
593
- await runtime.attachment.dispose();
594
- removeOwnedCanvas(canvas, ownsCanvas);
595
- return err({
596
- code: 'tool-preview-bootstrap-failed',
597
- expected: 'the real WebGPU Renderer to finish pipeline initialization before preview frames',
598
- hint: rendererReady.error.hint,
599
- detail: { phase: 'renderer-ready', cause: rendererReady.error },
600
- });
601
- }
602
589
  let resourceFacts: ToolPreviewResourceFacts | undefined;
603
590
  try {
604
591
  const prepared = await options.prepare?.(app);
@@ -626,7 +613,7 @@ export async function createToolPreviewHost(
626
613
  detail: { phase: bootstrapFailure.phase, cause },
627
614
  });
628
615
  }
629
- const attached = app.renderer.attachWorld(app.world);
616
+ const attached = app.renderer.attach(app.world);
630
617
  if (!attached.ok) {
631
618
  unsubscribeAppErrors();
632
619
  await app.dispose();
package/src/types.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  // loop, dt clamp, error fan-out, and input attach internals land in
10
10
  // later milestones (M2..M5 per plan-strategy section 7).
11
11
 
12
- import type { AssetRegistry, CatalogSource } from '@forgeax/engine-assets-runtime';
12
+ import type { AssetRegistry } from '@forgeax/engine-assets-runtime';
13
13
  import type { AudioBackend } from '@forgeax/engine-audio';
14
14
  import type { DebugDraw } from '@forgeax/engine-debug-draw';
15
15
  import type { TimePolicy, World } from '@forgeax/engine-ecs';
@@ -22,18 +22,12 @@ import type {
22
22
  import type { PhysicsWorld, PhysicsWorld2D } from '@forgeax/engine-physics';
23
23
  import type { Context, Plugin } from '@forgeax/engine-plugin';
24
24
  import type { Profiler } from '@forgeax/engine-profiler';
25
- import type {
26
- MembershipTimingOptions,
27
- Renderer,
28
- RendererError,
29
- RenderFeature,
30
- } from '@forgeax/engine-render';
31
- import type { RhiBackendInstrumentation } from '@forgeax/engine-render/internal';
25
+ import type { RenderError, Renderer, RenderFeature, RenderProfile } from '@forgeax/engine-render';
26
+ import type { RhiBackendInstrumentation } from '@forgeax/engine-render/internal/construct-renderer';
32
27
  import type { RhiError, RhiInstance } from '@forgeax/engine-rhi';
33
- import type { CaptureFrameOptions, RhiDebugError } from '@forgeax/engine-rhi-debug';
34
28
  import type { EngineEnvironmentError } from '@forgeax/engine-runtime';
35
- import type { AssetDecoderContributionRef, ImportTransport, Result } from '@forgeax/engine-types';
36
- import type { AssetRuntimeAssemblyError } from './assets-runtime-assembly';
29
+ import type { ImportTransport, Result } from '@forgeax/engine-types';
30
+
37
31
  import type { AppError, AppErrorCode } from './errors';
38
32
  import type { ExecutionControl, ExecutionOptions } from './execution';
39
33
  import type { RhiCapture } from './internal/rhi-capture';
@@ -58,7 +52,7 @@ export type { AppError, AppErrorCode };
58
52
  * `RhiErrorCode` / per-cluster `*ErrorCode` / `PostProcessErrorCode` literal
59
53
  * sets let TS narrow each arm to the concrete class.
60
54
  */
61
- export type AppDispatchError = AppError | RendererError;
55
+ export type AppDispatchError = AppError | RenderError;
62
56
 
63
57
  /**
64
58
  * Per-frame draw description pulled from the host each frame
@@ -137,11 +131,9 @@ export type DrawSource = () => DrawSourceResult | undefined;
137
131
  */
138
132
  export interface AppAssembleArgs {
139
133
  readonly renderer: Renderer;
134
+ /** Host-owned asset catalogue paired with the renderer construction. */
135
+ readonly assets?: AssetRegistry;
140
136
  readonly world: World;
141
- /** One immutable Catalog scope for this App realm. */
142
- readonly assetCatalog?: CatalogSource;
143
- /** Explicit owner contributions installed into this realm's Registry. */
144
- readonly assetDecoders?: readonly AssetDecoderContributionRef[];
145
137
  /** Unified plugin list (M1 feat-20260623-plugin-system-unify-build-world-protocol). */
146
138
  readonly plugins?: readonly Plugin[];
147
139
  readonly silenceUnhandledErrors?: boolean;
@@ -154,8 +146,6 @@ export interface AppAssembleArgs {
154
146
  readonly drawSource?: DrawSource;
155
147
  /** Explicit profiler capability shared by the host and renderer. */
156
148
  readonly profiler?: Profiler;
157
- /** Explicit opt-in for Render-owned HDRP membership timing evidence. */
158
- readonly membershipTiming?: MembershipTimingOptions;
159
149
  }
160
150
 
161
151
  /** Effective physical canvas size transported to an Engine Worker frame. */
@@ -169,8 +159,8 @@ export interface CanvasDrawingBufferSize {
169
159
  *
170
160
  * feat-20260608-create-app-param-surface-trim / M2 / D-3: self-describing
171
161
  * surface -- no longer `extends RendererOptions`. The 7 app-only fields
172
- * (input / audio / physics / silenceUnhandledErrors) plus the 2 RHI escape-hatch
173
- * fields (rhi / rawDeviceForContextConfigure) are
162
+ * (input / audio / physics / silenceUnhandledErrors) plus the RHI escape-hatch
163
+ * field (rhi) are
174
164
  * listed inline, so IDE autocomplete shows AI users a clean surface
175
165
  * without inheriting now-disallowed slots like clearColor (M1, on Camera)
176
166
  * and shaderManifestUrl (M2, on BundlerOptions / 3rd arg). The escape
@@ -178,23 +168,14 @@ export interface CanvasDrawingBufferSize {
178
168
  * default noise, but reachable when the AI user scrolls the type).
179
169
  */
180
170
  export interface CreateAppOptions {
181
- /**
182
- * Optional positive Host-owned upper bound for the canvas device pixel ratio.
183
- * Values below 1 intentionally downsample GPU-bound surfaces. The default is
184
- * the current devicePixelRatio; the Engine never reads URL or game-specific
185
- * settings to derive this value.
186
- */
187
- readonly maxCanvasPixelRatio?: number | undefined;
188
- /** One immutable Catalog scope for this App realm. */
189
- readonly assetCatalog?: CatalogSource;
190
- /** Explicit owner contributions installed into this realm's Registry. */
191
- readonly assetDecoders?: readonly AssetDecoderContributionRef[];
192
171
  /** Opt into realm-local engine execution. Omission preserves the existing local assembly path. */
193
172
  readonly execution?: ExecutionOptions;
194
173
  /** Host-owned UI root whose events do not enter gameplay input. */
195
174
  readonly uiRoot?: Node;
196
175
  /** Producer-owned render features forwarded to the renderer unchanged. */
197
176
  readonly features?: readonly RenderFeature<unknown>[];
177
+ /** Standard profile forwarded to the single renderer-owned pipeline. */
178
+ readonly standardProfile?: RenderProfile;
198
179
  /** Unified plugin list (M1 feat-20260623-plugin-system-unify-build-world-protocol). */
199
180
  readonly plugins?: readonly Plugin[];
200
181
  /**
@@ -220,15 +201,8 @@ export interface CreateAppOptions {
220
201
  * advanced AI users that ship their own RhiInstance shim.
221
202
  */
222
203
  readonly rhi?: RhiInstance | undefined;
223
- /** @internal Runtime-owned instrumentation seam for a recorder attachment. */
204
+ /** Optional host-owned RHI lifecycle instrumentation, such as recording. */
224
205
  readonly rhiInstrumentation?: RhiBackendInstrumentation;
225
- /**
226
- * D-S1 raw GPUDevice escape hatch -- forwarded verbatim to createRenderer.
227
- * Same semantics as `RendererOptions.rawDeviceForContextConfigure`. Used
228
- * by the apps/hello/triangle bootstrap, where the host configures the
229
- * canvas's GPUCanvasContext outside the RHI surface.
230
- */
231
- readonly rawDeviceForContextConfigure?: unknown | (() => unknown | undefined);
232
206
  /**
233
207
  * Neutral PointerLock gate forwarded verbatim to the canvas-form input
234
208
  * attach (attachInputAuto → attachBrowserInputBackend). When it returns
@@ -279,8 +253,6 @@ export interface CreateAppOptions {
279
253
  readonly drawSource?: DrawSource;
280
254
  /** Explicit profiler capability shared by the host and renderer. */
281
255
  readonly profiler?: Profiler;
282
- /** Explicit opt-in for Render-owned HDRP membership timing evidence. */
283
- readonly membershipTiming?: MembershipTimingOptions;
284
256
  }
285
257
 
286
258
  /**
@@ -345,8 +317,8 @@ export interface BundlerOptions {
345
317
  export interface App {
346
318
  /** Caller-owned Renderer (reference equality with the assemble input). */
347
319
  readonly renderer: Renderer;
348
- /** App-owned single-scope runtime Registry; disposed with the Cordis realm. */
349
- readonly assets: AssetRegistry;
320
+ /** Host-owned asset catalogue paired with this renderer lease. */
321
+ readonly assets?: AssetRegistry;
350
322
  /** Caller-owned World (reference equality with the assemble input). */
351
323
  readonly world: World;
352
324
  /** Host-side lifecycle and immutable diagnostics for the selected execution tier. */
@@ -355,9 +327,9 @@ export interface App {
355
327
  * Pause frame submission and relinquish the renderer presentation surface
356
328
  * without replacing World, Renderer, AssetRegistry, plugins, or history.
357
329
  */
358
- releaseSurfacePreserveWorld(): Promise<Result<void, RhiError>>;
330
+ releaseSurfacePreserveWorld(): Promise<Result<void, RhiError | RenderError>>;
359
331
  /** Restore the same surface and resume only when release paused a running App. */
360
- restoreSurface(): Promise<Result<void, RhiError>>;
332
+ restoreSurface(): Promise<Result<void, RhiError | RenderError>>;
361
333
  /** Native Cordis realm that owns this App's capability fibers and effects. */
362
334
  readonly pluginContext: Context;
363
335
  /** InputBackend handle when input attach is enabled; undefined otherwise. */
@@ -432,18 +404,12 @@ export interface App {
432
404
  */
433
405
  setDrawSource(drawSource: DrawSource | undefined): void;
434
406
  /**
435
- * Most recent device-loss error retained for host self-inspection without
407
+ * Most recent dispatched error retained for host self-inspection without
436
408
  * requiring an onError listener up front.
437
409
  */
438
410
  readonly lastError?: AppDispatchError | undefined;
439
- /**
440
- * Optional single-frame RHI capture capability.
441
- *
442
- * A successful capture returns one `{ kind: 'rhi-tape', digest, bytes }`
443
- * artifact. Pass that same artifact to DevKit summary and inspect
444
- * operations; the selection key is `FrameModel.works[].workIndex`.
445
- */
446
- readonly rhiCapture?: RhiCapture | undefined;
411
+ /** Optional single-frame RHI capture capability owned by the App host. */
412
+ readonly rhiCapture?: RhiCapture;
447
413
  /**
448
414
  * Handle for the remote eval server started by createApp (dev mode).
449
415
  *
@@ -461,30 +427,9 @@ export interface App {
461
427
  /** Host control returned by the unified execution path. Engine-owned objects remain realm-local. */
462
428
  export type ExecutionApp = Pick<
463
429
  App,
464
- | 'execution'
465
- | 'input'
466
- | 'audio'
467
- | 'rhiCapture'
468
- | 'start'
469
- | 'stop'
470
- | 'pause'
471
- | 'resume'
472
- | 'onError'
473
- | 'lastError'
430
+ 'execution' | 'input' | 'audio' | 'start' | 'stop' | 'pause' | 'resume' | 'onError' | 'lastError'
474
431
  >;
475
432
 
476
- /** Artifact returned by the browser RHI-debug capture capability. */
477
- export interface RhiCaptureArtifact {
478
- readonly kind: 'rhi-tape';
479
- readonly digest: string;
480
- readonly bytes: Uint8Array;
481
- }
482
-
483
- /** Same-origin browser hook shared by main-serial and Worker execution. */
484
- export interface RhiCaptureHook {
485
- captureFrame(options?: CaptureFrameOptions): Promise<Result<RhiCaptureArtifact, RhiDebugError>>;
486
- }
487
-
488
433
  /**
489
434
  * Error union returned by the assemble-form entry. The canvas-form thin
490
435
  * wrapper widens this with EngineEnvironmentError (createRenderer
@@ -492,7 +437,7 @@ export interface RhiCaptureHook {
492
437
  *
493
438
  * Cordis activation failures are projected into AppError at this boundary.
494
439
  */
495
- export type AssembleAppError = AppError | RhiError | AssetRuntimeAssemblyError;
440
+ export type AssembleAppError = AppError | RhiError;
496
441
 
497
442
  /**
498
443
  * Error union returned by the canvas-form thin wrapper. Extends
package/src/vite-env.d.ts CHANGED
@@ -6,7 +6,5 @@ interface ImportMeta {
6
6
  readonly env?: {
7
7
  readonly DEV?: boolean;
8
8
  readonly FORGEAX_ENGINE_RHI_DEBUG?: string;
9
- /** Explicit opt-in for bounded producer-owned semantic observations. */
10
- readonly VITE_FORGEAX_ENGINE_RHI_SEMANTIC?: string;
11
9
  };
12
10
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=app-rebuild.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"app-rebuild.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/app-rebuild.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=asset-registry-types.test-d.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"asset-registry-types.test-d.d.ts","sourceRoot":"","sources":["../../src/__tests__/asset-registry-types.test-d.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=assets-runtime-assembly.integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assets-runtime-assembly.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/assets-runtime-assembly.integration.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=draw-source-headless-full-chain.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"draw-source-headless-full-chain.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/draw-source-headless-full-chain.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ecs-import.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ecs-import.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ecs-import.unit.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=execution-world-health-owner.test-d.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"execution-world-health-owner.test-d.d.ts","sourceRoot":"","sources":["../../src/__tests__/execution-world-health-owner.test-d.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=remote-serve-flag.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"remote-serve-flag.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/remote-serve-flag.test.ts"],"names":[],"mappings":""}
@@ -1,19 +0,0 @@
1
- import type { AssetDecoderLease, AssetRegistry } from '@forgeax/engine-assets-runtime';
2
- import { type AssetDecoderContributionRef, type Result } from '@forgeax/engine-types';
3
- export interface AssetRuntimeAssemblyError {
4
- readonly code: 'asset-assembly-failed';
5
- readonly expected: string;
6
- readonly hint: string;
7
- readonly detail: {
8
- readonly kind: string;
9
- readonly cause: unknown;
10
- };
11
- }
12
- export interface AssetRuntimeAssembly {
13
- readonly registry: AssetRegistry;
14
- readonly leases: readonly AssetDecoderLease[];
15
- dispose(): void;
16
- }
17
- /** Install owner decoder contributions into the realm's one asset registry. */
18
- export declare function assembleAssetRuntime(registry: AssetRegistry, contributions: readonly AssetDecoderContributionRef[]): Result<AssetRuntimeAssembly, AssetRuntimeAssemblyError>;
19
- //# sourceMappingURL=assets-runtime-assembly.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assets-runtime-assembly.d.ts","sourceRoot":"","sources":["../src/assets-runtime-assembly.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAEvF,OAAO,EACL,KAAK,2BAA2B,EAIhC,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;CACrE;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC9C,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EACvB,aAAa,EAAE,SAAS,2BAA2B,EAAE,GACpD,MAAM,CAAC,oBAAoB,EAAE,yBAAyB,CAAC,CA0CzD"}
@@ -1,31 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { disposeWithOrderedDetail, RebuildLifecycleError } from '../execution/attached-world-swap';
3
-
4
- describe('M4 app rebuild lifecycle', () => {
5
- it('retains primary failure while recording both cleanup failures in order', async () => {
6
- const cleanup: { phase: 'candidate' | 'previous'; cause: unknown }[] = [];
7
- const primary = new Error('system throw');
8
- await disposeWithOrderedDetail(
9
- 'candidate',
10
- () => {
11
- throw new Error('candidate cleanup');
12
- },
13
- cleanup,
14
- );
15
- await disposeWithOrderedDetail(
16
- 'previous',
17
- () => {
18
- throw new Error('previous cleanup');
19
- },
20
- cleanup,
21
- );
22
-
23
- const failure = new RebuildLifecycleError(primary, cleanup);
24
- expect(failure.primary).toBe(primary);
25
- expect(failure.cleanup.map((entry) => entry.phase)).toEqual(['candidate', 'previous']);
26
- expect(failure.cleanup.map((entry) => (entry.cause as Error).message)).toEqual([
27
- 'candidate cleanup',
28
- 'previous cleanup',
29
- ]);
30
- });
31
- });
@@ -1,16 +0,0 @@
1
- import type { AssetRegistry } from '@forgeax/engine-assets-runtime';
2
- import type { EngineContextServices } from '@forgeax/engine-plugin';
3
- import type { RenderAssetPort } from '@forgeax/engine-render';
4
- import { describe, expectTypeOf, it } from 'vitest';
5
- import type { App, GameHost } from '../index';
6
-
7
- describe('app asset ownership types', () => {
8
- it('keeps the GameHost loader registry distinct from the App render projection', () => {
9
- expectTypeOf<GameHost['assets']>().toEqualTypeOf<AssetRegistry>();
10
- expectTypeOf<App['assets']>().toEqualTypeOf<AssetRegistry>();
11
- });
12
-
13
- it('augments the engine service with the Renderer-owned port', () => {
14
- expectTypeOf<EngineContextServices['assets']>().toEqualTypeOf<RenderAssetPort | undefined>();
15
- });
16
- });
@@ -1,68 +0,0 @@
1
- import {
2
- createAssetRegistry,
3
- createCatalogSource,
4
- defineAssetKind,
5
- } from '@forgeax/engine-assets-runtime';
6
- import { ok } from '@forgeax/engine-types';
7
- import { describe, expect, it } from 'vitest';
8
- import { assembleAssetRuntime } from '../assets-runtime-assembly';
9
-
10
- const kind = defineAssetKind<unknown, 'host-blob'>('host-blob');
11
-
12
- describe('App asset runtime assembly', () => {
13
- it('installs the one default owner contribution for each durable built-in kind', () => {
14
- const registry = createAssetRegistry({ catalog: createCatalogSource({ entries: [] }) });
15
- const assembled = assembleAssetRuntime(registry, []);
16
-
17
- expect(assembled.ok).toBe(true);
18
- if (!assembled.ok) return;
19
- expect(assembled.value.leases.map((lease) => lease.kind)).toEqual([
20
- 'mesh',
21
- 'material',
22
- 'scene',
23
- 'texture',
24
- 'equirect',
25
- 'sampler',
26
- 'font',
27
- 'render-pipeline',
28
- 'tileset',
29
- 'video',
30
- 'skeleton',
31
- 'skin',
32
- 'animation-clip',
33
- 'animation-graph',
34
- 'audio',
35
- 'particle-effect',
36
- ]);
37
- assembled.value.dispose();
38
- registry.dispose();
39
- });
40
-
41
- it('installs one owner lease and releases it idempotently', () => {
42
- const registry = createAssetRegistry({ catalog: createCatalogSource({ entries: [] }) });
43
- const assembled = assembleAssetRuntime(registry, [
44
- { kind, consumer: 'test-owner', decoder: { decode: async () => ok('value') } },
45
- ]);
46
-
47
- expect(assembled.ok).toBe(true);
48
- if (!assembled.ok) return;
49
- expect(assembled.value.leases).toHaveLength(17);
50
- expect(assembled.value.leases.at(-1)?.kind).toBe('host-blob');
51
- assembled.value.dispose();
52
- assembled.value.dispose();
53
- registry.dispose();
54
- });
55
-
56
- it('returns a closed assembly error for duplicate owner kinds', () => {
57
- const registry = createAssetRegistry({ catalog: createCatalogSource({ entries: [] }) });
58
- const contribution = {
59
- kind,
60
- consumer: 'test-owner',
61
- decoder: { decode: async () => ok('value') },
62
- };
63
- const assembled = assembleAssetRuntime(registry, [contribution, contribution]);
64
-
65
- expect(assembled).toMatchObject({ ok: false, error: { code: 'asset-assembly-failed' } });
66
- registry.dispose();
67
- });
68
- });