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
+50 -8
View File
@@ -20,9 +20,10 @@ The window is divided into these areas:
| Area | Purpose |
| --- | --- |
| `📁 File` and `👁️ View` | File operations and canvas view reset |
| `Grid`, `Snap`, and `🎯 Center Prop` | Shared grid, snapping, and prop placement settings |
| `Grid` and `Snap` | Shared grid spacing and snapping settings |
| `Prop Name` | The name stored in the `.prop` file |
| Mode bar | Switch between `🖐️ Arrange`, `✏️ Reshape`, and `📌 Attach` |
| Arrange controls | Whole-prop transform, normalization, centering, and the stickman guide |
| Authoring canvas | Draw, select, transform, and reshape the prop |
| Inspector | Material, shape, primitive, and anchor controls |
| Holding Preview | A private stickman-and-prop preview shown in Attach mode |
@@ -75,11 +76,6 @@ The Holding Preview has its own `Reset View` button; see [Holding Preview](#hold
| --- | --- |
| `Grid` | Sets the visible grid spacing and the snap increment, from 1 to 512. |
| `Snap` | Enables or disables snapping for shape transforms and anchor movement. |
| `🎯 Center Prop` | Moves the complete prop so the combined shape bounds are centered on the fixed local origin. It also translates every non-origin anchor by the same amount and focuses the canvas on the origin. |
Center Prop is a deliberate one-time command. The editor does not recenter
automatically after drawing, reshaping, or moving a shape. Empty and already
centered props are unchanged.
## Prop name and modes
@@ -96,6 +92,38 @@ Arrange is the mode for selecting, moving, rotating, scaling, mirroring, and
ordering complete shapes. The Add Shape inspector and the shape Erase button
are available in this mode.
#### Arrange controls
The Arrange mode top bar keeps the whole-prop actions in this order:
1. `✥ Transform Whole Prop`
2. `📏 Normalize Size`
3. `🎯 Center Prop`
4. `Show Stickman Guide`
The scale textbox and Apply Scale button are not part of the editor. Use
Normalize Size for the standard document size, or use Transform Whole Prop for
direct canvas manipulation. Normalize Size fits the shape-point bounds to a
96 px maximum dimension while preserving the fixed origin and proportional
anchor offsets. Center Prop separately moves the shape bounds and editable
anchors around the canonical origin. It is a deliberate one-time command: the
editor does not recenter automatically after drawing, reshaping, or moving a
shape, and empty or already centered props are unchanged.
With Transform Whole Prop enabled, drag visible shape geometry to move the
whole prop, drag the dot below the union bounds to rotate it around the
canonical origin, or drag a corner cross to resize it uniformly. Snap rounds
the move delta to the current grid. Hold **Ctrl** while rotating to snap to
15-degree increments. Grip and other editable anchor markers follow each
operation. The tool previews from the starting document and commits once when
the gesture is released; **Esc** cancels the active preview. The canonical
origin itself does not move.
Transform Whole Prop and Normalize Size are hidden in Reshape and Attach.
Center Prop and Show Stickman Guide remain available in those modes. Turning
Transform Whole Prop off restores the selected shape and normal per-shape
Arrange gizmos.
When a shape is selected, the canvas draws:
- a two-tone selection outline and bounding box;
@@ -113,7 +141,9 @@ the selected shape.
### `✏️ Reshape`
Reshape is for editing individual vertices. It does not move the whole shape
and does not show the Add Shape section or Erase Shape button. When the canvas
and does not show the Add Shape section, Erase Shape button, Normalize Size,
or Transform Whole Prop. Center Prop and Show Stickman Guide remain available.
When the canvas
is empty, it does not show the Arrange-only “Right-click to add a shape” hint.
- Original vertices are filled circles.
@@ -133,7 +163,9 @@ private stickman Holding Preview. It does not add gameplay attachment or
physics behavior to Sandbox Stage.
Attach mode shows the Attach toolbar and the Anchors inspector. Shape editing
controls are hidden, but the prop remains visible on the authoring canvas.
controls are hidden, as are Normalize Size and Transform Whole Prop. Center Prop
and Show Stickman Guide remain available, and the prop remains visible on the
authoring canvas.
## Grid, Snap, and canvas navigation
@@ -491,10 +523,20 @@ Load dialogs report malformed or unsupported files through the Error dialog.
### Arrange transforms and context menu
- [ ] Confirm the Arrange top bar order is Transform Whole Prop, Normalize Size,
Center Prop, then Show Stickman Guide.
- [ ] Drag a selected shape body to translate it.
- [ ] Drag the rotation dot and confirm the shape rotates continuously.
- [ ] Hold Ctrl while rotating and confirm 15-degree stepping.
- [ ] Drag each scale cross; hold Ctrl and confirm uniform scaling.
- [ ] Enable Transform Whole Prop; drag visible geometry, the rotation dot, and
each corner cross, confirming that all shapes and editable anchors follow.
- [ ] With Snap enabled, move the whole prop and confirm the move delta follows
the current grid; hold Ctrl while rotating and confirm 15-degree snapping.
- [ ] Press Esc during a whole-prop gesture and confirm the preview cancels
without changing the document.
- [ ] Switch to Reshape or Attach and confirm Transform Whole Prop and
Normalize Size are hidden while Center Prop and Show Stickman Guide remain.
- [ ] Use Copy, right-click empty canvas, and Paste; confirm the pasted shape
is offset and selected.
- [ ] Test Flip Left-Right and Flip Up-Down.
+6
View File
@@ -53,6 +53,8 @@ This document tracks known technical debt, optimization opportunities, and minor
| 41 | **Phase 10 custom prop collision uses one convex hull** — the planned Sandbox prop renders every authored layer, but collision encloses all valid closed-shape points in one solid hull. | Low | Planned | User-approved in `specs/phase_10_prop_integration.md`: one fixture keeps dynamic rigid bodies stable and avoids overlapping per-shape contacts. Hollows and concavities collide as filled space; revisit compound collision only if playtesting shows material misses. `PropFile.flatten_to_payload()` remains for legacy single-shape consumers; #29 stays open until implementation lands. (2026-09-21) |
| 42 | **Phase 10 Browse keeps external `.prop` paths as scene asset IDs** — arbitrary filesystem files are used in place rather than copied into `res://props/`. | Medium | Planned | This matches stickman Browse and avoids filename/import conflicts, but scenes depend on the external path remaining valid. A missing custom prop becomes an inert placeholder that preserves its original scene entry and rule references through later saves; restoring the file and reloading resolves it. Existing missing-stickman rule skipping is unchanged. See `specs/phase_10_prop_integration.md`. (2026-09-21) |
| 43 | **Phase 10 thumbnail invalidation relies on path plus mtime** — custom cache keys will hash the full canonical path and include file modification time. | Low | Planned | This prevents equal basenames in different folders from sharing a PNG, while retaining cheap refresh checks. A filesystem with coarse timestamp resolution can miss two same-tick edits; content hashing is deferred unless observed. Cleanup must not remove built-in or unrelated external thumbnails. See `specs/phase_10_prop_integration.md`. (2026-09-21) |
| 44 | **Phase 10a Sandbox prop scaling depends on rigid-body collision scale behavior** — the approved corner gesture changes `PropBlock.scale`, so visual and physics bounds must agree for built-in circles/polygons and custom one-hull props. | Medium | Resolved | `PropBlock.begin_play_instance_scale()` transfers authored scale into child visuals and collision geometry during PLAY, including custom one-hull props and the nonuniform circle fallback, then `end_play_instance_scale()` restores the authored root scale in EDIT. `tests/test_phase10a_prop_scaling.gd` verifies scaled polygon and circle extents, rotated polygon contacts, dynamic PLAY contacts, and legacy nonuniform circle ellipse contacts. (2026-09-22) |
| 45 | **Phase 10a geometric normalization excludes stroke and physical mass distribution** — Normalize Size fits the union of shape points to 96 px on its longest axis, scaling about the fixed prop origin while leaving outline width unchanged. | Low | Planned | This preserves anchor offsets and current Center Prop AABB semantics; an off-origin prop remains proportionally off-origin. A future visual-stroke fit or center-of-mass sizing tool would require a separate contract. Existing #39 tracks AABB versus physical center; #37 tracks missing document-wide undo. See `specs/phase_10a_prop_scaling.md`. (2026-09-21) |
---
@@ -100,6 +102,10 @@ This document tracks known technical debt, optimization opportunities, and minor
| 2026-09-20 | Phase 9b Prop Centering specification written (`specs/phase_9b_prop_centering.md`). Approved architecture: hide canonical origin from editable anchors while retaining it in `.prop` v1.0; draw a passive constant-screen-size `(0,0)` marker in all three modes; add an always-visible Center Prop document transaction; center the authoring camera on origin for startup/New/load/reset and preserve zoom after centering; and warn explicit saves with Center & Save / Save Anyway / Cancel when displacement exceeds `max(1024 px, 2 × bounds diagonal)`. Autosave stays silent and automatic recenter-on-edit is explicitly rejected. Logged #39 (AABB authoring center is not a future physics center of mass); #37 continues to track document-wide undo. |
| 2026-09-21 | Phase 9c Prop Editor UX specification written (`specs/phase_9c_prop_editor_ux.md`). Approved architecture: a single Front Pose / Walk Left / Walk Right preview-motion selector with dynamic Pause/Resume; manual arm IK pauses gait before taking target ownership; modal typed anchor rename; Show Other Markers controls origin plus unselected anchors; one global Snap source; theme-driven `#262C39` inspector; container-driven unclipped chrome; simplified full-figure preview with no blue border. The preview directly plays the proven in-place gait/mirror policy and remains isolated from navigation, physics, actions, and Sandbox state. Logged #40 (exclusive gait/manual hand-target ownership). |
| 2026-09-21 | Phase 10 custom prop integration specification written (`specs/phase_10_prop_integration.md`) after user approval of full layered visuals with one convex collision hull, direct external-path Browse, and missing-prop placeholders that preserve scene entries and rule references. The design reuses Sandbox prop freeze/restore and save flows, extends PropLibrary with a merged scan while retaining its four-template API, and gives custom thumbnails path-unique mtime keys. Logged #41–#43; #29 remains open pending implementation. |
| 2026-09-21 | Phase 10a Prop Scaling specification written (`specs/phase_10a_prop_scaling.md`) after approval of origin-based Normalize Size and single-`PropBlock` uniform corner scaling around its local origin; an initial numeric document-scale control was removed during final UI refinement. The editor scales points, circle radius, and non-origin anchors as one transaction; a world-space 1:1 stickman guide defaults OFF and persists only in editor settings. Sandbox reuses its existing scene scale and PLAY→EDIT authored-state lifecycle. Logged #44 for physics collision verification and #45 for geometry-only fit; #37 and #39 remain open. |
| 2026-09-22 | Phase 10a whole-prop drag amendment approved (`specs/phase_10a_prop_scaling.md` §3.4). In Arrange, a visible **Resize Whole Prop** toggle displays one union-bounds outline with large handles; dragging previews all shape points, circle radii, and non-origin anchors uniformly about canonical `(0,0)` from a captured snapshot. Release calls the existing document-scale transaction once; Esc, mode switch, toggle OFF, New, Load, and Clear discard a live preview. The preview stays outside authoritative save/autosave state, and the toggle adds no `.prop` field or fourth primary mode. Existing per-shape Arrange behavior remains when the toggle is OFF. Document-wide undo stays deferred under #37; this drag should become one future undo command. |
| 2026-09-22 | Phase 10a whole-prop transform extension approved and implemented (`specs/phase_10a_prop_scaling.md` §3.4). The prior Resize Whole Prop toggle becomes one **Transform Whole Prop** tool that mirrors Arrange: drag visible geometry to move the whole document, drag the union rotation dot to rotate it about canonical `(0,0)`, and drag a corner for the existing uniform origin-based resize. Move translates every point and non-origin anchor (snapping the baseline delta when Snap is ON); rotate transforms every point/anchor position and adds the angle to editable anchor orientations; circle radius changes only on resize. All gestures preview from snapshots outside authoritative save state and commit once on release; Esc cancellation, selection restoration, mode lifecycle, `.prop` v1.0, and deferred document undo remain unchanged. |
| 2026-09-22 | Phase 10a implementation and final UI were user verified. The Arrange top bar is ordered **Transform Whole Prop**, **Normalize Size**, **Center Prop**, **Show Stickman Guide**; the numeric scale textbox and Apply Scale button are removed. Transform Whole Prop and Normalize Size are hidden in Reshape and Attach, while Center Prop and Show Stickman Guide remain available. Whole-prop move, 15-degree Ctrl rotation, uniform resize, anchor following, Snap movement, and Esc cancellation are documented in `docs/prop_editor_user_guide.md`; focused tests and the Prop Editor startup smoke test passed. |
---