Editing while playing: play runs on a runtime copy, new Game tab (Scene | Game | Graph)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Fable 5.1 committed 2026-09-07 16:34:26 +02:00
1 parent cb8885359f
commit c3a533c4e5
14 files changed
+408 -118

No files matched your search

-1
View File
@@ -35,7 +35,6 @@ export class AssetPanel extends Panel {
state.on('project', () => this.refresh());
state.on('load', () => this.refresh());
state.on('selection', () => this.syncSelection());
state.on('mode', () => this.setEnabled(state.mode === 'edit'));
this.refresh();
}
-1
View File
@@ -55,7 +55,6 @@ export class HierarchyPanel extends Panel {
state.on('project', () => this.refresh());
state.on('load', () => this.refresh());
state.on('selection', () => this.syncSelection());
state.on('mode', () => this.setEnabled(state.mode === 'edit'));
this.refresh();
}
+17 -2
View File
@@ -1,3 +1,4 @@
import type { Container } from 'pixi.js';
import { RenameAssetCommand, ResetAssetPropertyCommand, SetAssetPropertyCommand } from '../../core/commands/assetCommands';
import { AddColliderCommand } from '../../core/commands/colliderCommands';
import { RemoveNodeCommand, SetNodeParamCommand } from '../../core/commands/graphCommands';
@@ -17,7 +18,7 @@ import { findAsset, findScene, findSceneObject } from '../../core/model/Project'
import type { SceneObject } from '../../core/model/SceneObject';
import { type PropertyDef, schemaForAsset, VARIABLE_KINDS, type VariableKind } from '../../core/properties/PropertySchema';
import { isModified, isOverridden, resolveAssetProps, resolveSceneObjectProps } from '../../core/properties/resolve';
import { Button, HStack, Label, Menu, type MenuItem, Panel, ScrollContainer, TextField, Theme, VStack } from '../../ui';
import { Button, HStack, Label, Menu, type MenuItem, Panel, ScrollContainer, TextField, Theme, ui, VStack } from '../../ui';
import { createField, createFieldRow, FIELD_LABEL_WIDTH, type FieldRow } from '../inspector/fieldFactory';
import type { EditorState, Selection } from '../state';
@@ -37,6 +38,8 @@ export class Inspector extends Panel {
private builtFor: Selection = null;
/** Describes the structure the fields were built for; a change means a rebuild. */
private signature = '';
/** Last live refresh (play mode), in ms – the world ticks far more often than the eye needs. */
private lastLiveRefresh = 0;
constructor(private readonly state: EditorState) {
super({ title: 'Inspector', padding: 0, gap: 0 });
@@ -46,10 +49,22 @@ export class Inspector extends Panel {
state.on('selection', () => this.rebuild());
state.on('load', () => this.rebuild());
state.on('project', () => this.refreshValues());
state.on('mode', () => this.setEnabled(state.mode === 'edit'));
state.on('runtime', () => this.refreshLive());
this.rebuild();
}
/**
* Play mode: show what the behaviors are doing to the selected object, ~10× a second.
* Skipped while a field in here is being edited so the typed text is not overwritten.
*/
private refreshLive(): void {
const now = performance.now();
if (now - this.lastLiveRefresh < 100) return;
for (let node: Container | null = ui().focus.focused; node; node = node.parent) if (node === this) return;
this.lastLiveRefresh = now;
this.refreshValues();
}
private rebuild(): void {
this.builtFor = this.state.selection;
this.body.destroy({ children: true });
+3 -2
View File
@@ -93,8 +93,9 @@ export class Toolbar extends HStack {
const scenes = listScenes(state.project);
this.sceneButton.setText(scene ? `${scene.name} ▾` : scenes.length ? 'Select scene ▾' : 'No scene ▾');
const editing = state.mode === 'edit';
this.undoButton.setEnabled(editing && state.commands.canUndo);
this.redoButton.setEnabled(editing && state.commands.canRedo);
// Undo/redo work in play mode too – on the runtime copy's own history.
this.undoButton.setEnabled(state.commands.canUndo);
this.redoButton.setEnabled(state.commands.canRedo);
this.playButton.setText(editing ? '▶ Play' : '■ Stop');
this.playButton.variant = editing ? 'primary' : 'danger';
this.playButton.setEnabled(scene !== undefined);