feat(control): spawn session NPCs and resize tokens in preview

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-08-18 14:42:06 +08:00
parent 1ab6ffd593
commit 1a9f0f2557
28 changed files with 1446 additions and 89 deletions
@@ -46,6 +46,29 @@ void test('SceneNpcTokensSessionStore setDisposition without inventing position'
assert.equal(s2.byPlacementId.a?.disposition, 'hostile');
});
void test('SceneNpcTokensSessionStore spawn is session-only and despawn removes it', () => {
const store = new SceneNpcTokensSessionStore();
const s1 = store.dispatch({
kind: 'spawn',
npcId: 'npc1',
sceneId: 'sceneA',
nx: 0.4,
ny: 0.6,
disposition: 'hostile',
});
const ids = Object.keys(s1.spawned);
assert.equal(ids.length, 1);
const spawn = s1.spawned[ids[0]!];
assert.equal(spawn?.npcId, 'npc1');
assert.equal(spawn?.sceneId, 'sceneA');
assert.equal(spawn?.nx, 0.4);
const s2 = store.dispatch({ kind: 'move', placementId: ids[0]!, nx: 0.7, ny: 0.2 });
assert.equal(s2.spawned[ids[0]!]?.nx, 0.7);
const s3 = store.dispatch({ kind: 'despawn', placementId: ids[0]! });
assert.deepEqual(s3.spawned, {});
assert.equal(s3.byPlacementId[ids[0]!], undefined);
});
void test('SceneNpcTokensSessionStore setInactive is session flag', () => {
const store = new SceneNpcTokensSessionStore();
const s1 = store.dispatch({ kind: 'setInactive', placementId: 'a', inactive: true });
@@ -58,3 +81,24 @@ void test('SceneNpcTokensSessionStore setInactive is session flag', () => {
assert.equal(s3.byPlacementId.a?.nx, 0.2);
assert.equal(s3.byPlacementId.a?.inactive, undefined);
});
void test('SceneNpcTokensSessionStore setSize is session-only and survives move', () => {
const store = new SceneNpcTokensSessionStore();
const s1 = store.dispatch({ kind: 'setSize', placementId: 'a', sizeN: 0.2 });
assert.equal(s1.byPlacementId.a?.sizeN, 0.2);
assert.equal(s1.byPlacementId.a?.nx, undefined);
const s2 = store.dispatch({ kind: 'move', placementId: 'a', nx: 0.3, ny: 0.4 });
assert.equal(s2.byPlacementId.a?.sizeN, 0.2);
assert.equal(s2.byPlacementId.a?.nx, 0.3);
const spawned = store.dispatch({
kind: 'spawn',
npcId: 'npc1',
sceneId: 'sceneA',
nx: 0.5,
ny: 0.5,
});
const id = Object.keys(spawned.spawned)[0]!;
const s3 = store.dispatch({ kind: 'setSize', placementId: id, sizeN: 0.18 });
assert.equal(s3.spawned[id]?.sizeN, 0.18);
assert.equal(s3.byPlacementId[id]?.sizeN, 0.18);
});