Z-order via position.z and reset-to-default for asset properties

- Position is now { x, y, z }; higher z draws on top, ties keep hierarchy order
- Viewport sorts the objects layer deterministically (syncDrawOrder)
- Inspector shows a Z field; asset properties that differ from the schema
  default are marked bold with a reset button (ResetAssetPropertyCommand)
- isModified() helper, unit tests, E2E checks and seed updated

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Fable 5.1 committed 2026-09-07 11:42:18 +02:00
1 parent aaa8154adf
commit d4b1ffa051
18 files changed
+232 -63

No files matched your search

+14
View File
@@ -4,7 +4,21 @@ export type PropertyValue = number | string | boolean;
/** Sparse map of property key → value (asset properties or scene-object overrides). */
export type PropertyBag = Record<string, PropertyValue>;
/** A point in world or screen space. */
export interface Vec2 {
x: number;
y: number;
}
/**
* Where a scene object sits: `x`/`y` in world units, `z` is the draw order. Higher `z` is
* drawn on top; objects with equal `z` keep their hierarchy order.
*/
export interface Position extends Vec2 {
z: number;
}
/** Stable draw order: ascending `z`, ties keep the input (hierarchy) order. */
export function sortByZ<T extends { z: number }>(items: readonly T[]): T[] {
return [...items].sort((a, b) => a.z - b.z);
}
+6 -4
View File
@@ -1,4 +1,4 @@
import type { PropertyBag, Vec2 } from './Properties';
import type { Position, PropertyBag, Vec2 } from './Properties';
/**
* An asset placed inside a scene. It links to the asset by id, owns a position
@@ -10,10 +10,12 @@ export interface SceneObject {
assetId: string;
/** Optional display name; falls back to the asset name when empty. */
name: string;
position: Vec2;
/** World position plus draw order (`z`). */
position: Position;
overrides: PropertyBag;
}
export function createSceneObject(id: string, assetId: string, position: Vec2): SceneObject {
return { id, assetId, name: '', position: { x: position.x, y: position.y }, overrides: {} };
/** Creates a scene object; `z` defaults to 0 when the caller only has a 2D point. */
export function createSceneObject(id: string, assetId: string, position: Vec2 | Position): SceneObject {
return { id, assetId, name: '', position: { x: position.x, y: position.y, z: 'z' in position ? position.z : 0 }, overrides: {} };
}