Apply/revert buttons for overrides, container instances and child positions

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-07 17:59:35 +02:00
1 parent 0b78382bcc
commit 3379232e64
7 files changed
+544 -37

No files matched your search

+48
View File
@@ -769,6 +769,54 @@ try {
check('placing the container asset instantiates its content below a new container object', afterPlace.length === objectsBeforeDelete + 6 && secondCrate && secondCrate.position.x === -135 && secondCrate.position.y === 40, JSON.stringify({ count: afterPlace.length, secondCrate }));
await shot('26-container-placed');
// 16g. Apply / revert on a container instance. The red crate (o1) is part of the first
// container; the second instance has an unmodified copy of it. Moving o1 on x shows
// ↑ and ↺ on the X row; ↑ writes x into the template and the copy follows; undo takes
// both back; ↺ puts o1 back to the template value.
const templateA = () => evaluate(`JSON.stringify(__gm.state.project.assets.find(a => a.id === '${containerAsset.id}').objects.find(t => t.id === '${o1c.templateId}'))`).then(JSON.parse);
await evaluate(`__gm.state.select({ kind: 'object', sceneId: 'scene1', objectId: 'o1' })`);
await sleep(200);
check('inspector names the container the object is part of', Boolean(await evaluate(`__gm.locate(${JSON.stringify(containerAsset.name)})`)));
check('no apply/revert while the instance matches its template', !(await evaluate(`__gm.locate('↑')`)) && !(await evaluate(`__gm.locate('↺')`)));
await evaluate(`(() => { __gm.state.activeScene.objects.find(o => o.id === 'o1').position.x = -100; __gm.state.preview(); })()`);
await sleep(200);
const applyButton = await evaluate(`__gm.locate('↑')`);
check('a moved instance shows apply and revert on its X row', Boolean(applyButton) && Boolean(await evaluate(`__gm.locate('↺')`)));
await shot('27-apply-buttons');
await click(applyButton.x, applyButton.y);
await sleep(200);
check('apply writes x into the template and the unmodified copy follows', (await templateA()).position.x === -100 && JSON.parse(await objectJson(secondCrate.id)).position.x === -100, JSON.stringify({ template: (await templateA()).position, copy: JSON.parse(await objectJson(secondCrate.id)).position }));
check('apply hides the buttons again', !(await evaluate(`__gm.locate('↑')`)));
await keyPress('z', 'KeyZ', { modifiers: 2, windowsVirtualKeyCode: 90 });
await sleep(200);
check('undo restores template and copy', (await templateA()).position.x === -135 && JSON.parse(await objectJson(secondCrate.id)).position.x === -135);
const revertButton = await evaluate(`__gm.locate('↺')`);
await click(revertButton.x, revertButton.y);
await sleep(200);
check('revert puts the instance back to the template position', JSON.parse(await objectJson('o1')).position.x === -135);
// 16h. Overrides on an instance offer a menu: "Apply to container" or "Apply to asset".
await evaluate(`(() => { __gm.state.activeScene.objects.find(o => o.id === 'o1').overrides.width = 77; __gm.state.preview(); })()`);
await sleep(200);
const applyMenu = await evaluate(`__gm.locate('↑ ▾')`);
check('an overridden property on an instance shows the apply menu button', Boolean(applyMenu));
await click(applyMenu.x, applyMenu.y);
await sleep(150);
check('the menu offers container and asset', Boolean(await evaluate(`__gm.locate('Apply to container')`)) && Boolean(await evaluate(`__gm.locate('Apply to asset')`)));
await shot('28-apply-menu');
await clickText('Apply to asset');
await sleep(200);
const crateAfterApply = JSON.parse(await evaluate(`JSON.stringify(__gm.state.project.assets.find(a => a.id === 'crate').props)`));
check('Apply to asset writes the value into the asset and drops the override', crateAfterApply.width === 77 && JSON.parse(await objectJson('o1')).overrides.width === undefined, JSON.stringify(crateAfterApply));
await keyPress('z', 'KeyZ', { modifiers: 2, windowsVirtualKeyCode: 90 });
await sleep(200);
check('undo restores asset and override', (await evaluate(`__gm.state.project.assets.find(a => a.id === 'crate').props.width`)) === 100 && JSON.parse(await objectJson('o1')).overrides.width === 77);
await click(applyMenu.x, applyMenu.y);
await sleep(150);
await clickText('Apply to container');
await sleep(200);
check('Apply to container writes the override into the template and the copy', (await templateA()).overrides.width === 77 && JSON.parse(await objectJson(secondCrate.id)).overrides.width === 77);
check('no exceptions during run', !consoleLog.some((l) => l.startsWith('EXCEPTION')), consoleLog.filter((l) => l.startsWith('EXCEPTION')).slice(0, 3).join(' | '));
ws.close();
} catch (error) {