@vgai/engine 0.5.22 → 0.5.24
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 +6 -3
- package/dist/adapter/adapter-module.d.ts.map +1 -1
- package/dist/adapter/adapter-module.js +2 -4
- package/dist/adapter/adapter-surface.d.ts +1 -1
- package/dist/adapter/adapter-surface.js +1 -1
- package/dist/adapter/authoring.d.ts +19 -21
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/authoring.js +2 -2
- package/dist/adapter/binding.d.ts +341 -0
- package/dist/adapter/binding.d.ts.map +1 -0
- package/dist/adapter/binding.js +148 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -1
- package/dist/adapter/colyseus-networking-adapter.js +23 -4
- package/dist/adapter/entrypoint-selection-readers.d.ts +24 -0
- package/dist/adapter/entrypoint-selection-readers.d.ts.map +1 -0
- package/dist/adapter/entrypoint-selection-readers.js +63 -0
- package/dist/adapter/entrypoint-selection-source.d.ts.map +1 -1
- package/dist/adapter/entrypoint-selection-source.js +1 -44
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -1
- package/dist/adapter/finders/scenes-from-entrypoint-selection.js +1 -52
- package/dist/adapter/host-context.d.ts +46 -15
- package/dist/adapter/host-context.d.ts.map +1 -1
- package/dist/adapter/host-context.js +2 -9
- package/dist/adapter/index.d.ts +11 -12
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +9 -10
- package/dist/adapter/ingest/game-contract-seams.d.ts +5 -0
- package/dist/adapter/ingest/game-contract-seams.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract-seams.js +1 -0
- package/dist/adapter/ingest/game-contract.d.ts +22 -3
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +0 -3
- package/dist/adapter/ingest/scene-capture.d.ts +19 -23
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +143 -17
- package/dist/adapter/ingest/visible-capture-window.d.ts +34 -0
- package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
- package/dist/adapter/native-debug-module.d.ts +40 -5
- package/dist/adapter/native-debug-module.d.ts.map +1 -1
- package/dist/adapter/native-debug-module.js +36 -9
- package/dist/adapter/rapier-physics-adapter.d.ts +31 -1
- package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -1
- package/dist/adapter/rapier-physics-adapter.js +50 -36
- package/dist/adapter/renderer-config.d.ts +2 -2
- package/dist/adapter/renderer-config.js +2 -2
- package/dist/adapter/root-adapter.d.ts +7 -7
- package/dist/adapter/root-adapter.js +4 -4
- package/dist/adapter/system-adapter.d.ts +45 -7
- package/dist/adapter/system-adapter.d.ts.map +1 -1
- package/dist/adapter/system-seam-contract.d.ts +3 -3
- package/dist/adapter/system-seam-contract.js +3 -3
- package/dist/adapter/system-slot.d.ts +168 -0
- package/dist/adapter/system-slot.d.ts.map +1 -0
- package/dist/adapter/system-slot.js +229 -0
- package/dist/adapter/transform.d.ts +11 -1
- package/dist/adapter/transform.d.ts.map +1 -1
- package/dist/ai/navigation.d.ts +17 -1
- package/dist/ai/navigation.d.ts.map +1 -1
- package/dist/ai/navigation.js +26 -5
- package/dist/animation/anim-graph-types.d.ts +11 -3
- package/dist/animation/anim-graph-types.d.ts.map +1 -1
- package/dist/animation/theatre-clock-binding.d.ts +4 -4
- package/dist/animation/theatre-clock-binding.js +4 -4
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
- package/dist/animation/xstate-animation-binding.js +2 -2
- package/dist/animation/xstate-animation-meta.d.ts +13 -0
- package/dist/animation/xstate-animation-meta.d.ts.map +1 -1
- package/dist/animation/xstate-animation-meta.js +14 -0
- package/dist/asset-formats/index.d.ts +4 -7
- package/dist/asset-formats/index.d.ts.map +1 -1
- package/dist/asset-formats/index.js +4 -7
- package/dist/asset-formats/render-env.d.ts +5 -8
- package/dist/asset-formats/render-env.d.ts.map +1 -1
- package/dist/asset-formats/render-env.js +3 -6
- package/dist/asset-parse-error.d.ts +2 -5
- package/dist/asset-parse-error.d.ts.map +1 -1
- package/dist/asset-parse-error.js +2 -5
- package/dist/audio/bus-mixer.d.ts +101 -0
- package/dist/audio/bus-mixer.d.ts.map +1 -0
- package/dist/audio/bus-mixer.js +115 -0
- package/dist/core/frame-pacing.d.ts +1 -1
- package/dist/core/frame-pacing.js +2 -2
- package/dist/core/game-loop.d.ts +1 -3
- package/dist/core/game-loop.d.ts.map +1 -1
- package/dist/core/game-loop.js +1 -3
- package/dist/core/seeded-random.d.ts +1 -1
- package/dist/core/sim-clock.d.ts +5 -6
- package/dist/core/sim-clock.d.ts.map +1 -1
- package/dist/core/sim-clock.js +4 -5
- package/dist/core/types.d.ts +1 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/defaults.d.ts +6 -14
- package/dist/defaults.d.ts.map +1 -1
- package/dist/defaults.js +6 -14
- package/dist/dev/register-render-vitals.d.ts +1 -4
- package/dist/dev/register-render-vitals.d.ts.map +1 -1
- package/dist/dev/register-render-vitals.js +1 -4
- package/dist/dev/render-debug-adapter.d.ts +2 -3
- package/dist/dev/render-debug-adapter.d.ts.map +1 -1
- package/dist/dev/render-debug-adapter.js +2 -3
- package/dist/dev/render-vitals.d.ts +3 -3
- package/dist/dev/render-vitals.js +3 -3
- package/dist/dev/webgl-frame-capture.d.ts +1 -1
- package/dist/dev/webgl-frame-capture.js +1 -1
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -4
- package/dist/input/host-pointer.d.ts +122 -0
- package/dist/input/host-pointer.d.ts.map +1 -0
- package/dist/input/host-pointer.js +160 -0
- package/dist/input/input-manager.d.ts +18 -5
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +33 -13
- package/dist/input/rebind-controller.d.ts.map +1 -1
- package/dist/input/rebind-controller.js +6 -8
- package/dist/input/schema.d.ts.map +1 -1
- package/dist/input/schema.js +56 -28
- package/dist/manifest/filename.d.ts.map +1 -1
- package/dist/manifest/filename.js +8 -12
- package/dist/manifest/load.d.ts +10 -10
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +9 -6
- package/dist/manifest/schema.d.ts +17 -21
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +45 -35
- package/dist/physics/collider-dimensions.d.ts +8 -12
- package/dist/physics/collider-dimensions.d.ts.map +1 -1
- package/dist/physics/collider-dimensions.js +8 -12
- package/dist/pixi/scene-capture.d.ts +11 -13
- package/dist/pixi/scene-capture.d.ts.map +1 -1
- package/dist/react/world-state.d.ts +1 -1
- package/dist/react/world-state.d.ts.map +1 -1
- package/dist/render/light-camera-factory.d.ts +5 -7
- package/dist/render/light-camera-factory.d.ts.map +1 -1
- package/dist/render/light-camera-factory.js +8 -11
- package/dist/render/material-factory.js +1 -1
- package/dist/render/render-batch-system.d.ts.map +1 -1
- package/dist/render/render-features.d.ts +17 -6
- package/dist/render/render-features.d.ts.map +1 -1
- package/dist/render/render-features.js +0 -28
- package/dist/runtime/create-runtime.d.ts +34 -25
- package/dist/runtime/create-runtime.d.ts.map +1 -1
- package/dist/runtime/create-runtime.js +218 -93
- package/dist/runtime/debug-bridge.d.ts +12 -0
- package/dist/runtime/debug-bridge.d.ts.map +1 -1
- package/dist/runtime/debug-bridge.js +4 -0
- package/dist/runtime/debug-registry.d.ts +95 -8
- package/dist/runtime/debug-registry.d.ts.map +1 -1
- package/dist/runtime/debug-registry.js +24 -3
- package/dist/runtime/dev-build.d.ts +2 -2
- package/dist/runtime/dev-build.js +2 -2
- package/dist/runtime/game-input-seams.d.ts +2 -2
- package/dist/runtime/game-input-seams.d.ts.map +1 -1
- package/dist/runtime/game.d.ts +102 -41
- package/dist/runtime/game.d.ts.map +1 -1
- package/dist/runtime/game.js +80 -54
- package/dist/runtime/mount-game.d.ts +0 -16
- package/dist/runtime/mount-game.d.ts.map +1 -1
- package/dist/runtime/mount-game.js +8 -39
- package/dist/runtime/mount-manifest.d.ts +22 -14
- package/dist/runtime/mount-manifest.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.js +18 -18
- package/dist/runtime/playtest.d.ts +22 -0
- package/dist/runtime/playtest.d.ts.map +1 -0
- package/dist/runtime/playtest.js +12 -0
- package/dist/runtime/run-ticks-settled.d.ts +34 -0
- package/dist/runtime/run-ticks-settled.d.ts.map +1 -0
- package/dist/runtime/run-ticks-settled.js +59 -0
- package/dist/runtime/state-bridge.d.ts +2 -3
- package/dist/runtime/state-bridge.d.ts.map +1 -1
- package/dist/runtime/state-bridge.js +1 -0
- package/dist/setup/setup-audio.d.ts +12 -0
- package/dist/setup/setup-audio.d.ts.map +1 -1
- package/dist/setup/setup-audio.js +9 -10
- package/dist/setup/setup-renderer.d.ts +2 -25
- package/dist/setup/setup-renderer.d.ts.map +1 -1
- package/dist/setup/setup-renderer.js +2 -31
- package/dist/world3d-react/r3f-root-factory.d.ts +7 -7
- package/dist/world3d-react/r3f-root-factory.js +7 -7
- package/dist/world3d-react/rapier-physics-bridge.d.ts +9 -8
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
- package/dist/world3d-react/rapier-physics-bridge.js +100 -48
- package/package.json +1 -1
- package/schemas/engine-capabilities.json +16 -14
- package/schemas/vgai-project.schema.json +35 -26
- package/src/adapter/adapter-module.ts +2 -4
- package/src/adapter/adapter-surface.ts +1 -1
- package/src/adapter/authoring.ts +19 -21
- package/src/adapter/binding.ts +468 -0
- package/src/adapter/colyseus-networking-adapter.ts +20 -5
- package/src/adapter/entrypoint-selection-readers.ts +66 -0
- package/src/adapter/entrypoint-selection-source.ts +1 -40
- package/src/adapter/finders/scenes-from-entrypoint-selection.ts +1 -48
- package/src/adapter/host-context.ts +45 -15
- package/src/adapter/index.ts +23 -11
- package/src/adapter/ingest/game-contract-seams.ts +1 -0
- package/src/adapter/ingest/game-contract.ts +22 -3
- package/src/adapter/ingest/scene-capture.ts +190 -39
- package/src/adapter/ingest/visible-capture-window.ts +35 -0
- package/src/adapter/native-debug-module.ts +66 -9
- package/src/adapter/rapier-physics-adapter.ts +76 -20
- package/src/adapter/renderer-config.ts +2 -2
- package/src/adapter/root-adapter.ts +7 -7
- package/src/adapter/system-adapter.ts +43 -8
- package/src/adapter/system-seam-contract.ts +3 -3
- package/src/adapter/system-slot.ts +291 -0
- package/src/adapter/transform.ts +18 -1
- package/src/ai/navigation.ts +30 -3
- package/src/animation/anim-graph-types.ts +11 -3
- package/src/animation/theatre-clock-binding.ts +4 -4
- package/src/animation/xstate-animation-binding.ts +2 -2
- package/src/animation/xstate-animation-meta.ts +16 -0
- package/src/asset-formats/index.ts +4 -7
- package/src/asset-formats/render-env.ts +3 -6
- package/src/asset-parse-error.ts +2 -5
- package/src/audio/bus-mixer.ts +161 -0
- package/src/core/frame-pacing.ts +2 -2
- package/src/core/game-loop.ts +1 -3
- package/src/core/seeded-random.ts +1 -1
- package/src/core/sim-clock.ts +5 -6
- package/src/core/types.ts +1 -3
- package/src/defaults.ts +6 -14
- package/src/dev/register-render-vitals.ts +1 -4
- package/src/dev/render-debug-adapter.ts +2 -3
- package/src/dev/render-vitals.ts +3 -3
- package/src/dev/webgl-frame-capture.ts +1 -1
- package/src/index.ts +2 -5
- package/src/input/host-pointer.ts +230 -0
- package/src/input/input-manager.ts +34 -13
- package/src/input/input-types.ts +1 -1
- package/src/input/rebind-controller.ts +6 -8
- package/src/input/schema.ts +216 -188
- package/src/manifest/filename.ts +8 -12
- package/src/manifest/load.ts +17 -13
- package/src/manifest/schema.ts +55 -47
- package/src/physics/collider-dimensions.ts +8 -12
- package/src/pixi/scene-capture.ts +12 -15
- package/src/react/world-state.tsx +1 -1
- package/src/render/light-camera-factory.ts +8 -11
- package/src/render/material-factory.ts +1 -1
- package/src/render/render-batch-system.ts +14 -6
- package/src/render/render-features.ts +17 -35
- package/src/runtime/create-runtime.ts +270 -108
- package/src/runtime/debug-bridge.ts +16 -0
- package/src/runtime/debug-registry.ts +121 -8
- package/src/runtime/dev-build.ts +2 -2
- package/src/runtime/game-input-seams.ts +2 -2
- package/src/runtime/game.ts +180 -80
- package/src/runtime/mount-game.ts +8 -56
- package/src/runtime/mount-manifest.ts +43 -34
- package/src/runtime/playtest.ts +22 -0
- package/src/runtime/run-ticks-settled.ts +72 -0
- package/src/runtime/state-bridge.ts +3 -3
- package/src/setup/setup-audio.ts +21 -11
- package/src/setup/setup-renderer.ts +2 -61
- package/src/world3d-react/r3f-root-factory.tsx +7 -7
- package/src/world3d-react/rapier-physics-bridge.tsx +107 -50
- package/dist/adapter/setup-three-root-adapter.d.ts +0 -86
- package/dist/adapter/setup-three-root-adapter.d.ts.map +0 -1
- package/dist/adapter/setup-three-root-adapter.js +0 -908
- package/dist/animation/clip-map.d.ts +0 -12
- package/dist/animation/clip-map.d.ts.map +0 -1
- package/dist/animation/clip-map.js +0 -31
- package/dist/asset-registry.d.ts +0 -38
- package/dist/asset-registry.d.ts.map +0 -1
- package/dist/asset-registry.js +0 -66
- package/dist/canvas-react/engine-bridge.d.ts +0 -45
- package/dist/canvas-react/engine-bridge.d.ts.map +0 -1
- package/dist/canvas-react/engine-bridge.js +0 -45
- package/dist/canvas-react/pixi-react-adapter.d.ts +0 -77
- package/dist/canvas-react/pixi-react-adapter.d.ts.map +0 -1
- package/dist/canvas-react/pixi-react-adapter.js +0 -294
- package/dist/canvas-react/world-context.d.ts +0 -98
- package/dist/canvas-react/world-context.d.ts.map +0 -1
- package/dist/canvas-react/world-context.js +0 -173
- package/dist/dev/debug-draw.d.ts +0 -24
- package/dist/dev/debug-draw.d.ts.map +0 -1
- package/dist/dev/debug-draw.js +0 -73
- package/dist/render/auto-batcher.d.ts +0 -34
- package/dist/render/auto-batcher.d.ts.map +0 -1
- package/dist/render/auto-batcher.js +0 -140
- package/dist/render/lod.d.ts +0 -13
- package/dist/render/lod.d.ts.map +0 -1
- package/dist/render/lod.js +0 -16
- package/dist/runtime/types.d.ts +0 -303
- package/dist/runtime/types.d.ts.map +0 -1
- package/dist/runtime/types.js +0 -1
- package/dist/world3d-react/engine-bridge.d.ts +0 -47
- package/dist/world3d-react/engine-bridge.d.ts.map +0 -1
- package/dist/world3d-react/engine-bridge.js +0 -73
- package/dist/world3d-react/r3f-adapter.d.ts +0 -58
- package/dist/world3d-react/r3f-adapter.d.ts.map +0 -1
- package/dist/world3d-react/r3f-adapter.js +0 -634
- package/dist/world3d-react/world-context.d.ts +0 -182
- package/dist/world3d-react/world-context.d.ts.map +0 -1
- package/dist/world3d-react/world-context.js +0 -235
- package/src/adapter/setup-three-root-adapter.ts +0 -1032
- package/src/animation/clip-map.ts +0 -34
- package/src/asset-registry.ts +0 -89
- package/src/dev/debug-draw.ts +0 -80
- package/src/render/auto-batcher.ts +0 -168
- package/src/render/lod.ts +0 -17
- package/src/runtime/types.ts +0 -328
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
// callers register, but it registers NONE itself. In particular there is no
|
|
13
13
|
// built-in 'canvas'/'react' registration here (that would require this file
|
|
14
14
|
// to value-import `pixi.js`/`react`/`react-dom`, exactly what `mount-manifest
|
|
15
|
-
// .ts` forbids); a project that has a canvas or react world MUST
|
|
16
|
-
// factory for that kind itself —
|
|
17
|
-
//
|
|
18
|
-
//
|
|
15
|
+
// .ts` forbids); a project that has a three, canvas, or react world MUST
|
|
16
|
+
// register a factory for that kind itself — the factories live with the
|
|
17
|
+
// modules that own their dependencies (`r3fRootFactory` in
|
|
18
|
+
// `@engine/world3d-react`, its Pixi twin in `@engine/canvas-react`), never
|
|
19
|
+
// wired up here automatically.
|
|
19
20
|
|
|
20
21
|
import { declaredRoots } from '../adapter/manifest-interpreter';
|
|
21
22
|
import {
|
|
@@ -26,12 +27,10 @@ import {
|
|
|
26
27
|
nativeDebugBindingFromEntryModule,
|
|
27
28
|
nativeSystemsBindingFromEntryModule,
|
|
28
29
|
} from '../adapter/native-debug-module';
|
|
29
|
-
import type { RootAdapter } from '../adapter/root-adapter';
|
|
30
30
|
import { publishDevInstruments } from '../dev/instruments';
|
|
31
31
|
import type { ResolvedAdapterRoot } from '../manifest/load';
|
|
32
32
|
import type { GameSession } from './create-runtime';
|
|
33
33
|
import { type MountEntry, mountManifestRoots, resolveManifest } from './mount-manifest';
|
|
34
|
-
import type { GameSetupFn } from './types';
|
|
35
34
|
import { assertExportedOrInEditor } from './unexported-game-trap';
|
|
36
35
|
|
|
37
36
|
// ---------------------------------------------------------------------------
|
|
@@ -149,50 +148,6 @@ export function __clearAdapterSurfaceRegistryForTests(): void {
|
|
|
149
148
|
registry.clear();
|
|
150
149
|
}
|
|
151
150
|
|
|
152
|
-
// ---------------------------------------------------------------------------
|
|
153
|
-
// `defaultThreeAdapterFactory` — an OPT-IN convenience, never auto-registered
|
|
154
|
-
// ---------------------------------------------------------------------------
|
|
155
|
-
|
|
156
|
-
/** The entry-module export shape every first-party entry module follows
|
|
157
|
-
* (an explicit world entry module, including `examples/*` projects'
|
|
158
|
-
* `src/index.ts` — see CLAUDE.md's "Adding an example project"). */
|
|
159
|
-
interface ThreeEntryModuleExports {
|
|
160
|
-
readonly adapter?: RootAdapter;
|
|
161
|
-
readonly setup?: GameSetupFn;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* A ready-to-register {@link AdapterSurfaceFactory} for `kind: 'three'` roots
|
|
166
|
-
* that follow the first-party entry-module convention (`export const
|
|
167
|
-
* adapter` and/or `export async function setup`). Threejs is safe to
|
|
168
|
-
* ship as an exported convenience (unlike canvas/react) because `three`/
|
|
169
|
-
* `SetupThreeRootAdapter` are already unconditional engine dependencies —
|
|
170
|
-
* see `mount-manifest.ts`'s header comment. Still never auto-registered:
|
|
171
|
-
* the registry itself stays zero-policy (see this file's header comment) —
|
|
172
|
-
* a caller opts in with `registerAdapter('three', defaultThreeAdapterFactory)`.
|
|
173
|
-
*
|
|
174
|
-
* Resolution mirrors `mount-manifest.ts`'s own `resolveThreeAdapter` branch
|
|
175
|
-
* order: an entry module's `adapter` export wins outright; else its `setup`
|
|
176
|
-
* export (wrapping via `fromSetup` happens inside `mountManifestRoots`
|
|
177
|
-
* itself — this factory just returns the `MountEntry` shape).
|
|
178
|
-
*/
|
|
179
|
-
export const defaultThreeAdapterFactory: AdapterSurfaceFactory = (world, ctx) => {
|
|
180
|
-
const mod = ctx.entryModule as ThreeEntryModuleExports | undefined;
|
|
181
|
-
if (mod?.adapter) return { kind: 'three', adapter: mod.adapter };
|
|
182
|
-
if (mod?.setup) return { kind: 'three', setup: mod.setup };
|
|
183
|
-
if (world.entry !== undefined) {
|
|
184
|
-
throw new Error(
|
|
185
|
-
`defaultThreeAdapterFactory: entry module "${world.entry}" for world "${world.id}" exports ` +
|
|
186
|
-
'neither `adapter` nor `setup` — every first-party entry module exports at least one ' +
|
|
187
|
-
'(export one from the declared entry module).',
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
throw new Error(
|
|
191
|
-
`defaultThreeAdapterFactory: world "${world.id}" declares no \`entry\` — a three root is ` +
|
|
192
|
-
'authored as a TSX/R3F world module; point `entry` at it.',
|
|
193
|
-
);
|
|
194
|
-
};
|
|
195
|
-
|
|
196
151
|
// ---------------------------------------------------------------------------
|
|
197
152
|
// The composer
|
|
198
153
|
// ---------------------------------------------------------------------------
|
|
@@ -208,12 +163,9 @@ export interface MountGameOptions {
|
|
|
208
163
|
/** True for the one shape `mountManifestRoots` can ALREADY mount with zero
|
|
209
164
|
* `entries[id]` at all.
|
|
210
165
|
*
|
|
211
|
-
*
|
|
212
|
-
* `default`-adapter, SCENE-driven, no-`entry` three world, which
|
|
213
|
-
* `resolveThreeAdapter`'s scene branch could mount from the manifest alone —
|
|
214
|
-
* died with the `.vscn.json` format. `load.ts` now rejects a three root with no
|
|
166
|
+
* NOTHING is self-sufficient: `load.ts` rejects a three root with no
|
|
215
167
|
* `entry` outright, so every world needs a registered factory or an explicit
|
|
216
|
-
* entry
|
|
168
|
+
* entry. This predicate is retained so the loud-degrade error stays the
|
|
217
169
|
* documented outcome rather than a silent skip. */
|
|
218
170
|
function worldIsSelfSufficient(_world: ResolvedAdapterRoot): boolean {
|
|
219
171
|
return false;
|
|
@@ -292,7 +244,7 @@ export async function mountGameFromManifest(
|
|
|
292
244
|
`mountGameFromManifest: root "${world.id}" (adapter "${world.adapter.identity}") has no registered ` +
|
|
293
245
|
`adapter factory and no explicit entries["${world.id}"] — call ` +
|
|
294
246
|
`registerAdapter("${world.adapter.identity}", factory) before mounting (see ` +
|
|
295
|
-
'`
|
|
247
|
+
'`r3fRootFactory` in `@vgai/engine/world3d-react` for the worked three factory), or pass ' +
|
|
296
248
|
`opts.entries["${world.id}"] directly (see mount-manifest.ts's \`MountEntry\`).`,
|
|
297
249
|
);
|
|
298
250
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// The standalone manifest-mount helper: an ENGINE-side generalization of
|
|
2
2
|
// `examples/tri-world/src/main.ts`'s hand-built `RootMountSpec[]`.
|
|
3
3
|
//
|
|
4
|
-
// `resolveAllRoots`/`
|
|
5
|
-
//
|
|
4
|
+
// `resolveAllRoots`/`resolveRootBinding` (`packages/editor/src/
|
|
5
|
+
// binding-resolver.ts`) already do this translation for the EDITOR, but they
|
|
6
6
|
// are Vite-coupled by construction (`/@fs/` dynamic imports of project files
|
|
7
7
|
// through the dev server, §0.1/§0.5 of the design doc) — unusable from a
|
|
8
8
|
// plain static build. This module mirrors their per-kind dispatch
|
|
@@ -17,18 +17,15 @@
|
|
|
17
17
|
// type-only import): this file never value-imports
|
|
18
18
|
// `pixi.js`, `react`, or `react-dom` — a
|
|
19
19
|
// canvas or react world's adapter is ALWAYS supplied already-constructed via
|
|
20
|
-
// `entries[id].adapter` (the caller's own module graph built it)
|
|
21
|
-
//
|
|
22
|
-
// `SetupThreeRootAdapter` are already unconditional dependencies of every
|
|
23
|
-
// caller of `createGameRuntime`, so wrapping a `setup` with
|
|
24
|
-
// `fromSetup` here adds no NEW bundle weight — only pixi/react are avoided.
|
|
20
|
+
// `entries[id].adapter` (the caller's own module graph built it), so no
|
|
21
|
+
// surface's library is pulled into a game that has no world on it.
|
|
25
22
|
|
|
26
23
|
import { assertNever } from '../adapter/adapter-surface';
|
|
24
|
+
import type { RootDeclaration } from '../adapter/binding';
|
|
27
25
|
import { declaredRoots } from '../adapter/manifest-interpreter';
|
|
28
26
|
import type { RootAdapter } from '../adapter/root-adapter';
|
|
29
27
|
// Value-imported from the implementer's OWN path, not the type-only
|
|
30
28
|
// `../adapter` barrel (P-6).
|
|
31
|
-
import { fromSetup } from '../adapter/setup-three-root-adapter';
|
|
32
29
|
import {
|
|
33
30
|
loadGameManifest,
|
|
34
31
|
type ResolvedAdapterRoot,
|
|
@@ -38,8 +35,8 @@ import { createGameRuntime, type GameSession, type RootMountSpec } from './creat
|
|
|
38
35
|
import { type DebugBridgeWindowTarget, maybeInstallDebugBridge } from './debug-bridge';
|
|
39
36
|
import { getDebugRegistry } from './debug-registry';
|
|
40
37
|
import { getGameplayRngTrapControl } from './gameplay-rng-trap';
|
|
38
|
+
import type { PlaytestContext } from './playtest';
|
|
41
39
|
import { RENDER_SEED_QUERY_PARAM } from './render-seed';
|
|
42
|
-
import type { GameSetupFn, PlaytestContext } from './types';
|
|
43
40
|
|
|
44
41
|
// ---------------------------------------------------------------------------
|
|
45
42
|
// The `entries` contract
|
|
@@ -53,20 +50,28 @@ import type { GameSetupFn, PlaytestContext } from './types';
|
|
|
53
50
|
* - `{ adapter }` — a fully-constructed {@link RootAdapter} (first-party or
|
|
54
51
|
* not). Always wins if present, regardless of the world's `entry` field —
|
|
55
52
|
* full caller control, including for a `{ module }`-adapter world
|
|
56
|
-
* (mountManifestRoots cannot import an arbitrary module path itself
|
|
57
|
-
*
|
|
58
|
-
* `
|
|
59
|
-
*
|
|
60
|
-
* `SetupThreeRootAdapter` here, mirroring `resolveDefaultThreeAdapter`'s
|
|
61
|
-
* entry branch exactly.
|
|
62
|
-
*
|
|
63
|
-
* The former third shape, `{ componentRegistry }` for a `scene`-declaring
|
|
64
|
-
* world, went with the `.vscn.json` format in WO-8.
|
|
53
|
+
* (mountManifestRoots cannot import an arbitrary module path itself —
|
|
54
|
+
* for a default-exported world, build the adapter with
|
|
55
|
+
* `resolveR3FEntryAdapter(entryModule, worldId)` from
|
|
56
|
+
* `@vgai/engine/world3d-react` and pass it here).
|
|
65
57
|
*/
|
|
66
|
-
export interface ThreeMountEntry {
|
|
58
|
+
export interface ThreeMountEntry extends MountEntryDeclaration {
|
|
67
59
|
readonly kind: 'three';
|
|
68
60
|
readonly adapter?: RootAdapter | undefined;
|
|
69
|
-
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The half of a root's binding declaration a CALLER holds — everything in
|
|
65
|
+
* `adapter/binding.ts`'s {@link RootDeclaration} except `root`, which this
|
|
66
|
+
* file already has from the manifest it just resolved.
|
|
67
|
+
*
|
|
68
|
+
* Optional throughout, and absent is the honest state for a caller who built
|
|
69
|
+
* an adapter by hand out of its own module graph: there is no entry namespace
|
|
70
|
+
* to report a static surface for, so the root registers with `binding: null`
|
|
71
|
+
* rather than one describing a module nobody loaded.
|
|
72
|
+
*/
|
|
73
|
+
export interface MountEntryDeclaration {
|
|
74
|
+
readonly declaration?: Omit<RootDeclaration, 'root'> | undefined;
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
/**
|
|
@@ -77,7 +82,7 @@ export interface ThreeMountEntry {
|
|
|
77
82
|
* `pixi.js`, which it deliberately never does (see this file's header
|
|
78
83
|
* comment).
|
|
79
84
|
*/
|
|
80
|
-
export interface PixiMountEntry {
|
|
85
|
+
export interface PixiMountEntry extends MountEntryDeclaration {
|
|
81
86
|
readonly kind: 'canvas';
|
|
82
87
|
readonly adapter: RootAdapter<'canvas'>;
|
|
83
88
|
}
|
|
@@ -95,7 +100,7 @@ export interface PixiMountEntry {
|
|
|
95
100
|
* itself (see this file's header comment) — building the adapter is
|
|
96
101
|
* entirely the caller's job.
|
|
97
102
|
*/
|
|
98
|
-
export interface ReactMountEntry {
|
|
103
|
+
export interface ReactMountEntry extends MountEntryDeclaration {
|
|
99
104
|
readonly kind: 'dom';
|
|
100
105
|
readonly adapter: RootAdapter<'dom'>;
|
|
101
106
|
}
|
|
@@ -244,8 +249,8 @@ export function resolveManifest(raw: unknown): ResolvedGameManifest {
|
|
|
244
249
|
}
|
|
245
250
|
|
|
246
251
|
// ---------------------------------------------------------------------------
|
|
247
|
-
// Per-kind entry -> adapter resolution (mirrors `
|
|
248
|
-
// per-identity dispatch, `packages/editor/src/
|
|
252
|
+
// Per-kind entry -> adapter resolution (mirrors `resolveRootBinding`'s
|
|
253
|
+
// per-identity dispatch, `packages/editor/src/binding-resolver.ts`)
|
|
249
254
|
// ---------------------------------------------------------------------------
|
|
250
255
|
|
|
251
256
|
function resolveThreeAdapter(
|
|
@@ -274,19 +279,17 @@ function resolveThreeAdapter(
|
|
|
274
279
|
|
|
275
280
|
// type === 'default'
|
|
276
281
|
if (world.entry !== undefined) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
return fromSetup(world.id, entry.setup);
|
|
282
|
+
throw new Error(
|
|
283
|
+
`mountManifestRoots: world "${world.id}" (three) declares \`entry\` "${world.entry}" ` +
|
|
284
|
+
`— supply entries["${world.id}"] = { kind: 'three', adapter } (for a default-exported ` +
|
|
285
|
+
'world, build it with `resolveR3FEntryAdapter(entryModule, worldId)` from ' +
|
|
286
|
+
'`@vgai/engine/world3d-react`). Got ' +
|
|
287
|
+
`${entry === undefined ? 'no entry at all' : 'an entry with no `adapter`'}.`,
|
|
288
|
+
);
|
|
286
289
|
}
|
|
287
290
|
// Unreachable in practice: `load.ts`'s `checkAdapterSceneEntryRules` requires
|
|
288
291
|
// `entry` for every 'default' THREE adapter world at manifest-load time (and
|
|
289
|
-
// rejects
|
|
292
|
+
// rejects any other content declaration on one outright).
|
|
290
293
|
throw new Error(
|
|
291
294
|
`mountManifestRoots: world "${world.id}" is default-three with no \`entry\` — this ` +
|
|
292
295
|
'should have been rejected by manifest validation.',
|
|
@@ -337,6 +340,12 @@ function buildRootMountSpec(
|
|
|
337
340
|
id: world.id,
|
|
338
341
|
zOrder: world.zOrder,
|
|
339
342
|
pausable: world.pausable,
|
|
343
|
+
// `root` is this file's own resolved manifest record; the rest — the
|
|
344
|
+
// parsed `vgai.adapter.ts`, the entry namespace, the entry's declared
|
|
345
|
+
// debug/systems bindings — only the caller who loaded the entry can know.
|
|
346
|
+
...(entry?.declaration === undefined
|
|
347
|
+
? {}
|
|
348
|
+
: { declaration: { root: world, ...entry.declaration } }),
|
|
340
349
|
};
|
|
341
350
|
|
|
342
351
|
// `entry`'s `kind` is guaranteed to agree with `world.kind` past the guard
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHO IS PLAYING, and under what identity — the host's own declaration for one
|
|
3
|
+
* private play run or coordinated team test.
|
|
4
|
+
*
|
|
5
|
+
* Its own module because it is a PUBLISHED path: a project's Colyseus
|
|
6
|
+
* networking adapter (the `colyseus` capability, copied into every game) names
|
|
7
|
+
* this type, so it must live somewhere that survives. The engine never joins a
|
|
8
|
+
* room and never couples this authoring identity to a networking library —
|
|
9
|
+
* games may pass `roomKey` as a Colyseus filter/join option, and that is the
|
|
10
|
+
* whole of the coupling.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Host-supplied identity for one private play run or coordinated team test.
|
|
14
|
+
* Games may pass `roomKey` as a Colyseus filter/join option; the engine never
|
|
15
|
+
* joins a room or couples this authoring identity to a networking library. */
|
|
16
|
+
export interface PlaytestContext {
|
|
17
|
+
readonly mode: 'private' | 'team';
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly roomKey: string;
|
|
20
|
+
readonly revision: number | null;
|
|
21
|
+
readonly participantId: string | null;
|
|
22
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `runTicksWhenSettled` — the settled-aware tick driver behind BOTH session run-ticks doors
|
|
3
|
+
* (the bridge's `window.__vgai.runTicksSettled`, the editor relay's `run-ticks` case), one
|
|
4
|
+
* implementation with byte-identical semantics across doors, exactly as `runTicks` itself is
|
|
5
|
+
* shared (D17).
|
|
6
|
+
*
|
|
7
|
+
* Why it exists: `Game.runTicks` is deliberately SYNCHRONOUS, but a game may be intentionally
|
|
8
|
+
* BETWEEN worlds when a tick arrives — `reload_current_scene` unmounts the running scene and
|
|
9
|
+
* the fresh one arrives on an ASYNC React commit. A tick driven into that gap runs against
|
|
10
|
+
* nothing, and WHICH tick first runs the fresh world then depends on wall timing between
|
|
11
|
+
* driver calls — measured on the starter-kit fidelity drive: the same script produced 7 or 8
|
|
12
|
+
* post-respawn walked ticks depending on how long the driver idled between ticks. The fidelity
|
|
13
|
+
* contract (docs/MIGRATE-FIDELITY.md) treats a nondeterministic channel as a MECHANISM defect,
|
|
14
|
+
* and this is the mechanism: ticks must not race remounts.
|
|
15
|
+
*
|
|
16
|
+
* So this driver runs the budget ONE tick at a time and, before each tick, waits for every
|
|
17
|
+
* registered world-settled probe ({@link DebugRegistry.registerWorldSettledProbe} — declared by
|
|
18
|
+
* the game through its `debug.settled` entry export) to answer `true`. The wall-clock poll is
|
|
19
|
+
* sound because the OUTCOME no longer depends on timing: however long the commit takes, the
|
|
20
|
+
* next tick is always the fresh world's first. A game that registers no probe gets the old
|
|
21
|
+
* behavior exactly (every wait resolves immediately).
|
|
22
|
+
*
|
|
23
|
+
* The wait is BOUNDED and loud: a remount that never settles is a real defect, and
|
|
24
|
+
* `WORLD_UNSETTLED_TIMEOUT` names it rather than letting the driver hang.
|
|
25
|
+
*/
|
|
26
|
+
import { DebugError, type DebugRegistry, type RunTicksOptions } from './debug-registry';
|
|
27
|
+
|
|
28
|
+
/** A remount is a couple of React commits on an idle main thread; polling faster buys nothing
|
|
29
|
+
* and slower delays every settled check by the poll period. */
|
|
30
|
+
const SETTLED_POLL_MS = 4;
|
|
31
|
+
/** A commit that hasn't landed after this long is not "in flight", it is stuck. */
|
|
32
|
+
const SETTLED_TIMEOUT_MS = 10_000;
|
|
33
|
+
|
|
34
|
+
export async function runTicksWhenSettled(
|
|
35
|
+
registry: Pick<DebugRegistry, 'worldSettled' | 'getRunTicksTarget'>,
|
|
36
|
+
n: number,
|
|
37
|
+
opts?: RunTicksOptions,
|
|
38
|
+
/** Test-only overrides — real callers leave this unset (the same seam
|
|
39
|
+
* convention as fast-forward's `batchTicks`). */
|
|
40
|
+
waits?: { timeoutMs?: number; pollMs?: number },
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
const target = registry.getRunTicksTarget();
|
|
43
|
+
if (target === null) {
|
|
44
|
+
throw new DebugError(
|
|
45
|
+
'RUN_TICKS_UNAVAILABLE',
|
|
46
|
+
'runTicksWhenSettled: no run-ticks target is wired — no Game has mounted yet',
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const timeoutMs = waits?.timeoutMs ?? SETTLED_TIMEOUT_MS;
|
|
50
|
+
const pollMs = waits?.pollMs ?? SETTLED_POLL_MS;
|
|
51
|
+
const render = opts?.render ?? 'last';
|
|
52
|
+
for (let i = 0; i < n; i++) {
|
|
53
|
+
if (!registry.worldSettled()) {
|
|
54
|
+
const deadline = Date.now() + timeoutMs;
|
|
55
|
+
while (!registry.worldSettled()) {
|
|
56
|
+
if (Date.now() > deadline) {
|
|
57
|
+
throw new DebugError(
|
|
58
|
+
'WORLD_UNSETTLED_TIMEOUT',
|
|
59
|
+
`runTicksWhenSettled: a world-settled probe still answers false after ${timeoutMs}ms — ` +
|
|
60
|
+
'a scene remount (or a broken probe) is stuck, and driving ticks into it would race it',
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const isFinalTick = i === n - 1;
|
|
67
|
+
// Same per-tick render policy `Game.runTicks` applies across its own loop.
|
|
68
|
+
const tickRender =
|
|
69
|
+
render === 'all' ? 'all' : render === 'none' ? 'none' : isFinalTick ? 'last' : 'none';
|
|
70
|
+
target.runTicks(1, { render: tickRender });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -48,9 +48,8 @@ export interface GameStateBridge {
|
|
|
48
48
|
export interface GameStateBridgeInternal extends GameStateBridge {
|
|
49
49
|
/** Bump `frameVersion` by one and notify every current subscriber, in
|
|
50
50
|
* subscription order. Subscriber errors are isolated (per-subscriber
|
|
51
|
-
* try/catch, loud `console.error`, never swallowed silently)
|
|
52
|
-
*
|
|
53
|
-
* `update()` calls: one offending subscriber must not stop its siblings
|
|
51
|
+
* try/catch, loud `console.error`, never swallowed silently): one
|
|
52
|
+
* offending subscriber must not stop its siblings
|
|
54
53
|
* from being notified, and must not break the frame loop. */
|
|
55
54
|
bump(): void;
|
|
56
55
|
}
|
|
@@ -84,6 +83,7 @@ export function createStateBridge(): GameStateBridgeInternal {
|
|
|
84
83
|
try {
|
|
85
84
|
onFrame();
|
|
86
85
|
} catch (err) {
|
|
86
|
+
// biome-ignore lint/suspicious/noConsole: a throwing subscriber must not take the notify loop down, and the console (captured by the editor session ledger) is the engine runtime's one report channel.
|
|
87
87
|
console.error('[state-bridge] subscriber threw:', err);
|
|
88
88
|
}
|
|
89
89
|
}
|
package/src/setup/setup-audio.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
+
import { type AudioBusMixer, createAudioBusMixer } from '../audio/bus-mixer';
|
|
2
3
|
|
|
3
4
|
export interface AudioContext {
|
|
4
5
|
listener: THREE.AudioListener;
|
|
@@ -8,10 +9,24 @@ export interface AudioContext {
|
|
|
8
9
|
sfx: GainNode;
|
|
9
10
|
voice: GainNode;
|
|
10
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* The named-bus mixer the three below are buses OF (`../audio/bus-mixer.ts`).
|
|
14
|
+
*
|
|
15
|
+
* `buses` is a fixed struct because those three names are the ones the engine
|
|
16
|
+
* itself routes; a game with an `ambience`, a `ui` or a per-character bus asks
|
|
17
|
+
* the mixer for it by name — `audio.mixer.bus('ambience', 'master')` mints it
|
|
18
|
+
* under the master gain, `audio.mixer.setDb('ambience', -6)` sets it in
|
|
19
|
+
* decibels — and `audio.mixer.disconnect()` is the ONE teardown for all of
|
|
20
|
+
* them, the three struct members included.
|
|
21
|
+
*/
|
|
22
|
+
mixer: AudioBusMixer;
|
|
11
23
|
/** Call this on first user interaction (click/key) to resume audio context */
|
|
12
24
|
resume: () => void;
|
|
13
25
|
}
|
|
14
26
|
|
|
27
|
+
/** The bus every other bus routes into, and the node `masterGain` is. */
|
|
28
|
+
const MASTER_BUS = 'master';
|
|
29
|
+
|
|
15
30
|
/**
|
|
16
31
|
* Creates the audio listener and bus hierarchy.
|
|
17
32
|
*
|
|
@@ -23,25 +38,19 @@ export function setupAudio(camera: THREE.Camera): AudioContext {
|
|
|
23
38
|
camera.add(listener);
|
|
24
39
|
|
|
25
40
|
const ctx = listener.context;
|
|
26
|
-
const
|
|
27
|
-
masterGain.
|
|
41
|
+
const mixer = createAudioBusMixer({ context: ctx, destination: ctx.destination });
|
|
42
|
+
const masterGain = mixer.bus(MASTER_BUS);
|
|
28
43
|
|
|
29
44
|
// Route the Three.js listener through masterGain so that THREE.Audio /
|
|
30
45
|
// THREE.PositionalAudio objects are also silenced by the mute button.
|
|
31
46
|
listener.gain.disconnect();
|
|
32
47
|
listener.gain.connect(masterGain);
|
|
33
48
|
|
|
34
|
-
const musicGain =
|
|
49
|
+
const musicGain = mixer.bus('music', MASTER_BUS);
|
|
35
50
|
musicGain.gain.value = 0.7;
|
|
36
|
-
musicGain.connect(masterGain);
|
|
37
|
-
|
|
38
|
-
const sfxGain = ctx.createGain();
|
|
39
|
-
sfxGain.gain.value = 1.0;
|
|
40
|
-
sfxGain.connect(masterGain);
|
|
41
51
|
|
|
42
|
-
const
|
|
43
|
-
voiceGain
|
|
44
|
-
voiceGain.connect(masterGain);
|
|
52
|
+
const sfxGain = mixer.bus('sfx', MASTER_BUS);
|
|
53
|
+
const voiceGain = mixer.bus('voice', MASTER_BUS);
|
|
45
54
|
|
|
46
55
|
return {
|
|
47
56
|
listener,
|
|
@@ -51,6 +60,7 @@ export function setupAudio(camera: THREE.Camera): AudioContext {
|
|
|
51
60
|
sfx: sfxGain,
|
|
52
61
|
voice: voiceGain,
|
|
53
62
|
},
|
|
63
|
+
mixer,
|
|
54
64
|
resume() {
|
|
55
65
|
if (ctx.state === 'suspended') {
|
|
56
66
|
ctx.resume();
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
DepthOfFieldEffect,
|
|
10
10
|
DotScreenEffect,
|
|
11
11
|
type Effect,
|
|
12
|
-
EffectComposer,
|
|
12
|
+
type EffectComposer,
|
|
13
13
|
EffectPass,
|
|
14
14
|
GlitchEffect,
|
|
15
15
|
GodRaysEffect,
|
|
@@ -42,13 +42,6 @@ import { DEFAULTS } from '../defaults';
|
|
|
42
42
|
import { detectKtx2Support } from '../loader';
|
|
43
43
|
import { type RenderScope, resolveRenderSettings } from '../render/render-settings';
|
|
44
44
|
|
|
45
|
-
export interface RendererContext {
|
|
46
|
-
renderer: THREE.WebGLRenderer;
|
|
47
|
-
scene: THREE.Scene;
|
|
48
|
-
camera: THREE.PerspectiveCamera;
|
|
49
|
-
composer: EffectComposer;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
45
|
/**
|
|
53
46
|
* Apply the live renderer-level render settings (shadows, resolution scale) from
|
|
54
47
|
* the resolved cascade. `antialias`/`backend` are reload-only (renderer re-init)
|
|
@@ -73,7 +66,7 @@ export function applyRendererSettings(
|
|
|
73
66
|
/**
|
|
74
67
|
* Create ONLY the WebGL renderer. The HOST owns the renderer (see
|
|
75
68
|
* `ThreeHostContext.renderer`); the game/adapter owns the scene/camera/composer it
|
|
76
|
-
* renders into.
|
|
69
|
+
* renders into.
|
|
77
70
|
*
|
|
78
71
|
* `rendering` is the scene-level render scope (`env.rendering`); it seeds the
|
|
79
72
|
* reload-only `antialias` option at construction and the live shadow/resolution
|
|
@@ -118,58 +111,6 @@ export function createHostRenderer(
|
|
|
118
111
|
return renderer;
|
|
119
112
|
}
|
|
120
113
|
|
|
121
|
-
/**
|
|
122
|
-
* Create the scene, camera, and postprocessing composer that a first-party game
|
|
123
|
-
* renders into, given a host-provided renderer. The GPU-only `composer` is
|
|
124
|
-
* created here; a headless host (no GPU) skips this entirely.
|
|
125
|
-
*/
|
|
126
|
-
export function createSceneView(
|
|
127
|
-
renderer: THREE.WebGLRenderer,
|
|
128
|
-
width = window.innerWidth,
|
|
129
|
-
height = window.innerHeight,
|
|
130
|
-
): { scene: THREE.Scene; camera: THREE.PerspectiveCamera; composer: EffectComposer } {
|
|
131
|
-
const safeWidth = Math.max(1, width);
|
|
132
|
-
const safeHeight = Math.max(1, height);
|
|
133
|
-
const scene = new THREE.Scene();
|
|
134
|
-
scene.background = new THREE.Color(0x1a1a2e);
|
|
135
|
-
|
|
136
|
-
const camera = new THREE.PerspectiveCamera(
|
|
137
|
-
DEFAULTS.camera.fov,
|
|
138
|
-
safeWidth / safeHeight,
|
|
139
|
-
DEFAULTS.camera.near,
|
|
140
|
-
DEFAULTS.camera.far,
|
|
141
|
-
);
|
|
142
|
-
camera.position.set(0, 5, 10);
|
|
143
|
-
camera.lookAt(0, 0, 0);
|
|
144
|
-
|
|
145
|
-
const composer = new EffectComposer(renderer);
|
|
146
|
-
composer.addPass(new RenderPass(scene, camera));
|
|
147
|
-
composer.addPass(
|
|
148
|
-
new EffectPass(
|
|
149
|
-
camera,
|
|
150
|
-
new BloomEffect({ luminanceThreshold: DEFAULTS.postProcessing.bloom.luminanceThreshold }),
|
|
151
|
-
),
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
return { scene, camera, composer };
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Creates the Three.js renderer, scene, camera, and postprocessing pipeline.
|
|
159
|
-
*
|
|
160
|
-
* This is direct Three.js setup — no abstraction. Edit freely. (Now a thin
|
|
161
|
-
* combination of {@link createHostRenderer} + {@link createSceneView}.)
|
|
162
|
-
*/
|
|
163
|
-
export function setupRenderer(
|
|
164
|
-
canvas: HTMLCanvasElement,
|
|
165
|
-
width = window.innerWidth,
|
|
166
|
-
height = window.innerHeight,
|
|
167
|
-
): RendererContext {
|
|
168
|
-
const renderer = createHostRenderer(canvas, width, height);
|
|
169
|
-
const { scene, camera, composer } = createSceneView(renderer, width, height);
|
|
170
|
-
return { renderer, scene, camera, composer };
|
|
171
|
-
}
|
|
172
|
-
|
|
173
114
|
const toneMappingModes: Record<string, THREE.ToneMapping> = {
|
|
174
115
|
none: THREE.NoToneMapping,
|
|
175
116
|
linear: THREE.LinearToneMapping,
|
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
*
|
|
19
19
|
* ## Why this is NOT in `mount-game.ts`
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
21
|
+
* The adapter registry module is deliberately dependency-free beyond `three`
|
|
22
|
+
* (already an unconditional engine dependency). `@react-three/fiber` is NOT —
|
|
23
|
+
* it is the PROJECT's dependency, and `world3d-react` is the opt-in module
|
|
24
|
+
* that owns it. Putting this factory beside the registry would make R3F
|
|
25
|
+
* unconditional for every game, including ones with no React at all; instead
|
|
26
|
+
* each project's `main.ts` registers it (`registerAdapter('three',
|
|
27
|
+
* r3fRootFactory)`).
|
|
28
28
|
*
|
|
29
29
|
* ## The mount mechanics (fiber v9, host-gated)
|
|
30
30
|
*
|