@forgeax/engine-app 0.1.2
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/LICENSE +202 -0
- package/README.md +418 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/animation-asset-lookup.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-asset-lookup.unit.test.d.ts.map +1 -0
- package/dist/__tests__/app-rebuild.test.d.ts +2 -0
- package/dist/__tests__/app-rebuild.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-types.test-d.d.ts +2 -0
- package/dist/__tests__/asset-registry-types.test-d.d.ts.map +1 -0
- package/dist/__tests__/assets-runtime-assembly.integration.test.d.ts +2 -0
- package/dist/__tests__/assets-runtime-assembly.integration.test.d.ts.map +1 -0
- package/dist/__tests__/callback-deletion.unit.test.d.ts +2 -0
- package/dist/__tests__/callback-deletion.unit.test.d.ts.map +1 -0
- package/dist/__tests__/callback-inference.test-d.d.ts +2 -0
- package/dist/__tests__/callback-inference.test-d.d.ts.map +1 -0
- package/dist/__tests__/component-introspection.unit.test.d.ts +2 -0
- package/dist/__tests__/component-introspection.unit.test.d.ts.map +1 -0
- package/dist/__tests__/consumer-migration.unit.test.d.ts +2 -0
- package/dist/__tests__/consumer-migration.unit.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-features.test.d.ts +2 -0
- package/dist/__tests__/create-app-features.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-listener-sync.test.d.ts +2 -0
- package/dist/__tests__/create-app-listener-sync.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-lock-provider.test.d.ts +2 -0
- package/dist/__tests__/create-app-lock-provider.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-plugin.test.d.ts +2 -0
- package/dist/__tests__/create-app-plugin.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-stop.test.d.ts +2 -0
- package/dist/__tests__/create-app-stop.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-time.unit.test.d.ts +2 -0
- package/dist/__tests__/create-app-time.unit.test.d.ts.map +1 -0
- package/dist/__tests__/create-app.test-d.d.ts +2 -0
- package/dist/__tests__/create-app.test-d.d.ts.map +1 -0
- package/dist/__tests__/create-app.test.d.ts +2 -0
- package/dist/__tests__/create-app.test.d.ts.map +1 -0
- package/dist/__tests__/create-renderer-error.integration.test.d.ts +2 -0
- package/dist/__tests__/create-renderer-error.integration.test.d.ts.map +1 -0
- package/dist/__tests__/create-renderer-lifecycle.integration.test.d.ts +2 -0
- package/dist/__tests__/create-renderer-lifecycle.integration.test.d.ts.map +1 -0
- package/dist/__tests__/docs-gate-green.unit.test.d.ts +2 -0
- package/dist/__tests__/docs-gate-green.unit.test.d.ts.map +1 -0
- package/dist/__tests__/draw-source-headless-full-chain.test.d.ts +2 -0
- package/dist/__tests__/draw-source-headless-full-chain.test.d.ts.map +1 -0
- package/dist/__tests__/draw-source-injected-world-update-visibility.test.d.ts +2 -0
- package/dist/__tests__/draw-source-injected-world-update-visibility.test.d.ts.map +1 -0
- package/dist/__tests__/draw-source-single-world-regression.test.d.ts +2 -0
- package/dist/__tests__/draw-source-single-world-regression.test.d.ts.map +1 -0
- package/dist/__tests__/ecs-import.unit.test.d.ts +2 -0
- package/dist/__tests__/ecs-import.unit.test.d.ts.map +1 -0
- package/dist/__tests__/engine-worker-bootstrap-channel.unit.test.d.ts +2 -0
- package/dist/__tests__/engine-worker-bootstrap-channel.unit.test.d.ts.map +1 -0
- package/dist/__tests__/engine-worker-world-swap.unit.test.d.ts +2 -0
- package/dist/__tests__/engine-worker-world-swap.unit.test.d.ts.map +1 -0
- package/dist/__tests__/errors-pointer-lock-failed.test.d.ts +2 -0
- package/dist/__tests__/errors-pointer-lock-failed.test.d.ts.map +1 -0
- package/dist/__tests__/execution-bootstrap-isolation.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-bootstrap-isolation.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-error-detail.test-d.d.ts +2 -0
- package/dist/__tests__/execution-error-detail.test-d.d.ts.map +1 -0
- package/dist/__tests__/execution-error-detail.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-error-detail.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-frame-order.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-frame-order.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-frame-protocol.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-frame-protocol.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-input-sample.contract.test.d.ts +2 -0
- package/dist/__tests__/execution-input-sample.contract.test.d.ts.map +1 -0
- package/dist/__tests__/execution-measurement.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-measurement.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-public-api.test-d.d.ts +2 -0
- package/dist/__tests__/execution-public-api.test-d.d.ts.map +1 -0
- package/dist/__tests__/execution-public-api.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-public-api.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-rebuild.contract.test.d.ts +2 -0
- package/dist/__tests__/execution-rebuild.contract.test.d.ts.map +1 -0
- package/dist/__tests__/execution-report.contract.test.d.ts +2 -0
- package/dist/__tests__/execution-report.contract.test.d.ts.map +1 -0
- package/dist/__tests__/execution-report.types.test-d.d.ts +2 -0
- package/dist/__tests__/execution-report.types.test-d.d.ts.map +1 -0
- package/dist/__tests__/execution-schema-freshness.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-schema-freshness.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-selector.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-selector.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-shared-kernel.unit.test.d.ts +2 -0
- package/dist/__tests__/execution-shared-kernel.unit.test.d.ts.map +1 -0
- package/dist/__tests__/execution-world-health-owner.test-d.d.ts +2 -0
- package/dist/__tests__/execution-world-health-owner.test-d.d.ts.map +1 -0
- package/dist/__tests__/fallback-camera.unit.test.d.ts +2 -0
- package/dist/__tests__/fallback-camera.unit.test.d.ts.map +1 -0
- package/dist/__tests__/frame-loop-time-elapsed.test.d.ts +2 -0
- package/dist/__tests__/frame-loop-time-elapsed.test.d.ts.map +1 -0
- package/dist/__tests__/frame-loop-time.unit.test.d.ts +2 -0
- package/dist/__tests__/frame-loop-time.unit.test.d.ts.map +1 -0
- package/dist/__tests__/frame-loop-world-array.test.d.ts +2 -0
- package/dist/__tests__/frame-loop-world-array.test.d.ts.map +1 -0
- package/dist/__tests__/kernel-worker-runtime.unit.test.d.ts +2 -0
- package/dist/__tests__/kernel-worker-runtime.unit.test.d.ts.map +1 -0
- package/dist/__tests__/migration-surface-inventory.unit.test.d.ts +2 -0
- package/dist/__tests__/migration-surface-inventory.unit.test.d.ts.map +1 -0
- package/dist/__tests__/plugin-policy.integration.test.d.ts +2 -0
- package/dist/__tests__/plugin-policy.integration.test.d.ts.map +1 -0
- package/dist/__tests__/plugin-profiles.unit.test.d.ts +2 -0
- package/dist/__tests__/plugin-profiles.unit.test.d.ts.map +1 -0
- package/dist/__tests__/profiler-default-off.test.d.ts +2 -0
- package/dist/__tests__/profiler-default-off.test.d.ts.map +1 -0
- package/dist/__tests__/profiler-frame-token.test.d.ts +2 -0
- package/dist/__tests__/profiler-frame-token.test.d.ts.map +1 -0
- package/dist/__tests__/profiler-phase-catalog.test.d.ts +2 -0
- package/dist/__tests__/profiler-phase-catalog.test.d.ts.map +1 -0
- package/dist/__tests__/profiler-phase-integration.test.d.ts +2 -0
- package/dist/__tests__/profiler-phase-integration.test.d.ts.map +1 -0
- package/dist/__tests__/profiler-remote-bridge.test.d.ts +2 -0
- package/dist/__tests__/profiler-remote-bridge.test.d.ts.map +1 -0
- package/dist/__tests__/remote-integration.test.d.ts +2 -0
- package/dist/__tests__/remote-integration.test.d.ts.map +1 -0
- package/dist/__tests__/remote-serve-flag.test.d.ts +2 -0
- package/dist/__tests__/remote-serve-flag.test.d.ts.map +1 -0
- package/dist/__tests__/rhi-capture-capability.test-d.d.ts +2 -0
- package/dist/__tests__/rhi-capture-capability.test-d.d.ts.map +1 -0
- package/dist/__tests__/rhi-capture-host.integration.test.d.ts +2 -0
- package/dist/__tests__/rhi-capture-host.integration.test.d.ts.map +1 -0
- package/dist/__tests__/rhi-capture.browser.test.d.ts +2 -0
- package/dist/__tests__/rhi-capture.browser.test.d.ts.map +1 -0
- package/dist/__tests__/surface-handoff.test.d.ts +2 -0
- package/dist/__tests__/surface-handoff.test.d.ts.map +1 -0
- package/dist/__tests__/types-m2.test-d.d.ts +2 -0
- package/dist/__tests__/types-m2.test-d.d.ts.map +1 -0
- package/dist/__tests__/visibility-remote.integration.test.d.ts +2 -0
- package/dist/__tests__/visibility-remote.integration.test.d.ts.map +1 -0
- package/dist/__tests__/worker-execution-stop.test.d.ts +2 -0
- package/dist/__tests__/worker-execution-stop.test.d.ts.map +1 -0
- package/dist/animation-asset-lookup.d.ts +8 -0
- package/dist/animation-asset-lookup.d.ts.map +1 -0
- package/dist/assets-runtime-assembly.d.ts +19 -0
- package/dist/assets-runtime-assembly.d.ts.map +1 -0
- package/dist/canvas-policy.d.ts +4 -0
- package/dist/canvas-policy.d.ts.map +1 -0
- package/dist/create-app.d.ts +57 -0
- package/dist/create-app.d.ts.map +1 -0
- package/dist/engine-worker-runtime.mjs +884 -0
- package/dist/engine-worker-runtime.mjs.map +1 -0
- package/dist/errors.d.ts +263 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/execution/attached-world-swap.d.ts +21 -0
- package/dist/execution/attached-world-swap.d.ts.map +1 -0
- package/dist/execution/bootstrap-entry.d.ts +30 -0
- package/dist/execution/bootstrap-entry.d.ts.map +1 -0
- package/dist/execution/capabilities.d.ts +5 -0
- package/dist/execution/capabilities.d.ts.map +1 -0
- package/dist/execution/control.d.ts +14 -0
- package/dist/execution/control.d.ts.map +1 -0
- package/dist/execution/engine-worker-runtime.d.ts +2 -0
- package/dist/execution/engine-worker-runtime.d.ts.map +1 -0
- package/dist/execution/engine-worker.d.ts +23 -0
- package/dist/execution/engine-worker.d.ts.map +1 -0
- package/dist/execution/host-controller.d.ts +16 -0
- package/dist/execution/host-controller.d.ts.map +1 -0
- package/dist/execution/index.d.ts +10 -0
- package/dist/execution/index.d.ts.map +1 -0
- package/dist/execution/kernel-pool.d.ts +14 -0
- package/dist/execution/kernel-pool.d.ts.map +1 -0
- package/dist/execution/kernel-worker-runtime.d.ts +2 -0
- package/dist/execution/kernel-worker-runtime.d.ts.map +1 -0
- package/dist/execution/measurement.d.ts +7 -0
- package/dist/execution/measurement.d.ts.map +1 -0
- package/dist/execution/protocol.d.ts +84 -0
- package/dist/execution/protocol.d.ts.map +1 -0
- package/dist/execution/report.d.ts +5 -0
- package/dist/execution/report.d.ts.map +1 -0
- package/dist/execution/schema.d.ts +4 -0
- package/dist/execution/schema.d.ts.map +1 -0
- package/dist/execution/selector.d.ts +10 -0
- package/dist/execution/selector.d.ts.map +1 -0
- package/dist/execution/types.d.ts +107 -0
- package/dist/execution/types.d.ts.map +1 -0
- package/dist/fallback-camera.d.ts +8 -0
- package/dist/fallback-camera.d.ts.map +1 -0
- package/dist/game-context.d.ts +98 -0
- package/dist/game-context.d.ts.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +3985 -0
- package/dist/index.mjs.map +1 -0
- package/dist/input-map-plugin.d.ts +5 -0
- package/dist/input-map-plugin.d.ts.map +1 -0
- package/dist/input-plugin.d.ts +4 -0
- package/dist/input-plugin.d.ts.map +1 -0
- package/dist/internal/assembled-engine-profile.d.ts +5 -0
- package/dist/internal/assembled-engine-profile.d.ts.map +1 -0
- package/dist/internal/assets-world-plugin.d.ts +21 -0
- package/dist/internal/assets-world-plugin.d.ts.map +1 -0
- package/dist/internal/browser-remote-bridge.d.ts +25 -0
- package/dist/internal/browser-remote-bridge.d.ts.map +1 -0
- package/dist/internal/browser-rhi-debug-runtime.d.ts +18 -0
- package/dist/internal/browser-rhi-debug-runtime.d.ts.map +1 -0
- package/dist/internal/component-introspection.d.ts +24 -0
- package/dist/internal/component-introspection.d.ts.map +1 -0
- package/dist/internal/ecs-import.d.ts +6 -0
- package/dist/internal/ecs-import.d.ts.map +1 -0
- package/dist/internal/engine-profile-common.d.ts +9 -0
- package/dist/internal/engine-profile-common.d.ts.map +1 -0
- package/dist/internal/error-fanout.d.ts +66 -0
- package/dist/internal/error-fanout.d.ts.map +1 -0
- package/dist/internal/frame-loop.d.ts +35 -0
- package/dist/internal/frame-loop.d.ts.map +1 -0
- package/dist/internal/input-attach.d.ts +44 -0
- package/dist/internal/input-attach.d.ts.map +1 -0
- package/dist/internal/main-engine-profile.d.ts +15 -0
- package/dist/internal/main-engine-profile.d.ts.map +1 -0
- package/dist/internal/remote-serve-flag.d.ts +23 -0
- package/dist/internal/remote-serve-flag.d.ts.map +1 -0
- package/dist/internal/remote-server-plugin.d.ts +8 -0
- package/dist/internal/remote-server-plugin.d.ts.map +1 -0
- package/dist/internal/rhi-capture.d.ts +19 -0
- package/dist/internal/rhi-capture.d.ts.map +1 -0
- package/dist/internal/rhi-debug-flag.d.ts +18 -0
- package/dist/internal/rhi-debug-flag.d.ts.map +1 -0
- package/dist/internal/worker-engine-profile.d.ts +13 -0
- package/dist/internal/worker-engine-profile.d.ts.map +1 -0
- package/dist/kernel-worker-runtime.mjs +69 -0
- package/dist/kernel-worker-runtime.mjs.map +1 -0
- package/dist/load-game-errors.d.ts +131 -0
- package/dist/load-game-errors.d.ts.map +1 -0
- package/dist/load-game.d.ts +34 -0
- package/dist/load-game.d.ts.map +1 -0
- package/dist/plugin-factories.d.ts +3 -0
- package/dist/plugin-factories.d.ts.map +1 -0
- package/dist/tool-preview/bootstrap.d.ts +113 -0
- package/dist/tool-preview/bootstrap.d.ts.map +1 -0
- package/dist/tool-preview/evidence.d.ts +20 -0
- package/dist/tool-preview/evidence.d.ts.map +1 -0
- package/dist/tool-preview/framing.d.ts +13 -0
- package/dist/tool-preview/framing.d.ts.map +1 -0
- package/dist/tool-preview/recipe.d.ts +54 -0
- package/dist/tool-preview/recipe.d.ts.map +1 -0
- package/dist/types.d.ts +444 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +86 -0
- package/schema/execution-report.schema.json +168 -0
- package/src/__tests__/animation-asset-lookup.unit.test.ts +20 -0
- package/src/__tests__/app-rebuild.test.ts +31 -0
- package/src/__tests__/asset-registry-types.test-d.ts +16 -0
- package/src/__tests__/assets-runtime-assembly.integration.test.ts +68 -0
- package/src/__tests__/callback-deletion.unit.test.ts +14 -0
- package/src/__tests__/callback-inference.test-d.ts +32 -0
- package/src/__tests__/component-introspection.unit.test.ts +56 -0
- package/src/__tests__/consumer-migration.unit.test.ts +21 -0
- package/src/__tests__/create-app-features.test.ts +40 -0
- package/src/__tests__/create-app-listener-sync.test.ts +377 -0
- package/src/__tests__/create-app-lock-provider.test.ts +212 -0
- package/src/__tests__/create-app-plugin.test.ts +217 -0
- package/src/__tests__/create-app-stop.test.ts +617 -0
- package/src/__tests__/create-app-time.unit.test.ts +26 -0
- package/src/__tests__/create-app.test-d.ts +82 -0
- package/src/__tests__/create-app.test.ts +346 -0
- package/src/__tests__/create-renderer-error.integration.test.ts +24 -0
- package/src/__tests__/create-renderer-lifecycle.integration.test.ts +19 -0
- package/src/__tests__/docs-gate-green.unit.test.ts +61 -0
- package/src/__tests__/draw-source-headless-full-chain.test.ts +226 -0
- package/src/__tests__/draw-source-injected-world-update-visibility.test.ts +182 -0
- package/src/__tests__/draw-source-single-world-regression.test.ts +185 -0
- package/src/__tests__/ecs-import.unit.test.ts +40 -0
- package/src/__tests__/engine-worker-bootstrap-channel.unit.test.ts +74 -0
- package/src/__tests__/engine-worker-world-swap.unit.test.ts +76 -0
- package/src/__tests__/errors-pointer-lock-failed.test.ts +268 -0
- package/src/__tests__/execution-bootstrap-isolation.unit.test.ts +80 -0
- package/src/__tests__/execution-error-detail.test-d.ts +13 -0
- package/src/__tests__/execution-error-detail.unit.test.ts +35 -0
- package/src/__tests__/execution-frame-order.unit.test.ts +38 -0
- package/src/__tests__/execution-frame-protocol.unit.test.ts +61 -0
- package/src/__tests__/execution-input-sample.contract.test.ts +23 -0
- package/src/__tests__/execution-measurement.unit.test.ts +20 -0
- package/src/__tests__/execution-public-api.test-d.ts +10 -0
- package/src/__tests__/execution-public-api.unit.test.ts +9 -0
- package/src/__tests__/execution-rebuild.contract.test.ts +36 -0
- package/src/__tests__/execution-report.contract.test.ts +50 -0
- package/src/__tests__/execution-report.types.test-d.ts +16 -0
- package/src/__tests__/execution-schema-freshness.unit.test.ts +20 -0
- package/src/__tests__/execution-selector.unit.test.ts +72 -0
- package/src/__tests__/execution-shared-kernel.unit.test.ts +180 -0
- package/src/__tests__/execution-world-health-owner.test-d.ts +9 -0
- package/src/__tests__/fallback-camera.unit.test.ts +32 -0
- package/src/__tests__/frame-loop-time-elapsed.test.ts +115 -0
- package/src/__tests__/frame-loop-time.unit.test.ts +61 -0
- package/src/__tests__/frame-loop-world-array.test.ts +441 -0
- package/src/__tests__/kernel-worker-runtime.unit.test.ts +50 -0
- package/src/__tests__/migration-surface-inventory.unit.test.ts +13 -0
- package/src/__tests__/plugin-policy.integration.test.ts +15 -0
- package/src/__tests__/plugin-profiles.unit.test.ts +190 -0
- package/src/__tests__/profiler-default-off.test.ts +53 -0
- package/src/__tests__/profiler-frame-token.test.ts +248 -0
- package/src/__tests__/profiler-phase-catalog.test.ts +30 -0
- package/src/__tests__/profiler-phase-integration.test.ts +129 -0
- package/src/__tests__/profiler-remote-bridge.test.ts +31 -0
- package/src/__tests__/remote-integration.test.ts +224 -0
- package/src/__tests__/remote-serve-flag.test.ts +24 -0
- package/src/__tests__/rhi-capture-capability.test-d.ts +22 -0
- package/src/__tests__/rhi-capture-host.integration.test.ts +157 -0
- package/src/__tests__/rhi-capture.browser.test.ts +51 -0
- package/src/__tests__/surface-handoff.test.ts +92 -0
- package/src/__tests__/types-m2.test-d.ts +81 -0
- package/src/__tests__/visibility-remote.integration.test.ts +119 -0
- package/src/__tests__/worker-execution-stop.test.ts +116 -0
- package/src/animation-asset-lookup.ts +13 -0
- package/src/assets-runtime-assembly.ts +70 -0
- package/src/canvas-policy.ts +16 -0
- package/src/create-app.ts +1351 -0
- package/src/errors.ts +454 -0
- package/src/execution/attached-world-swap.ts +67 -0
- package/src/execution/bootstrap-entry.ts +122 -0
- package/src/execution/capabilities.ts +102 -0
- package/src/execution/control.ts +52 -0
- package/src/execution/engine-worker-runtime.ts +400 -0
- package/src/execution/engine-worker.ts +161 -0
- package/src/execution/host-controller.ts +454 -0
- package/src/execution/index.ts +43 -0
- package/src/execution/kernel-pool.ts +236 -0
- package/src/execution/kernel-worker-runtime.ts +103 -0
- package/src/execution/measurement.ts +39 -0
- package/src/execution/protocol.ts +131 -0
- package/src/execution/report.ts +66 -0
- package/src/execution/schema.ts +168 -0
- package/src/execution/selector.ts +98 -0
- package/src/execution/types.ts +146 -0
- package/src/fallback-camera.ts +20 -0
- package/src/game-context.ts +126 -0
- package/src/index.ts +176 -0
- package/src/input-map-plugin.ts +21 -0
- package/src/input-plugin.ts +26 -0
- package/src/internal/assembled-engine-profile.ts +22 -0
- package/src/internal/assets-world-plugin.ts +79 -0
- package/src/internal/browser-remote-bridge.ts +267 -0
- package/src/internal/browser-rhi-debug-runtime.ts +67 -0
- package/src/internal/component-introspection.ts +116 -0
- package/src/internal/ecs-import.ts +41 -0
- package/src/internal/engine-profile-common.ts +10 -0
- package/src/internal/error-fanout.ts +129 -0
- package/src/internal/frame-loop.ts +525 -0
- package/src/internal/input-attach.ts +104 -0
- package/src/internal/main-engine-profile.ts +80 -0
- package/src/internal/remote-serve-flag.ts +50 -0
- package/src/internal/remote-server-plugin.ts +16 -0
- package/src/internal/rhi-capture.ts +211 -0
- package/src/internal/rhi-debug-flag.ts +40 -0
- package/src/internal/worker-engine-profile.ts +47 -0
- package/src/load-game-errors.ts +211 -0
- package/src/load-game.ts +115 -0
- package/src/plugin-factories.ts +2 -0
- package/src/tool-preview/bootstrap.ts +848 -0
- package/src/tool-preview/evidence.ts +59 -0
- package/src/tool-preview/framing.ts +52 -0
- package/src/tool-preview/recipe.ts +137 -0
- package/src/types.ts +505 -0
- package/src/vite-env.d.ts +12 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
# @forgeax/engine-app
|
|
2
|
+
|
|
3
|
+
> **App is the browser host adapter: it measures one frame delta, passes it to the World, and draws.** Game scheduling, time resources, fixed-step policy, and gameplay behavior belong to the ECS World.
|
|
4
|
+
|
|
5
|
+
## One-screen takeoff
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createApp } from '@forgeax/engine-app';
|
|
9
|
+
import { Time, Update } from '@forgeax/engine-ecs';
|
|
10
|
+
import { forgeaxBundlerAdapter } from 'virtual:forgeax/bundler';
|
|
11
|
+
|
|
12
|
+
const result = await createApp(canvas, {}, forgeaxBundlerAdapter());
|
|
13
|
+
if (!result.ok) {
|
|
14
|
+
console.error(result.error.code, result.error.hint);
|
|
15
|
+
throw result.error;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const app = result.value;
|
|
19
|
+
app.world.addSystem(Update, {
|
|
20
|
+
name: 'move-player',
|
|
21
|
+
queries: [],
|
|
22
|
+
fn: (world) => {
|
|
23
|
+
const delta = world.getResource(Time).delta;
|
|
24
|
+
movePlayer(delta);
|
|
25
|
+
},
|
|
26
|
+
}).unwrap();
|
|
27
|
+
app.start().unwrap();
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The canvas form creates a World, renderer, default plugins, browser input backend, and rAF loop. Handle the `Result` before calling `start`.
|
|
31
|
+
|
|
32
|
+
## RHI capture
|
|
33
|
+
|
|
34
|
+
When the development RHI-debug flag is enabled, `app.rhiCapture` exposes one
|
|
35
|
+
single-frame `captureFrame()` capability. A successful call returns one
|
|
36
|
+
self-contained `rhi-tape` artifact; pass that same artifact to DevKit's
|
|
37
|
+
`rhi.summary` and `rhi.inspect` operations, using the summary's
|
|
38
|
+
`FrameModel.works[].workIndex` for selection.
|
|
39
|
+
|
|
40
|
+
App owns only the optional capture capability. Replay, readback, PNG output,
|
|
41
|
+
and artifact/file handling remain in the RHI-debug core and DevKit shells, so
|
|
42
|
+
the live App surface does not grow a second replay cache or inspection API.
|
|
43
|
+
|
|
44
|
+
## Execution tiers
|
|
45
|
+
|
|
46
|
+
`execution` moves the complete World, Renderer, AssetRegistry, render features,
|
|
47
|
+
and gameplay plugins into one Engine Worker. The Host keeps DOM input, frame
|
|
48
|
+
credit, Web Audio, and inspection. `shared` adds a lazy persistent Kernel Worker
|
|
49
|
+
pool over shared ECS numeric columns; it does not split the live World or render
|
|
50
|
+
graph across realms.
|
|
51
|
+
|
|
52
|
+
The bootstrap module constructs renderer features and native Cordis plugins
|
|
53
|
+
inside the selected realm. Those plugins receive the real owners through
|
|
54
|
+
`inject`; there is no parallel `run(context)` or cleanup ledger.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// game-bootstrap.ts
|
|
58
|
+
import type { ExecutionBootstrapEntry } from '@forgeax/engine-app';
|
|
59
|
+
import { audioPlugin } from '@forgeax/engine-audio';
|
|
60
|
+
|
|
61
|
+
const bootstrap: ExecutionBootstrapEntry = (data) => ({
|
|
62
|
+
features: [createGameRenderFeature(data)],
|
|
63
|
+
plugins: [
|
|
64
|
+
audioPlugin(),
|
|
65
|
+
createGamePhysicsPlugin(data),
|
|
66
|
+
{
|
|
67
|
+
name: 'game-session',
|
|
68
|
+
inject: ['world', 'renderer', 'assets', 'executionBootstrapHost'],
|
|
69
|
+
async apply(ctx) {
|
|
70
|
+
const session = await createGameSession({
|
|
71
|
+
world: ctx.world,
|
|
72
|
+
renderer: ctx.renderer,
|
|
73
|
+
assets: ctx.assets,
|
|
74
|
+
port: ctx.executionBootstrapHost.port,
|
|
75
|
+
});
|
|
76
|
+
ctx.effect(() => () => session.dispose(), 'game/session');
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export default bootstrap;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const result = await createApp(canvas, {
|
|
87
|
+
execution: {
|
|
88
|
+
tier: 'auto',
|
|
89
|
+
bootstrap: new URL('./game-bootstrap.mjs', import.meta.url),
|
|
90
|
+
bootstrapData: { gameId: 'example' },
|
|
91
|
+
bootstrapPort: realmPort,
|
|
92
|
+
},
|
|
93
|
+
}, forgeaxBundlerAdapter());
|
|
94
|
+
if (!result.ok) throw result.error;
|
|
95
|
+
|
|
96
|
+
const app = result.value;
|
|
97
|
+
app.start().unwrap();
|
|
98
|
+
const report = app.execution.report();
|
|
99
|
+
console.log(report.requestedTier, report.actualTier, report.selectionReason);
|
|
100
|
+
|
|
101
|
+
if (report.world.health === 'poisoned') {
|
|
102
|
+
const rebuilt = await app.execution.rebuild();
|
|
103
|
+
if (!rebuilt.ok) throw rebuilt.error;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```mermaid
|
|
108
|
+
flowchart LR
|
|
109
|
+
H["Host: DOM UI, input, frame credit, Web Audio"] <--> P["Typed MessagePort"]
|
|
110
|
+
P <--> E["Engine realm: World, Renderer, Assets, game bootstrap"]
|
|
111
|
+
E --> K["Kernel Workers: eligible QuerySpan shards"]
|
|
112
|
+
K --> E
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
| Requested tier | Runtime shape | Selection rule |
|
|
116
|
+
|:--|:--|:--|
|
|
117
|
+
| `main-serial` | Host-owned World and Renderer | Always available |
|
|
118
|
+
| `engine-worker` | Co-located Engine Worker | Requires Worker, OffscreenCanvas, and Worker WebGPU |
|
|
119
|
+
| `shared` | Engine Worker plus SAB Kernel pool | Also requires isolation headers, SharedArrayBuffer, and Atomics wait |
|
|
120
|
+
| `auto` | Best available proven tier | Reports the actual tier and reason; never disguises fallback |
|
|
121
|
+
|
|
122
|
+
An explicit unavailable tier returns a structured `AppError`; only `auto` falls back. Serve `shared` with `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp` or `credentialless`, then verify the Worker-realm facts in `app.execution.report()`. Every SharedKernel module is imported, export-checked, and retained in every lane before the Engine Worker reports ready; frame jobs invoke that retained module synchronously, so an invalid module fails before the first shared write without adding a dynamic-import Promise to each dispatch. A partial Kernel write poisons the World, stops update/draw, and requires explicit rebuild to obtain a new World identity.
|
|
123
|
+
|
|
124
|
+
`bootstrapData` must be structured-cloneable and is validated before a canvas is
|
|
125
|
+
transferred. `bootstrapPort` is the realm side of a host-created
|
|
126
|
+
`MessageChannel`; `executionBootstrapHostPlugin` provides it and closes it with
|
|
127
|
+
the execution Fiber. Keep DOM UI on the Host side of that typed channel.
|
|
128
|
+
`ExecutionBootstrapHost.setPointerLockAllowed` is the one built-in
|
|
129
|
+
realm-to-Host control because browser input ownership remains on the Host.
|
|
130
|
+
|
|
131
|
+
When `execution` is present, realm-bound `CreateAppOptions` (`features`,
|
|
132
|
+
`plugins`, RHI injection, draw source, membership
|
|
133
|
+
timing, and bundler import transport) are rejected instead of working only in a
|
|
134
|
+
`main-serial` fallback. Construct them in the bootstrap module so `auto` has one
|
|
135
|
+
game assembly path in every selected tier.
|
|
136
|
+
|
|
137
|
+
The machine-readable report contract is [`schema/execution-report.schema.json`](./schema/execution-report.schema.json). Shared Kernel eligibility and storage rules are owned by [`@forgeax/engine-ecs`](../ecs). The production reference and benchmark commands are in [`hello/multithreaded-execution`](../../apps/hello/multithreaded-execution).
|
|
138
|
+
|
|
139
|
+
## Renderer feature passthrough
|
|
140
|
+
|
|
141
|
+
`CreateAppOptions.membershipTiming` is a transparent Render option. App does
|
|
142
|
+
not timestamp frames or own timing reasons; it forwards the value to Runtime
|
|
143
|
+
and Render. Omit it for zero timing work, use `cpu-control` for the independent
|
|
144
|
+
CPU control path, or use `gpu` for bounded backend-aware evidence.
|
|
145
|
+
|
|
146
|
+
`CreateAppOptions.features` is the transparent app seam for producer-owned
|
|
147
|
+
renderer features. The array is forwarded to the existing renderer options
|
|
148
|
+
without reordering, copying, or adding an App-level VFX branch. A feature host
|
|
149
|
+
therefore remains the owner of its feature and lifecycle:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import { createApp } from '@forgeax/engine-app';
|
|
153
|
+
import { createVfxRuntimeHost } from '@forgeax/engine-vfx-render';
|
|
154
|
+
import { vfxGpuEffectContribution } from '@forgeax/engine-vfx';
|
|
155
|
+
|
|
156
|
+
declare const canvas: HTMLCanvasElement;
|
|
157
|
+
declare const camera: import('@forgeax/engine-vfx-render').ParticleRenderCameraSource;
|
|
158
|
+
declare const bundler: import('@forgeax/engine-app').BundlerOptions;
|
|
159
|
+
|
|
160
|
+
const vfxHost = createVfxRuntimeHost({ camera });
|
|
161
|
+
const result = await createApp(
|
|
162
|
+
canvas,
|
|
163
|
+
{
|
|
164
|
+
features: [vfxHost.feature],
|
|
165
|
+
assetDecoders: [vfxGpuEffectContribution],
|
|
166
|
+
},
|
|
167
|
+
bundler,
|
|
168
|
+
);
|
|
169
|
+
if (!result.ok) {
|
|
170
|
+
console.error(result.error.code, result.error.hint);
|
|
171
|
+
throw result.error;
|
|
172
|
+
}
|
|
173
|
+
result.value.start().unwrap();
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The app does not attach a VFX World or registry. Call
|
|
177
|
+
`vfxHost.attachWorld({ world, assets })` before the first update and
|
|
178
|
+
`vfxHost.detachWorld({ world })` during teardown. Inspect structured Result
|
|
179
|
+
errors by `code`, `expected`, `hint`, and `detail`; do not treat a successful App
|
|
180
|
+
construction as proof that a particle asset is ready or visible.
|
|
181
|
+
|
|
182
|
+
The App default assembly includes a device-neutral `particle-effect` decoder.
|
|
183
|
+
VFX rendering selects the artifact-backed GPU owner explicitly with
|
|
184
|
+
`assetDecoders: [vfxGpuEffectContribution]`; the host then shares that decoder
|
|
185
|
+
lease instead of installing a competing kind.
|
|
186
|
+
|
|
187
|
+
## Frame-loop responsibility
|
|
188
|
+
|
|
189
|
+
Every frame follows one host-owned sequence:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
measured deltaSeconds -> world.update(deltaSeconds) -> renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 })
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The host measures the delta once and forwards that same value to its World. A `World` validates the delta, owns `Time` and `FixedTime`, runs its `Update` and `FixedUpdate` schedules, and applies its own time policy. App does not maintain an elapsed clock, clamp time, register frame callbacks, or offer a second scheduling surface.
|
|
196
|
+
|
|
197
|
+
`app.onError` receives structured failures from the World update and renderer draw paths.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
const unlisten = app.onError((error) => {
|
|
201
|
+
console.error(error.code, error.hint);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const started = app.start();
|
|
205
|
+
if (!started.ok) console.error(started.error.code, started.error.hint);
|
|
206
|
+
|
|
207
|
+
// Pause scheduling without destroying the realm:
|
|
208
|
+
unlisten();
|
|
209
|
+
app.stop();
|
|
210
|
+
|
|
211
|
+
// Final ownership release:
|
|
212
|
+
await app.dispose();
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Hosts that discover additional Worlds during bootstrap can update the routing pull
|
|
216
|
+
without creating a second frame loop:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
app.setDrawSource(() => ({
|
|
220
|
+
worlds: [app.world, overlayWorld],
|
|
221
|
+
cameraOwner: 0,
|
|
222
|
+
resourceOwner: 0,
|
|
223
|
+
}));
|
|
224
|
+
// `app.setDrawSource(undefined)` restores the single-world path.
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The injected Worlds are updated by the same frame loop before the renderer draw;
|
|
228
|
+
the setter changes only draw routing, while each World retains its own time policy.
|
|
229
|
+
|
|
230
|
+
## Opt-in CPU profiling
|
|
231
|
+
|
|
232
|
+
Performance tooling passes one `Profiler` capability through the canvas or assemble options. App
|
|
233
|
+
and Render write bounded records into that capability only while a capture is active; default App
|
|
234
|
+
construction has no profiler work and no capture artifact.
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
import { createProfiler } from '@forgeax/engine-profiler';
|
|
238
|
+
|
|
239
|
+
const profiler = createProfiler();
|
|
240
|
+
const result = await createApp({ renderer, world, profiler });
|
|
241
|
+
if (!result.ok) throw result.error;
|
|
242
|
+
|
|
243
|
+
const started = profiler.startCapture({ frameLimit: 120, eventLimit: 1024 });
|
|
244
|
+
if (!started.ok) throw started.error;
|
|
245
|
+
// Run the App for the requested frames, then finish the bounded session.
|
|
246
|
+
const capture = started.value.finish();
|
|
247
|
+
if (!capture.ok) throw capture.error;
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Read `profiler.phaseCatalog` for the owner-declared App and Render relation. Use
|
|
251
|
+
`validateProfileCapture(capture.value)` before persisting or passing an artifact to the CLI. The
|
|
252
|
+
profiler is a CPU diagnostic capability; it does not replace ECS schedules, GPU timestamps, or a
|
|
253
|
+
browser UI.
|
|
254
|
+
|
|
255
|
+
## Time policy
|
|
256
|
+
|
|
257
|
+
Canvas-form callers configure the World time policy when they create the App.
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
const result = await createApp(canvas, {
|
|
261
|
+
time: {
|
|
262
|
+
fixedDeltaSeconds: 1 / 60,
|
|
263
|
+
maxStepsPerUpdate: 4,
|
|
264
|
+
maxDeltaSeconds: 0.1,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Systems read time through ECS resources:
|
|
270
|
+
|
|
271
|
+
- `Time.delta`: validated variable-rate seconds for the current frame.
|
|
272
|
+
- `Time.elapsed`: accumulated validated variable-rate seconds.
|
|
273
|
+
- `FixedTime.delta`: fixed simulation interval.
|
|
274
|
+
- `FixedTime.tick`: completed fixed updates.
|
|
275
|
+
- `FixedTime.overstep`: seconds accrued toward the next fixed update.
|
|
276
|
+
- `FixedTime.droppedSeconds` and `FixedTime.droppedUpdates`: explicit metrics when the configured catch-up cap truncates work.
|
|
277
|
+
|
|
278
|
+
The assemble form preserves the injected World's policy. Create that World before assembly instead of passing a competing app option.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
import { World } from '@forgeax/engine-ecs';
|
|
282
|
+
import { createApp } from '@forgeax/engine-app';
|
|
283
|
+
|
|
284
|
+
const world = new World({ time: { fixedDeltaSeconds: 1 / 120, maxStepsPerUpdate: 8 } });
|
|
285
|
+
const result = await createApp({ renderer, world, plugins: [myPlugin] });
|
|
286
|
+
if (!result.ok) throw result.error;
|
|
287
|
+
result.value.start().unwrap();
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Callback deletion migration
|
|
291
|
+
|
|
292
|
+
`registerUpdate` is deleted. Convert each former callback into a named ECS system and select its schedule explicitly.
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
import { Time, Update, defineSystem } from '@forgeax/engine-ecs';
|
|
296
|
+
|
|
297
|
+
const AnimateHud = defineSystem({
|
|
298
|
+
name: 'animate-hud',
|
|
299
|
+
queries: [],
|
|
300
|
+
fn: (world) => updateHud(Math.sin(world.getResource(Time).elapsed)),
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
app.world.addSystem(Update, AnimateHud).unwrap();
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Use `FixedUpdate` for deterministic simulation.
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
import { FixedUpdate } from '@forgeax/engine-ecs';
|
|
310
|
+
|
|
311
|
+
app.world.addSystem(FixedUpdate, {
|
|
312
|
+
name: 'step-combat',
|
|
313
|
+
queries: [],
|
|
314
|
+
fn: () => stepCombat(),
|
|
315
|
+
}).unwrap();
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Schedule ordering is ECS data. Use `before`, `after`, system sets, and token-first mutation APIs rather than a callback list.
|
|
319
|
+
|
|
320
|
+
## Input and plugins
|
|
321
|
+
|
|
322
|
+
The canvas form inserts the input backend and activates its scan system on `Update` before user systems. Gameplay systems consume the frozen `InputSnapshot`; they do not install raw browser event listeners.
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
import { INPUT_SNAPSHOT_RESOURCE_KEY, type InputSnapshot } from '@forgeax/engine-input';
|
|
326
|
+
import { Update, defineSystem } from '@forgeax/engine-ecs';
|
|
327
|
+
|
|
328
|
+
const ReadInput = defineSystem({
|
|
329
|
+
name: 'read-input',
|
|
330
|
+
queries: [],
|
|
331
|
+
fn: (world) => {
|
|
332
|
+
const input = world.getResource<InputSnapshot>(INPUT_SNAPSHOT_RESOURCE_KEY);
|
|
333
|
+
if (input.keyboard.down('KeyW')) moveForward();
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
app.world.addSystem(Update, ReadInput).unwrap();
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Pass optional capabilities as native Cordis plugins. Providers are explicit:
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
import { audioPlugin } from '@forgeax/engine-audio';
|
|
343
|
+
import { webAudioPlugin } from '@forgeax/engine-audio-webaudio';
|
|
344
|
+
import { physicsPlugin } from '@forgeax/engine-physics';
|
|
345
|
+
|
|
346
|
+
const result = await createApp(canvas, {
|
|
347
|
+
plugins: [webAudioPlugin(), audioPlugin(), physicsPlugin('rapier-3d')],
|
|
348
|
+
});
|
|
349
|
+
if (!result.ok) throw result.error;
|
|
350
|
+
|
|
351
|
+
const feature = await result.value.pluginContext.plugin(optionalGameplayFeature);
|
|
352
|
+
await feature.dispose();
|
|
353
|
+
await result.value.dispose();
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Every App owns one `pluginContext`. Cordis `inject`, `provide`, `effect`, and
|
|
357
|
+
`Fiber` are the only composition lifecycle. `stop()` controls frame scheduling;
|
|
358
|
+
`dispose()` drains plugin effects and releases Host/renderer ownership. An
|
|
359
|
+
assemble-form host still owns the World and renderer objects it supplied, while
|
|
360
|
+
the App owns the Cordis realm it assembled around them.
|
|
361
|
+
|
|
362
|
+
## API index
|
|
363
|
+
|
|
364
|
+
| Entry | Shape | Purpose |
|
|
365
|
+
|:--|:--|:--|
|
|
366
|
+
| `createApp(canvas, options?, bundler?)` | `Promise<Result<App, CanvasAppError>>` | Creates the canvas-form World, renderer, plugins, input, and frame loop. |
|
|
367
|
+
| `createApp({ renderer, world, plugins?, ... })` | `Promise<Result<App, AssembleAppError>>` | Assembles host-owned renderer and World without replacing their policy. |
|
|
368
|
+
| `CreateAppOptions.time` | `TimePolicy` | Policy used only for the newly created canvas-form World. |
|
|
369
|
+
| `CreateAppOptions.features` | `readonly RenderFeature<unknown>[]` | Existing renderer feature seam, forwarded by reference and order. |
|
|
370
|
+
| `CreateAppOptions.execution` | `ExecutionOptions` | Selects `auto`, `main-serial`, `engine-worker`, or `shared` and names the bootstrap module. |
|
|
371
|
+
| `App.execution.report()` | `ExecutionReport` | Returns the schema-valid requested/actual tier, capabilities, health, performance, audio, and fault projection. |
|
|
372
|
+
| `App.execution.rebuild()` | `Promise<Result<ExecutionReport, AppError>>` | Rebuilds only a poisoned Worker World with a new identity. |
|
|
373
|
+
| `App.start()` | `Result<void, AppError>` | Arms the rAF loop. |
|
|
374
|
+
| `App.stop()` / `pause()` / `resume()` | `Result<void, AppError>` | Controls the rAF lifecycle. |
|
|
375
|
+
| `App.dispose()` | `Promise<Result<void, AppError>>` | Drains the Cordis realm, Host resources, and renderer ownership. |
|
|
376
|
+
| `App.pluginContext` | `Context` | Native Cordis realm for runtime and asset-resident game plugins. |
|
|
377
|
+
| `App.stepFrame(deltaSeconds)` | `Result<void, AppDispatchError>` | While paused, advances one deterministic update/draw frame through the same App frame authority used by rAF. |
|
|
378
|
+
| `App.releaseSurfacePreserveWorld()` / `restoreSurface()` | `Promise<Result<void, RhiError>>` | Temporarily pauses presentation and relinquishes the canvas surface while preserving the same World, Renderer, registry, and execution authority; restore resumes only a loop that was running before release. |
|
|
379
|
+
| `App.onError(callback)` | `() => void` | Subscribes to structured World and renderer failures. |
|
|
380
|
+
| `App.setDrawSource(drawSource)` | `void` | Replaces per-frame multi-world routing; `undefined` restores the single-world path. |
|
|
381
|
+
| `App.world` / `App.renderer` | readonly | Exposes the assembled ECS and renderer instances. |
|
|
382
|
+
|
|
383
|
+
## Boundaries
|
|
384
|
+
|
|
385
|
+
- `createApp` returns `Result`; inspect `.ok`, `.error.code`, and `.error.hint` rather than swallowing failures.
|
|
386
|
+
- `createRenderer` is the lower-level route. Its host is responsible for `world.update(deltaSeconds)` and renderer drawing.
|
|
387
|
+
- Demo motion failures are engine or schedule integration failures. Do not restore a demo-local callback or manual frame loop workaround.
|
|
388
|
+
- Deterministic preview and tooling seeks must pause the App and use `stepFrame`; they must not call `world.update` or `renderer.draw` as a parallel frame path.
|
|
389
|
+
- `Camera.clearColor` belongs to the Camera component, and bundler wiring belongs to `BundlerOptions`; neither is an App time responsibility.
|
|
390
|
+
|
|
391
|
+
See `packages/app/src/types.ts` for option and Result types, `packages/app/src/internal/frame-loop.ts` for the frame-loop implementation, `packages/plugin/README.md` for the Cordis lifecycle, and `packages/ecs/README.md` for World schedule and time semantics.
|
|
392
|
+
|
|
393
|
+
## Remote component discovery
|
|
394
|
+
|
|
395
|
+
Quick start in a Node or dawn-node host:
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
import { createApp } from '@forgeax/engine-app';
|
|
399
|
+
|
|
400
|
+
process.env.FORGEAX_ENGINE_REMOTE_SERVE = '1';
|
|
401
|
+
const result = await createApp({ world, renderer });
|
|
402
|
+
// Use the existing WS client to call the existing introspect method.
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
The app host derives JSON-safe descriptors from the global ECS component
|
|
406
|
+
registry after plugins build. It injects those descriptors into the existing
|
|
407
|
+
remote `introspect` response; app does not define, validate, or own a component.
|
|
408
|
+
|
|
409
|
+
| Boundary | Contract | Recovery |
|
|
410
|
+
|:--|:--|:--|
|
|
411
|
+
| App -> remote | `startServer({ introspection })` carries data only | If remote is absent, verify dev mode or the explicit headless env flag |
|
|
412
|
+
| Remote -> consumer | Existing `eval` and `introspect` methods remain the full surface | Use the returned `RemoteError` fields, never message parsing |
|
|
413
|
+
| ECS/render | Registry and `Visibility` remain package-owned | Use `_import('@forgeax/engine-render')` in eval, not app-local labels |
|
|
414
|
+
|
|
415
|
+
The descriptor is a transport projection, not a live token: it contains schema,
|
|
416
|
+
field reflection, labels, and JSON-safe metadata, but no methods or validator
|
|
417
|
+
functions. Camera, picking, lifecycle, assets, and VFX shadow policy remain
|
|
418
|
+
outside the app host.
|