@forgeax/engine-runtime 0.1.27 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +98 -0
  2. package/dist/collect-scene-asset.d.ts.map +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.mjs +480 -15
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/scene-utils/mount-override-fold.d.ts +3 -1
  8. package/dist/scene-utils/mount-override-fold.d.ts.map +1 -1
  9. package/package.json +37 -30
  10. package/src/__tests__/animation-graph-collect-roundtrip.test.ts +4 -2
  11. package/src/__tests__/asset-registry-aabb.cases.unit.test.ts +5 -4
  12. package/src/__tests__/asset-registry-guid-reverse.test.ts +22 -27
  13. package/src/__tests__/asset-registry-mounts.test.ts +174 -734
  14. package/src/__tests__/asset-registry-scene.cases.unit.test.ts +9 -18
  15. package/src/__tests__/asset-registry.recursive.spec.ts +23 -29
  16. package/src/__tests__/camera-ortho.cases.unit.test.ts +12 -3
  17. package/src/__tests__/collect-scene-asset.test.ts +96 -113
  18. package/src/__tests__/collect-scene-mount-collapse.test.ts +64 -66
  19. package/src/__tests__/collect-transient-children-absent.test.ts +11 -17
  20. package/src/__tests__/collect-transient-roundtrip.test.ts +12 -13
  21. package/src/__tests__/collect-transient-skip.test.ts +20 -27
  22. package/src/__tests__/components.test-d.ts +17 -1
  23. package/src/__tests__/components.unit.test.ts +75 -27
  24. package/src/__tests__/composite-skybox-cross-world.browser.test.ts +4 -2
  25. package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +8 -4
  26. package/src/__tests__/dawn/instances-shadow.dawn.test.ts +4 -1
  27. package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +66 -92
  28. package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +200 -4
  29. package/src/__tests__/errors.unit.test.ts +13 -0
  30. package/src/__tests__/feature-depth-material.dawn.test.ts +23 -0
  31. package/src/__tests__/feature-depth-material.fixture.ts +473 -0
  32. package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +14 -14
  33. package/src/__tests__/geometry.unit.test.ts +42 -43
  34. package/src/__tests__/gpu-resource-release.cases.unit.test.ts +16 -9
  35. package/src/__tests__/handle-migration.test.ts +0 -1
  36. package/src/__tests__/instances-renderer-lifecycle.integration.test.ts +20 -14
  37. package/src/__tests__/instances.test-d.ts +13 -52
  38. package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +42 -80
  39. package/src/__tests__/lazy-catalog.cases.unit.test.ts +17 -3
  40. package/src/__tests__/loader-registry.cases.unit.test.ts +4 -4
  41. package/src/__tests__/material-publication.browser.test.ts +29 -0
  42. package/src/__tests__/material-publication.commands.ts +23 -0
  43. package/src/__tests__/material-publication.dawn.test.ts +24 -0
  44. package/src/__tests__/material-publication.fixture.ts +349 -0
  45. package/src/__tests__/material-publication.server.ts +109 -0
  46. package/src/__tests__/parse-scene-payload-refs.cases.unit.test.ts +73 -96
  47. package/src/__tests__/pbr-pipeline.unit.test.ts +25 -11
  48. package/src/__tests__/point-light-shadow.browser.test.ts +8 -2
  49. package/src/__tests__/point-light-shadow.unit.test.ts +37 -8
  50. package/src/__tests__/record-all-topology.cases.unit.test.ts +52 -0
  51. package/src/__tests__/record-draw-branch.cases.unit.test.ts +1 -0
  52. package/src/__tests__/record-worldid-isolation.test.ts +47 -28
  53. package/src/__tests__/render-error-exhaustive.test-d.ts +24 -0
  54. package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +15 -4
  55. package/src/__tests__/render-system-extract.test.ts +61 -0
  56. package/src/__tests__/render-system-extract.unit.test.ts +21 -7
  57. package/src/__tests__/render-system-fold-bucket.unit.test.ts +33 -1
  58. package/src/__tests__/render-system-fold-material.unit.test.ts +32 -6
  59. package/src/__tests__/render-system-fold-modegate.unit.test.ts +26 -4
  60. package/src/__tests__/render-system-fold.dawn.test.ts +4 -1
  61. package/src/__tests__/render-system-mega.test.ts +50 -62
  62. package/src/__tests__/renderer-device-loss-provider-feasibility.dawn.test.ts +0 -1
  63. package/src/__tests__/renderer-device-loss-recovery.dawn.test.ts +0 -3
  64. package/src/__tests__/renderer-draw-world.cases.unit.test.ts +16 -513
  65. package/src/__tests__/resolve-scene-guids.cases.unit.test.ts +48 -43
  66. package/src/__tests__/rhi-null-command-flow.unit.test.ts +9 -7
  67. package/src/__tests__/roots-to-scene-asset.test.ts +27 -28
  68. package/src/__tests__/roundtrip-primitive.test.ts +24 -23
  69. package/src/__tests__/scene-equirect-roundtrip.test.ts +5 -16
  70. package/src/__tests__/scene-instantiate-cycle-runtime.test.ts +13 -29
  71. package/src/__tests__/scene-mount-fixed-point.test.ts +104 -227
  72. package/src/__tests__/scene-mount-roundtrip.test.ts +95 -961
  73. package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +36 -182
  74. package/src/__tests__/scene-sugar-instantiate.test.ts +20 -15
  75. package/src/__tests__/serialize-mounts-roundtrip.test.ts +108 -492
  76. package/src/__tests__/serialize-scene-asset.test.ts +36 -50
  77. package/src/__tests__/shadow-caster-empty-schema.test.ts +3 -1
  78. package/src/__tests__/shadow-fields-observable.dawn.test.ts +34 -19
  79. package/src/__tests__/shadow-mesh-ssbo-order.test.ts +5 -12
  80. package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +6 -4
  81. package/src/__tests__/skin-m2-extract-happy.cases.unit.test.ts +50 -2
  82. package/src/__tests__/skin-m2-extract-joint-error.cases.unit.test.ts +50 -2
  83. package/src/__tests__/skin-m2-extract-null-assets.cases.unit.test.ts +50 -2
  84. package/src/__tests__/skin-m2-extract-skeleton-error.cases.unit.test.ts +50 -2
  85. package/src/__tests__/skin-palette-extract.cases.unit.test.ts +2 -0
  86. package/src/__tests__/skinned-shadow-mixed.dawn.test.ts +93 -48
  87. package/src/__tests__/skylight-pipeline-layout.cases.unit.test.ts +6 -2
  88. package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +1 -1
  89. package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +11 -3
  90. package/src/__tests__/template-game-default-api-contract.test.ts +21 -21
  91. package/src/__tests__/tonemap-hdr-target.cases.unit.test.ts +8 -5
  92. package/src/__tests__/tonemap-pipeline-split.cases.unit.test.ts +3 -0
  93. package/src/__tests__/transient-fields-collect.test.ts +4 -4
  94. package/src/__tests__/transient-runtime-behavior.test.ts +9 -9
  95. package/src/__tests__/vfx-depth-material.dawn.test.ts +42 -0
  96. package/src/__tests__/vfx-mesh-lighting.browser.test.ts +16 -0
  97. package/src/__tests__/vfx-mesh-lighting.commands.ts +14 -0
  98. package/src/__tests__/vfx-mesh-lighting.dawn.test.ts +16 -0
  99. package/src/__tests__/vfx-mesh-lighting.fixture.ts +883 -0
  100. package/src/__tests__/wave1-dynamic-geometry.browser.test.ts +326 -0
  101. package/src/__tests__/wave1-rendering-materials.browser.test.ts +617 -0
  102. package/src/__tests__/wave1-rendering-p0.browser.test.ts +751 -0
  103. package/src/__tests__/wave1-rendering-recovery.browser.test.ts +666 -0
  104. package/src/__tests__/wave1-shadow-diagnostic.browser.test.ts +582 -0
  105. package/src/__tests__/world-scene-despawn.test.ts +8 -8
  106. package/src/__tests__/world-scene-instantiate.test.ts +23 -29
  107. package/src/__tests__/world-scene-nested.test.ts +90 -163
  108. package/src/__tests__/world-scene-override.test.ts +17 -16
  109. package/src/__tests__/zero-compression-zero-load.integration.test.ts +1 -0
  110. package/src/collect-scene-asset.ts +637 -19
  111. package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
  112. package/src/index.ts +1 -0
  113. package/src/scene-utils/mount-override-fold.ts +5 -14
  114. package/src/__tests__/node-shims.d.ts +0 -31
@@ -49,7 +49,7 @@ describe('w1 — AC-07 transient exclusion (SpriteAnimation, VideoPlayer)', () =
49
49
  expect(collected.ok).toBe(true);
50
50
  if (!collected.ok) return;
51
51
 
52
- const entity = collected.value.entities[0];
52
+ const entity = Object.values(collected.value.entities)[0];
53
53
  expect(entity).toBeDefined();
54
54
  if (!entity) return;
55
55
 
@@ -80,7 +80,7 @@ describe('w1 — AC-07 transient exclusion (SpriteAnimation, VideoPlayer)', () =
80
80
  expect(collected.ok).toBe(true);
81
81
  if (!collected.ok) return;
82
82
 
83
- const entity = collected.value.entities[0];
83
+ const entity = Object.values(collected.value.entities)[0];
84
84
  expect(entity).toBeDefined();
85
85
  if (!entity) return;
86
86
 
@@ -117,7 +117,7 @@ describe('w2 — AC-08 round-trip tests (SpriteAnimation, VideoPlayer)', () => {
117
117
  expect(collected.ok).toBe(true);
118
118
  if (!collected.ok) return;
119
119
 
120
- const entity = collected.value.entities[0];
120
+ const entity = Object.values(collected.value.entities)[0];
121
121
  expect(entity).toBeDefined();
122
122
  if (!entity) return;
123
123
 
@@ -173,7 +173,7 @@ describe('w2 — AC-08 round-trip tests (SpriteAnimation, VideoPlayer)', () => {
173
173
  expect(collected.ok).toBe(true);
174
174
  if (!collected.ok) return;
175
175
 
176
- const entity = collected.value.entities[0];
176
+ const entity = Object.values(collected.value.entities)[0];
177
177
  expect(entity).toBeDefined();
178
178
  if (!entity) return;
179
179
 
@@ -41,7 +41,7 @@ function makeWorld(): World {
41
41
  return world;
42
42
  }
43
43
 
44
- function localId(n: number): LocalEntityId {
44
+ function _localId(n: number): LocalEntityId {
45
45
  return n as LocalEntityId;
46
46
  }
47
47
 
@@ -74,7 +74,7 @@ describe('m3t2 — transient runtime behavior (AC-07)', () => {
74
74
  // touches the manually-spawned entity
75
75
  const asset: SceneAsset = {
76
76
  kind: 'scene',
77
- entities: [{ localId: localId(0), components: {} }],
77
+ entities: { 'entity-0': { components: {} } },
78
78
  };
79
79
  cat(reg, '00000000-0000-4000-8000-000000000000', asset);
80
80
  const inst = reg.instantiate(rs(world, asset), world);
@@ -112,7 +112,7 @@ describe('m3t2 — transient runtime behavior (AC-07)', () => {
112
112
  // Collect an unrelated scene to exercise the collect code path
113
113
  const asset: SceneAsset = {
114
114
  kind: 'scene',
115
- entities: [{ localId: localId(0), components: {} }],
115
+ entities: { 'entity-0': { components: {} } },
116
116
  };
117
117
  cat(reg, '11111111-1111-4111-8111-111111111111', asset);
118
118
  const inst = reg.instantiate(rs(world, asset), world);
@@ -134,7 +134,7 @@ describe('m3t2 — transient runtime behavior (AC-07)', () => {
134
134
 
135
135
  const child: SceneAsset = {
136
136
  kind: 'scene',
137
- entities: [{ localId: localId(0), components: {} }],
137
+ entities: { 'entity-0': { components: {} } },
138
138
  };
139
139
  cat(reg, '22222222-2222-4222-8222-222222222222', child);
140
140
  const inst = reg.instantiate(rs(world, child), world);
@@ -171,7 +171,7 @@ describe('m3t2 — transient runtime behavior (AC-07)', () => {
171
171
  // Collect an unrelated scene
172
172
  const asset: SceneAsset = {
173
173
  kind: 'scene',
174
- entities: [{ localId: localId(0), components: {} }],
174
+ entities: { 'entity-0': { components: {} } },
175
175
  };
176
176
  cat(reg, '33333333-3333-4333-8333-333333333333', asset);
177
177
  const inst = reg.instantiate(rs(world, asset), world);
@@ -195,10 +195,10 @@ describe('m3t2 — transient runtime behavior (AC-07)', () => {
195
195
  // The mirror hook should populate Children on entity at localId 0.
196
196
  const asset: SceneAsset = {
197
197
  kind: 'scene',
198
- entities: [
199
- { localId: localId(0), components: { Transform: {} } },
200
- { localId: localId(1), components: { Transform: {}, ChildOf: { parent: localId(0) } } },
201
- ],
198
+ entities: {
199
+ 'entity-0': { components: { Transform: {} } },
200
+ 'entity-1': { components: { Transform: {}, ChildOf: { parent: 'entity-0' } } },
201
+ },
202
202
  };
203
203
  cat(reg, '44444444-4444-4444-8444-444444444444', asset);
204
204
  const inst = reg.instantiate(rs(world, asset), world);
@@ -0,0 +1,42 @@
1
+ import { it } from 'vitest';
2
+ import { particleDepthLayouts, verifyFeatureDepthMaterial } from './feature-depth-material.fixture';
3
+
4
+ // Separate from the synthetic layout suite so each renderer/manifest batch
5
+ // has a bounded process lifetime under the Dawn runner's file isolation.
6
+ const layouts = [
7
+ { ...particleDepthLayouts[0], particleKind: 'billboard' },
8
+ ...(['ribbon', 'trail', 'beam'] as const).map((particleKind) => ({
9
+ ...particleDepthLayouts[1],
10
+ particleKind,
11
+ })),
12
+ { ...particleDepthLayouts[2], particleKind: 'mesh' },
13
+ ] as const;
14
+ it.each(
15
+ layouts.flatMap((layout) =>
16
+ (['none', 'material', 'depth'] as const).map((missing) => ({ ...layout, view: true, missing })),
17
+ ),
18
+ )(
19
+ 'cooks and submits $particleKind with material/depth/input: missing=$missing',
20
+ verifyFeatureDepthMaterial,
21
+ 120_000,
22
+ );
23
+ it.each(
24
+ layouts.map((layout) => ({ ...layout, view: true, missing: 'none' as const, inputLane: 3 })),
25
+ )(
26
+ 'renders sparse material lane 3 through cooked $particleKind instances',
27
+ verifyFeatureDepthMaterial,
28
+ 120_000,
29
+ );
30
+ it.each(
31
+ layouts.map((layout) => ({
32
+ ...layout,
33
+ view: true,
34
+ missing: 'none' as const,
35
+ inputLane: 3,
36
+ allInputs: true,
37
+ })),
38
+ )(
39
+ 'reads all four distinct material lanes through cooked $particleKind instances',
40
+ verifyFeatureDepthMaterial,
41
+ 120_000,
42
+ );
@@ -0,0 +1,16 @@
1
+ import { it } from 'vitest';
2
+ import { commands } from 'vitest/browser';
3
+ import { type CookMeshLightingFixture, verifyVfxMeshLighting } from './vfx-mesh-lighting.fixture';
4
+
5
+ declare module 'vitest/browser' {
6
+ interface BrowserCommands {
7
+ cookVfxMeshLighting: CookMeshLightingFixture;
8
+ }
9
+ }
10
+
11
+ it('verifies Mesh Point/IBL parity and depth-dependent shadow latency on WebGPU', async () => {
12
+ await verifyVfxMeshLighting({
13
+ shaderManifestUrl: '/shaders/manifest.json',
14
+ cook: commands.cookVfxMeshLighting,
15
+ });
16
+ }, 120_000);
@@ -0,0 +1,14 @@
1
+ import { ok } from '@forgeax/engine-types';
2
+ import { cookParticleCodeEffect, type ParticleCodeModuleSet } from '@forgeax/engine-vfx-compiler';
3
+
4
+ /** Test-host cooking only; no compiler or source evaluation enters the player. */
5
+ export const vfxMeshLightingCommands = {
6
+ async cookVfxMeshLighting(
7
+ _context: unknown,
8
+ source: unknown,
9
+ modules: Readonly<Record<string, ParticleCodeModuleSet>>,
10
+ ) {
11
+ const cooked = await cookParticleCodeEffect(source, modules);
12
+ return cooked.ok ? ok({ asset: cooked.value.asset }) : cooked;
13
+ },
14
+ };
@@ -0,0 +1,16 @@
1
+ import { writeFileSync } from 'node:fs';
2
+ import { env } from 'node:process';
3
+ import { cookParticleCodeEffect } from '@forgeax/engine-vfx-compiler';
4
+ import { buildEngineShaderManifest } from '@forgeax/engine-vite-plugin-shader';
5
+ import { it } from 'vitest';
6
+ import { verifyVfxMeshLighting } from './vfx-mesh-lighting.fixture';
7
+
8
+ it('verifies Mesh Point/IBL parity and depth-dependent shadow latency on Dawn', async () => {
9
+ const manifest = await buildEngineShaderManifest({ pointShadows: true });
10
+ await verifyVfxMeshLighting({
11
+ shaderManifestUrl: `data:application/json,${encodeURIComponent(JSON.stringify(manifest))}`,
12
+ cook: cookParticleCodeEffect,
13
+ tapePaths: env,
14
+ saveTape: writeFileSync,
15
+ });
16
+ }, 120_000);