Implement Phase 10a - Prop Scaling

- Added specifications for Phase 10a, introducing permanent size changes to `.prop` documents and reversible uniform instance scaling in Sandbox EDIT mode.
- Updated `PropCanvas`, `PropAnchorData`, `PropEditor`, `StageGizmos`, `SandboxStage`, and `StageSelection` classes to support new scaling features.
- Implemented document transactions for scaling, including normalization to a 96 px maximum dimension.
- Introduced a new **Transform Whole Prop** tool in the Prop Editor for moving, rotating, and resizing props.
- Created unit tests for the new scaling functionality, validating shape scaling, anchor transformations, and whole-prop interactions.
- Ensured compatibility with existing prop formats and maintained the integrity of the document structure during scaling operations.
This commit is contained in:
2026-09-22 22:23:31 -04:00
parent 97f3730413
commit 0a7f97cec7
18 changed files with 1782 additions and 78 deletions
+8 -1
View File
@@ -885,7 +885,14 @@ Each entry in the `shapes` array:
## File format (`.prop`)
The **Prop Editor** (Phase 9) authors vector prop assets saved as `.prop` files, stored under `res://props/*.prop`. Files are UTF-8 JSON, pretty-printed with tab indentation, versioned, and designed to remain **backward compatible** — the format stores the editor's full multi-shape stack, while a deterministic converter (`PropFile.flatten_to_payload()`) collapses it into the single-shape payload `PropUtils.spawn_prop()` consumes at runtime (frontmost closed polygon → else circle → else the first shape; lines are editor-only and never become collision geometry).
The **Prop Editor** (Phase 9, extended by Phase 10a) authors vector prop assets saved as `.prop` files, stored under `res://props/*.prop`. Files are UTF-8 JSON, pretty-printed with tab indentation, versioned, and designed to remain **backward compatible** — the format stores the editor's full multi-shape stack, while a deterministic converter (`PropFile.flatten_to_payload()`) collapses it into the single-shape payload `PropUtils.spawn_prop()` consumes at runtime (frontmost closed polygon → else circle → else the first shape; lines are editor-only and never become collision geometry).
In the Prop Editor, Arrange exposes **Transform Whole Prop**, **Normalize Size**,
**Center Prop**, and **Show Stickman Guide** in that order. Whole-prop move,
origin-based rotation, and uniform resize preview from a snapshot and commit once;
Snap rounds movement, Ctrl snaps rotation to 15°, and Esc cancels. The Sandbox
Stage has a separate single-prop corner scale gesture whose visual and collision
bounds remain synchronized during PLAY.
```json
{