Spawn node: place assets at runtime into the play copy, Spawner demo behavior

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Fable 5.1 committed 2026-09-07 16:57:19 +02:00
1 parent c3a533c4e5
commit 91ee2feadd
13 files changed
+219 -37

No files matched your search

+35
View File
@@ -82,6 +82,41 @@ describe('world ↔ model synchronisation (editing while playing)', () => {
expect(sceneOf().objects.map((o) => o.id)).toEqual([a]);
});
it('spawn adds an object to the runtime scene and an entity at once, without resetting others', () => {
const { project, sceneId, spriteId, a, sceneOf } = setup();
const world = World.instantiate(project, sceneId);
const entityA = world.findByObjectId(a)!;
entityA.x = 77; // moved earlier in this tick – a spawn must not pull the model value back
const child = world.spawn(spriteId, { x: 10, y: 20, z: 1 }, entityA)!;
expect(child).not.toBeNull();
expect(child.parent).toBe(entityA);
expect(child.type).toBe('sprite');
expect(child.name).toBe('Box');
expect(child.props.width).toBe(100);
expect(entityA.x).toBe(77);
const object = sceneOf().objects.find((o) => o.id === child.objectId)!;
expect(object.parentId).toBe(a);
expect(object.position).toEqual({ x: 10, y: 20, z: 1 });
// The spawn is a structural change the panels must see – reported once.
expect(world.syncToModel()).toBe(true);
expect(world.syncToModel()).toBe(false);
// A full sync from the model keeps the spawned entity (identity included).
world.syncFromModel();
expect(world.findByObjectId(child.objectId)).toBe(child);
expect(child.parent).toBe(entityA);
// Destroying the spawned entity drops its object again.
world.remove(child);
expect(world.syncToModel()).toBe(true);
expect(sceneOf().objects.some((o) => o.id === child.objectId)).toBe(false);
// Unknown or unplaceable assets spawn nothing.
expect(world.spawn('nope', { x: 0, y: 0, z: 0 }, null)).toBeNull();
expect(world.spawn(sceneId, { x: 0, y: 0, z: 0 }, null)).toBeNull();
});
it('a play-mode copy leaves the original model untouched', () => {
const { project, sceneId, a, object } = setup();
const copy = deserializeProject(serializeProject(project), project.id);