The scene view and the animation preview share one camera, the three form dialogs one base, and keys are found through one set of helpers (#85)
game-maker / gate (push) Successful in 1m36s
game-maker / suite (push) Successful in 5m41s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-17 14:19:53 +02:00
1 parent bf02c9e8b3
commit 2a390e52ff
22 files changed
+418 -452

No files matched your search

+11 -8
View File
@@ -1,4 +1,5 @@
import type { KeyClipboard, KeyRef } from '../core/commands/animationCommands';
import type { KeyClipboard } from '../core/commands/animationCommands';
import { findKey, findTrack, hasKey, type KeyRef, sameKey } from '../core/model/animation';
import { type Command, CommandError } from '../core/commands/Command';
import { CommandStack } from '../core/commands/CommandStack';
import type { Asset, SceneAsset } from '../core/model/Asset';
@@ -126,8 +127,7 @@ export function graphSelection(
*/
export function trackSelection(assetId: string, keys: readonly KeyRef[], trackId?: string): Selection {
const unique: KeyRef[] = [];
for (const key of keys)
if (!unique.some((k) => k.trackId === key.trackId && k.frame === key.frame)) unique.push(key);
for (const key of keys) if (!hasKey(unique, key)) unique.push(key);
const last = unique[unique.length - 1];
const row = trackId ?? last?.trackId;
return row ? { kind: 'track', assetId, trackId: row, keys: unique } : null;
@@ -495,10 +495,8 @@ export class EditorState {
if (!asset) this.select(null);
else {
// A key that moved or died leaves the selection; a row that died takes its keys with it.
const alive = s.keys.filter((key) =>
asset.tracks.some((t) => t.id === key.trackId && t.keys.some((k) => k.frame === key.frame)),
);
const rowAlive = asset.tracks.some((t) => t.id === s.trackId);
const alive = s.keys.filter((key) => findKey(asset, key));
const rowAlive = findTrack(asset, s.trackId) !== undefined;
if (alive.length !== s.keys.length || !rowAlive)
this.select(
trackSelection(s.assetId, alive, rowAlive ? s.trackId : undefined) ?? {
@@ -525,6 +523,11 @@ export class EditorState {
return findAssetOf(this.project, s.assetId, 'animation')?.id ?? null;
}
/** The timeline row the selection is about; undefined when it is about something else. */
get selectedTrackId(): string | undefined {
return this.selection?.kind === 'track' ? this.selection.trackId : undefined;
}
/** The keys picked in the Animation tab, none when the selection is about something else. */
get selectedKeys(): KeyRef[] {
return this.selection?.kind === 'track' ? this.selection.keys : [];
@@ -627,7 +630,7 @@ export function sameSelection(a: Selection, b: Selection): boolean {
a.assetId === b.assetId &&
a.trackId === b.trackId &&
a.keys.length === b.keys.length &&
a.keys.every((key, i) => key.trackId === b.keys[i]!.trackId && key.frame === b.keys[i]!.frame)
a.keys.every((key, i) => sameKey(key, b.keys[i]!))
);
if (a.kind === 'annotation' && b.kind === 'annotation')
return (