Split the object inspector, and sweep out the section banners

objectSection.ts had grown to 559 lines around three separable parts: the
queries, the vector rows and the parent row. Four object commands repeated the
same capture/restore preamble – applyCommands stays out, its five carry extra
undo state whose restore order matters.

58 dashed banner comments are gone. The nine labels in nodes/index.ts stay:
they are the only structure a flat 90-entry array has.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-10 07:14:45 +02:00
1 parent 11981b40d0
commit 3b3f374e10
11 files changed
+258 -244

No files matched your search

+62 -50
View File
@@ -1,6 +1,12 @@
import { newId } from '../ids';
import { isSelfOrAncestor, localPositionFor, removeSubtrees, worldPosition } from '../model/hierarchy';
import { captureObject, isLiveInstance, type ObjectMemo, restoreObject } from '../model/instance';
import {
captureObject,
isLiveInstance,
type ObjectMemo,
type ObjectRef,
restoreObject,
} from '../model/instance';
import { placementRejection } from '../model/placement';
import { type Position, type PropertyValue, toPosition, type Vec2 } from '../model/Properties';
import type { Project } from '../model/Project';
@@ -17,6 +23,33 @@ import {
requireStructural,
} from './require';
/**
* An edit to one placed object. The base captures the object before the edit and puts it back on
* undo, so a subclass only says what changes. `applyCommands` deliberately does not use this: its
* commands carry extra undo state whose restore order matters.
*/
abstract class ObjectEditCommand implements Command {
abstract readonly label: string;
private memo: ObjectMemo | undefined;
protected constructor(
private readonly holderId: string,
private readonly objectId: string,
) {}
protected abstract apply(ref: ObjectRef, project: Project): void;
execute(project: Project): void {
const ref = requireObjectRef(project, this.holderId, this.objectId);
this.memo = captureObject(ref);
this.apply(ref, project);
}
undo(): void {
if (this.memo) restoreObject(this.memo);
}
}
/**
* The position is a world position; with a parent it is converted to the parent's local space.
* Placing a container adds the container object alone – its content is resolved from the template
@@ -88,91 +121,70 @@ export class RemoveSceneObjectCommand extends RemoveSceneObjectsCommand {
* The previous position is read at execution time, so a caller that previewed the move must
* restore the model before executing.
*/
export class MoveSceneObjectCommand implements Command {
export class MoveSceneObjectCommand extends ObjectEditCommand {
readonly label = 'Move object';
private memo: ObjectMemo | undefined;
constructor(
private readonly holderId: string,
private readonly objectId: string,
holderId: string,
objectId: string,
private readonly position: Position,
) {}
execute(project: Project): void {
const ref = requireObjectRef(project, this.holderId, this.objectId);
this.memo = captureObject(ref);
ref.setPosition(this.position);
) {
super(holderId, objectId);
}
undo(): void {
if (this.memo) restoreObject(this.memo);
protected override apply(ref: ObjectRef): void {
ref.setPosition(this.position);
}
}
/** Editor-only: undoable like any other edit, but it changes nothing the game can see. */
export class SetEditorOffsetCommand implements Command {
export class SetEditorOffsetCommand extends ObjectEditCommand {
readonly label = 'Editor offset';
private memo: ObjectMemo | undefined;
constructor(
private readonly holderId: string,
private readonly objectId: string,
holderId: string,
objectId: string,
private readonly offset: Vec2,
) {}
) {
super(holderId, objectId);
}
execute(project: Project): void {
const ref = requireObjectRef(project, this.holderId, this.objectId);
this.memo = captureObject(ref);
protected override apply(ref: ObjectRef): void {
ref.setEditorOffset(this.offset);
}
undo(): void {
if (this.memo) restoreObject(this.memo);
}
}
export class RenameSceneObjectCommand implements Command {
export class RenameSceneObjectCommand extends ObjectEditCommand {
readonly label = 'Rename object';
private memo: ObjectMemo | undefined;
constructor(
private readonly holderId: string,
private readonly objectId: string,
holderId: string,
objectId: string,
private readonly name: string,
) {}
execute(project: Project): void {
const ref = requireObjectRef(project, this.holderId, this.objectId);
this.memo = captureObject(ref);
ref.setName(this.name);
) {
super(holderId, objectId);
}
undo(): void {
if (this.memo) restoreObject(this.memo);
protected override apply(ref: ObjectRef): void {
ref.setName(this.name);
}
}
abstract class OverrideCommand implements Command {
private memo: ObjectMemo | undefined;
abstract class OverrideCommand extends ObjectEditCommand {
protected constructor(
private readonly holderId: string,
private readonly objectId: string,
holderId: string,
objectId: string,
protected readonly key: string,
readonly label: string,
) {}
) {
super(holderId, objectId);
}
protected abstract nextValue(object: SceneObject, project: Project): PropertyValue | undefined;
execute(project: Project): void {
const ref = requireObjectRef(project, this.holderId, this.objectId);
this.memo = captureObject(ref);
protected override apply(ref: ObjectRef, project: Project): void {
ref.setOverride(this.key, this.nextValue(ref.object, project));
}
undo(): void {
if (this.memo) restoreObject(this.memo);
}
}
export class SetOverrideCommand extends OverrideCommand {