Duplicate an asset from its right-click menu (#297)
game-maker / gate (push) Successful in 3m4s
game-maker / suite (push) Successful in 14m16s

A new asset that starts out like an existing one (a death animation
next to "Break", a second slime) had to be built again by hand. Now
the asset panel's right-click menu has Duplicate.

- The copy lands right below the original and is named the way a new
  asset would be ("Crate 2"). It is selected and its tab opens where
  it has one. A copied scene does not become the active one.
- One undo step takes it out again. A redo brings back the same id.
- The copy is a deep copy: values, graph, tracks, layers and objects
  are its own, and editing it leaves the original alone.
- Frames of a texture or of pixel art get fresh ids, because a sprite
  names a frame across the whole document.
- Objects of a scene or container get fresh ids the way pasted ones
  do. Parents and object references among them follow the copy.
- Whatever pointed at the original keeps pointing at the original: a
  sprite wearing it, an animation's root, a placed object.

Tests:
- 3 new unit tests (DuplicateAssetCommand). One counter-check run:
  without renaming the references the scene test fails.
- e2e 04: 2 new checks with the real menu (copy named "Crate 2" right
  behind the Crate and selected, one undo removes it).
- Gate: 221 files, 3445 tests, CHECK EXIT 0.
- e2e total 1703 is computed (1701 + 2). Full suite left to CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-03 11:17:02 +02:00
1 parent 0dda6a012a
commit 4f4c149211
5 files changed
+128 -3

No files matched your search

+18 -1
View File
@@ -31,7 +31,24 @@ export async function assets(t) {
check('asset context menu opens', Boolean(await evaluate(`__gm.locate('Delete…')`)));
check('placing is no longer a menu item', !(await evaluate(`__gm.locate('Place in scene')`)));
await shot('11-context-menu');
await press('Escape');
await clickText('Duplicate');
const copy = await json(`(() => {
const assets = __gm.state.project.assets;
const c = assets[assets.findIndex((a) => a.id === 'crate') + 1];
const s = __gm.state.selection;
return c ? { name: c.name, type: c.type, open: s?.kind === 'asset' && s.assetId === c.id } : null;
})()`);
check(
'Duplicate puts "Crate 2" right behind the Crate and opens it',
copy?.name === 'Crate 2' && copy.type === 'sprite' && copy.open,
JSON.stringify(copy),
);
await undo();
check(
'one undo takes the copy back out',
!(await json("__gm.state.project.assets.some((a) => a.name === 'Crate 2')")),
);
await showTab('scene');
await addMenuOnRightClick(t);