Drop a picture or video onto a composition track (#419)
A track item has always carried an object, and an object needs an asset. Instead of objects without one, a dropped picture or video gets a sprite the composition owns, the way a song owns its sounds (#355). To the rest of the code it is a sprite like any other. - The asset list starts a drag for textures, vector art, pixel art and videos. Dropped on a track, they make the sprite and the item in one undo step. A video item is as long as the video and follows it. - One sprite per picture and composition. A second drop of the same video shares it. Once no item wears it, it goes in the same step. - Deleting a composition takes its sprites along. A duplicate gets sprites of its own. - Pasting into a scene or container turns the sprite into a project asset. Pasting into another composition gives that one a copy. The clipboard carries the sprite, so cut and paste loses nothing. - Owned sprites stay out of the asset list and the pickers. The inspector shows them with a dot in front. - "Make project asset" in the item's menu, on the timeline and in the hierarchy, turns the sprite into an ordinary one. - The first track of the Composition tab gets its top line, as the Song tab's has. Found on the way: loading kept an owner only for the asset types a song can hold. A composition's sprite would have lost its owner and turned up in the list after a reload. Tests: - Unit composition-sprites: 11 new. Without the rule 5 of them are red, without the loading fix the loading test is. - e2e 69 on melektaus-atx: ALL PASSED, 15 checks, 69k new - Gate on melektaus-atx: 305 files, 4714 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f171c77f91
commit
b16fe8c718
18 files changed
+573
-49
No files matched your search
@@ -369,11 +369,14 @@ export function deserializeProject(raw: unknown, fallbackId = ''): Project {
|
||||
assets.push({ id, type, name, props });
|
||||
}
|
||||
const owner = typeof a.owner === 'string' ? a.owner : '';
|
||||
if (owner && isEmbeddable(type)) assets[assets.length - 1]!.owner = owner;
|
||||
if (owner && (isEmbeddable(type) || type === 'sprite')) assets[assets.length - 1]!.owner = owner;
|
||||
}
|
||||
// One whose song or composition (#419) is gone is kept as a project asset rather than lost (#355).
|
||||
const ownerType = new Map(assets.map((a) => [a.id, a.type]));
|
||||
for (const asset of assets) {
|
||||
if (!asset.owner) continue;
|
||||
if (ownerType.get(asset.owner) !== (asset.type === 'sprite' ? 'composition' : 'song')) delete asset.owner;
|
||||
}
|
||||
// One whose song is gone is kept as a project asset rather than lost (#355).
|
||||
const songs = new Set(assets.filter((a) => a.type === 'song').map((a) => a.id));
|
||||
for (const asset of assets) if (asset.owner && !songs.has(asset.owner)) delete asset.owner;
|
||||
|
||||
let activeSceneId = typeof r.activeSceneId === 'string' ? r.activeSceneId : '';
|
||||
if (!assets.some((a) => a.type === 'scene' && a.id === activeSceneId)) {
|
||||
|
||||
Reference in new issue
Block a user