@forgeax/engine-runtime 0.1.28 → 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 (113) 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 -32
  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-rendering-materials.browser.test.ts +617 -0
  101. package/src/__tests__/wave1-rendering-p0.browser.test.ts +751 -0
  102. package/src/__tests__/wave1-rendering-recovery.browser.test.ts +666 -0
  103. package/src/__tests__/wave1-shadow-diagnostic.browser.test.ts +582 -0
  104. package/src/__tests__/world-scene-despawn.test.ts +8 -8
  105. package/src/__tests__/world-scene-instantiate.test.ts +23 -29
  106. package/src/__tests__/world-scene-nested.test.ts +90 -163
  107. package/src/__tests__/world-scene-override.test.ts +17 -16
  108. package/src/__tests__/zero-compression-zero-load.integration.test.ts +1 -0
  109. package/src/collect-scene-asset.ts +637 -19
  110. package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
  111. package/src/index.ts +1 -0
  112. package/src/scene-utils/mount-override-fold.ts +5 -14
  113. package/src/__tests__/node-shims.d.ts +0 -31
@@ -1,202 +1,56 @@
1
- // scene-mount-wrapper-roundtrip.test.ts — regression for the editor "Add to
2
- // Scene" ghost-node accretion bug.
3
- //
4
- // The editor's whole-GLB Add-to-Scene (spawnGlbSceneAsMount) produces a scene
5
- // pack shaped like:
6
- // entities: [ ..., { localId: W, Name:"bed.glb", Transform, Children:[M] } ]
7
- // mounts: [ { localId: M, source: <bedGUID>, memberCount: N, parent: W } ]
8
- // i.e. an OWNED wrapper entity whose child is a nested mount. This is the exact
9
- // on-disk shape after the first add+save.
10
- //
11
- // On RELOAD, world.instantiateScene re-materialises the mount as a plain "mount
12
- // entity" (no Name, no SceneInstance — just Transform/ChildOf/Children) sitting
13
- // BETWEEN the wrapper and the child SceneInstance root. On the NEXT collect that
14
- // plain mount entity carries no SceneInstance, so rootsToSceneAsset emitted it
15
- // as an OWNED (nameless) entity + a fresh mount — one extra ghost node per
16
- // save→reload cycle. This test asserts collect is a FIXED POINT across two
17
- // reload cycles.
18
-
19
1
  import type { Asset } from '@forgeax/engine-assets-runtime';
20
2
  import { AssetRegistry } from '@forgeax/engine-assets-runtime';
21
3
  import { World } from '@forgeax/engine-ecs';
22
4
  import { AssetGuid } from '@forgeax/engine-pack/guid';
23
- import { Children, Name, Transform } from '@forgeax/engine-scene';
5
+ import { SceneInstance } from '@forgeax/engine-render';
24
6
  import type { Handle, SceneAsset } from '@forgeax/engine-types';
25
7
  import { describe, expect, it } from 'vitest';
26
- import { rootsToSceneAsset, serializeSceneAssetToPack } from '../collect-scene-asset';
8
+ import { rootsToSceneAsset } from '../collect-scene-asset';
27
9
  import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
28
10
  import { registerSceneComponents } from './helpers/register-scene-components';
29
11
 
30
- const G_CHILD = '11111111-1111-4111-8111-111111111111';
31
- const G_TOP = '22222222-2222-4222-8222-222222222222';
32
-
33
- function mkReg(): AssetRegistry {
34
- return new AssetRegistry(makeMockShaderRegistry());
35
- }
36
- function pg(s: string): AssetGuid {
37
- const r = AssetGuid.parse(s);
38
- if (!r.ok) throw new Error(`bad GUID: ${s}`);
39
- return r.value;
40
- }
41
- function cat(reg: AssetRegistry, g: string, p: SceneAsset): void {
42
- reg.catalog(pg(g), p as Asset);
43
- }
44
- function rs(w: World, a: SceneAsset): Handle<'SceneAsset', 'shared'> {
45
- registerSceneComponents(w, [Name]);
46
- return w.allocSharedRef('SceneAsset', a);
47
- }
48
- function accessParse(reg: AssetRegistry) {
49
- const internal = reg as unknown as {
50
- parseAssetPayload(kind: string, payload: Record<string, unknown>, refs?: string[]): unknown;
51
- };
52
- return (payload: Record<string, unknown>, refs?: readonly string[]): SceneAsset =>
53
- internal.parseAssetPayload('scene', payload, refs as string[] | undefined) as SceneAsset;
12
+ const CHILD = '11111111-1111-4111-8111-111111111111';
13
+ function guid(value: string): AssetGuid {
14
+ const result = AssetGuid.parse(value);
15
+ if (!result.ok) throw new Error(`bad GUID: ${value}`);
16
+ return result.value;
54
17
  }
55
- function unpack(pack: Record<string, unknown>): {
56
- payload: Record<string, unknown>;
57
- refs: readonly string[] | undefined;
58
- } {
59
- const a = (pack.assets as Record<string, unknown>[])[0] as Record<string, unknown>;
60
- return { payload: a.payload as Record<string, unknown>, refs: a.refs as string[] | undefined };
18
+ function makeHandle(world: World, asset: SceneAsset): Handle<'SceneAsset', 'shared'> {
19
+ registerSceneComponents(world);
20
+ return world.allocSharedRef('SceneAsset', asset);
61
21
  }
62
22
 
63
- describe('editor Add-to-Scene wrapper+mount round-trip (ghost accretion regression)', () => {
64
- it('collect is a fixed point across reload cycles (no nameless ghost accretes)', () => {
65
- const reg = mkReg();
66
- const w = new World();
67
-
68
- // Child scene = the "bed": one owned mesh entity.
23
+ describe('keyed instance wrapper collect', () => {
24
+ it('collect preserves the wrapper key, source and explicit parent declaration', () => {
25
+ const registry = new AssetRegistry(makeMockShaderRegistry());
26
+ const world = new World();
69
27
  const child: SceneAsset = {
70
28
  kind: 'scene',
71
- entities: [
72
- {
73
- localId: 0 as never,
74
- components: { Name: { value: 'bed-mesh' }, Transform: { pos: [0, 0, 0] } },
75
- },
76
- ],
29
+ entities: { leaf: { components: { Transform: {} } } },
77
30
  };
78
- cat(reg, G_CHILD, child);
79
-
80
- // Plain top scene with ONE owned entity (like spin-cube's Ground). The
81
- // editor adds the mount live below via a wrapper (no mounts[] on disk yet).
82
- const top: SceneAsset = {
31
+ expect(registry.catalog(guid(CHILD), child as Asset).ok).toBe(true);
32
+ const parent: SceneAsset = {
83
33
  kind: 'scene',
84
- entities: [
85
- {
86
- localId: 0 as never,
87
- components: { Name: { value: 'Ground' }, Transform: { pos: [0, 0, 0] } },
34
+ entities: {
35
+ root: { components: { Transform: {} } },
36
+ wrapper: {
37
+ components: { ChildOf: { parent: 'root' } },
38
+ instance: { source: CHILD },
88
39
  },
89
- ],
40
+ },
90
41
  };
91
- cat(reg, G_TOP, top);
92
-
93
- const parse = accessParse(reg);
94
-
95
- const runCycle = (roots: number[]): { owned: number; mounts: number; pack: SceneAsset } => {
96
- const c = rootsToSceneAsset(reg, w, roots as never);
97
- if (!c.ok) throw new Error(`collect failed: ${JSON.stringify(c.error)}`);
98
- return {
99
- owned: c.value.entities.length,
100
- mounts: (c.value.mounts ?? []).length,
101
- pack: c.value,
102
- };
103
- };
104
-
105
- // The editor's owned top-level roots after a reload = the named entities the
106
- // session tracks (store.ts _e2h owned-set: the scene asset's entities[], not
107
- // mount internals). Mirror that here by taking the NAMED entities reachable
108
- // from the scene (Ground + the bed.glb wrapper), excluding the nameless
109
- // mount carrier — exactly what the editor collects via entRootHandles.
110
- const namedTopEntities = (syntheticRoot: number): number[] => {
111
- const wr = w as unknown as {
112
- get(
113
- e: number,
114
- c: unknown,
115
- ): {
116
- ok: boolean;
117
- value?: { entities?: ArrayLike<number>; value?: string; parent?: number };
118
- };
119
- };
120
- // BFS from the synthetic root over Children; keep NAMED entities whose
121
- // parent is not itself a named-tracked entity (i.e. top-level owned roots).
122
- const named: number[] = [];
123
- const queue = [syntheticRoot];
124
- const seen = new Set<number>([syntheticRoot]);
125
- while (queue.length) {
126
- const cur = queue.shift() as number;
127
- const ch = wr.get(cur, Children);
128
- if (ch.ok && ch.value?.entities) {
129
- for (const k of Array.from(ch.value.entities)) {
130
- if (seen.has(k)) continue;
131
- seen.add(k);
132
- queue.push(k);
133
- if (wr.get(k, Name).ok) named.push(k);
134
- }
135
- }
136
- }
137
- return named;
138
- };
139
-
140
- // Instantiate the top scene.
141
- const i0 = reg.instantiate(rs(w, top), w);
142
- expect(i0.ok).toBe(true);
143
- if (!i0.ok) return;
144
-
145
- // ── Editor "Add to Scene": spawn a NAMED wrapper parented under the top
146
- // scene, then mount the child scene UNDER the wrapper (instantiate with
147
- // parent=wrapper). Mirrors spawnGlbSceneAsMount +
148
- // instantiateSceneRefUnderWorld. ──
149
- const wrapperRes = w.spawn(
150
- { component: Name, data: { value: 'bed.glb' } },
151
- { component: Transform, data: { pos: [0, 0, 0] } },
152
- );
153
- expect(wrapperRes.ok).toBe(true);
154
- if (!wrapperRes.ok) return;
155
- const mountRes = reg.instantiate(rs(w, child), w, wrapperRes.value);
156
- expect(mountRes.ok).toBe(true);
157
- if (!mountRes.ok) return;
158
-
159
- // Cycle 1: collect from the owned roots (Ground + wrapper).
160
- // Ground is a child of the synthetic root; the wrapper is a free root we
161
- // just spawned. Collect from both (the editor's entRootHandles set).
162
- const groundRoots = namedTopEntities(i0.value as unknown as number);
163
- const c1 = runCycle([...groundRoots, wrapperRes.value as unknown as number]);
164
-
165
- // Cycle 2: serialize → parse → reload → collect.
166
- const s1 = serializeSceneAssetToPack(c1.pack, w.components.entries(), G_TOP);
167
- expect(s1.ok).toBe(true);
168
- if (!s1.ok) return;
169
- const u1 = unpack(s1.value);
170
- const p1 = parse(u1.payload, u1.refs);
171
- cat(reg, G_TOP, p1);
172
- const i1 = reg.instantiate(rs(w, p1), w);
173
- expect(i1.ok).toBe(true);
174
- if (!i1.ok) return;
175
- const c2 = runCycle(namedTopEntities(i1.value as unknown as number));
176
-
177
- // Cycle 3: reload + collect once more (the ghost-accretion point).
178
- const s2 = serializeSceneAssetToPack(c2.pack, w.components.entries(), G_TOP);
179
- expect(s2.ok).toBe(true);
180
- if (!s2.ok) return;
181
- const u2 = unpack(s2.value);
182
- const p2 = parse(u2.payload, u2.refs);
183
- cat(reg, G_TOP, p2);
184
- const i2 = reg.instantiate(rs(w, p2), w);
185
- expect(i2.ok).toBe(true);
186
- if (!i2.ok) return;
187
- const c3 = runCycle(namedTopEntities(i2.value as unknown as number));
188
-
189
- // ACCEPTANCE: owned + mount counts are a FIXED POINT across reloads (before
190
- // the fix this grew unboundedly: owned 2 → 3 → 5, one nameless ghost per
191
- // cycle). Ground + bed.glb wrapper = 2 owned; the bed = 1 mount.
192
- expect({ owned: c1.owned, mounts: c1.mounts }).toEqual({ owned: 2, mounts: 1 });
193
- expect({ owned: c2.owned, mounts: c2.mounts }).toEqual({ owned: 2, mounts: 1 });
194
- expect({ owned: c3.owned, mounts: c3.mounts }).toEqual({ owned: 2, mounts: 1 });
195
-
196
- // No owned entity is nameless (the ghost signature).
197
- for (const e of c3.pack.entities) {
198
- const comps = e.components as Record<string, Record<string, unknown>>;
199
- expect(comps.Name, `owned entity localId ${e.localId} must have a Name`).toBeDefined();
200
- }
42
+ const result = registry.instantiate(makeHandle(world, parent), world);
43
+ expect(result.ok).toBe(true);
44
+ if (!result.ok) return;
45
+ expect(
46
+ [...world.iterDescendants(result.value)].filter(
47
+ (entity) => world.get(entity, SceneInstance).ok,
48
+ ),
49
+ ).toHaveLength(1);
50
+ const collected = rootsToSceneAsset(registry, world, [result.value]);
51
+ expect(collected.ok).toBe(true);
52
+ if (!collected.ok) return;
53
+ expect(collected.value.entities.wrapper?.instance?.source).toBe(CHILD);
54
+ expect(collected.value.entities.wrapper?.components.ChildOf).toEqual({ parent: 'root' });
201
55
  });
202
56
  });
@@ -21,24 +21,23 @@ import { AssetRegistry } from '@forgeax/engine-assets-runtime';
21
21
  import { defineComponent, type EntityHandle, World } from '@forgeax/engine-ecs';
22
22
  import { SceneInstance } from '@forgeax/engine-render';
23
23
  import { ChildOf } from '@forgeax/engine-scene';
24
- import type { Handle, LocalEntityId, SceneAsset, SceneEntity } from '@forgeax/engine-types';
24
+ import type { Handle, SceneAsset, SceneEntity } from '@forgeax/engine-types';
25
25
  import { toShared } from '@forgeax/engine-types';
26
26
  import { describe, expect, it } from 'vitest';
27
27
  import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
28
28
  import { registerRuntimeComponents } from './helpers/register-runtime-components';
29
29
 
30
- function localId(n: number): LocalEntityId {
31
- return n as LocalEntityId;
32
- }
33
-
34
30
  function buildScene(): SceneAsset {
35
31
  const Transform = defineComponent('Transform', { pos: 'array<f32, 3>' });
36
32
  void Transform;
37
33
  const nodes: SceneEntity[] = [
38
- { localId: localId(0), components: { Transform: { pos: [1, 0, 0] } } },
39
- { localId: localId(1), components: { Transform: { pos: [2, 0, 0] } } },
34
+ { key: 'entity-0', components: { Transform: { pos: [1, 0, 0] } } },
35
+ { key: 'entity-1', components: { Transform: { pos: [2, 0, 0] } } },
40
36
  ];
41
- return { kind: 'scene', entities: nodes };
37
+ return {
38
+ kind: 'scene',
39
+ entities: Object.fromEntries(nodes.map(({ key, components }) => [key, { components }])),
40
+ };
42
41
  }
43
42
 
44
43
  function registerSceneAsset(world: World, asset: SceneAsset): Handle<'SceneAsset', 'shared'> {
@@ -142,11 +141,17 @@ describe('w30 - engine.assets.instantiate sugar wrapper equivalence (AC-03)', ()
142
141
  // array is a snapshot at call time, not a live view (SceneInstance contract).
143
142
 
144
143
  function buildPostScene(): SceneAsset {
145
- const nodes: SceneEntity[] = [
146
- { localId: localId(0), components: { Transform: { pos: [0, 0, 0] } } },
147
- { localId: localId(1), components: { Transform: { pos: [1, 0, 0] }, ChildOf: { parent: 0 } } },
144
+ const nodes: Array<SceneEntity & { readonly key: string }> = [
145
+ { key: 'entity-0', components: { Transform: { pos: [0, 0, 0] } } },
146
+ {
147
+ key: 'entity-1',
148
+ components: { Transform: { pos: [1, 0, 0] }, ChildOf: { parent: 'entity-0' } },
149
+ },
148
150
  ];
149
- return { kind: 'scene', entities: nodes };
151
+ return {
152
+ kind: 'scene',
153
+ entities: Object.fromEntries(nodes.map(({ key, components }) => [key, { components }])),
154
+ };
150
155
  }
151
156
 
152
157
  // A lightweight component for post-instantiate injection testing.
@@ -227,8 +232,8 @@ describe('M5 post-instantiate component injection (w13 / AC-09 + AC-10)', () =>
227
232
  // Two root nodes, each gets a different component via query-after.
228
233
  defineComponent('Transform', { pos: 'array<f32, 3>' });
229
234
  const multiRoot: SceneEntity[] = [
230
- { localId: localId(0), components: { Transform: { pos: [0, 0, 0] } } },
231
- { localId: localId(1), components: { Transform: { pos: [10, 0, 0] } } },
235
+ { key: 'entity-0', components: { Transform: { pos: [0, 0, 0] } } },
236
+ { key: 'entity-1', components: { Transform: { pos: [10, 0, 0] } } },
232
237
  ];
233
238
  const reg = new AssetRegistry(makeMockShaderRegistry());
234
239
  const world = new World();
@@ -267,7 +272,7 @@ describe('M5 post-instantiate component injection (w13 / AC-09 + AC-10)', () =>
267
272
  const world = new World();
268
273
  registerRuntimeComponents(world, [Enemy, Waypoint]);
269
274
  const singleRoot: SceneEntity[] = [
270
- { localId: localId(0), components: { Transform: { pos: [0, 0, 0] } } },
275
+ { key: 'entity-0', components: { Transform: { pos: [0, 0, 0] } } },
271
276
  ];
272
277
  const asset: SceneAsset = { kind: 'scene', entities: singleRoot };
273
278
  const handle = registerSceneAsset(world, asset);