Add headless regression tests for Prop Editor functionality
- Implement tests for PropFile, including preset conversion, file dictionary conversion, round-trip serialization, version rejection, default values for missing keys, flattening, sanitization, and save/load functionality. - Create tests for PropEditor, covering window title formatting, mode button text, safe saving, and recent file list management. - Add tests for PropTheme, validating fallback behavior, invalid input handling, and default values for primitives and UI tokens. - Introduce tests for ThumbnailCache, ensuring proper key formatting, PNG handling, and behavior with missing files.
This commit is contained in:
@@ -38,6 +38,13 @@ This document tracks known technical debt, optimization opportunities, and minor
|
||||
| 26 | **Impact speed is a coarse magnitude** — collision reactions currently scale from `prop.linear_velocity.length()`, not normal-relative velocity or an impulse computed from contact mass. | Low | Open | This keeps the signal contract simple and deterministic. Use the normal component and/or contact impulse if reaction strength needs to reflect glancing impacts accurately. (2026-09-12) |
|
||||
| 27 | **Post-IK reaction timing is engine-order-sensitive** — bounded flinch offsets are applied at the end of `StickmanRig._physics_process()`, after the IK/head-pin work. | Low | Open | The current slot is verified and prevents cumulative rotation, but future changes to Skeleton2D modification ordering could overwrite or delay the visible reaction. Revisit only with a targeted engine-order regression. (2026-09-12) |
|
||||
| 28 | **Airborne collision sweep cost scales per proxy** — Phase 6a tests the horizontal movement against each of the rig's ten synchronized collision proxies every airborne physics frame. | Low | Open | The per-proxy `PhysicsShapeQueryParameters2D.cast_motion()` checks reuse the existing proxy shapes and avoid a second body-size approximation; this is acceptable for the current sandbox scale. With many simultaneously falling rigs, the cost grows with `rigs × 10` casts per physics frame. Consider a combined query shape or broadphase candidate filter if airborne crowds become a target. (2026-09-17) |
|
||||
| 29 | **Prop Editor multi-shape → single-shape `PropBlock` flattening** — Phase 9 (`.prop` v1.0) stores a full multi-shape `shapes[]` stack, but `PropFile.flatten_to_payload()` collapses it into the one payload `PropUtils.spawn_prop()` consumes (frontmost closed polygon → circle → first shape). Also: a circle whose vertices were hand-edited still flattens by an average-distance radius, and a non-NONE preset thumbnail ignores payload colors because `PropThumbnail` re-tints from the preset. | Low | Open | Deliberate contract until a multi-shape `PropBlock` composition (multiple `Polygon2D`/`Line2D` children + merged collision) exists; recorded per `specs/phase_9_prop_editor.md` §6. Custom `.prop` thumbnails are mtime-keyed (`ThumbnailCache.prop_file_key`/`prop_file_png`, `<basename>_<mtime>.png`), so re-edits invalidate the cached PNG; built-in template PNGs stay `id_v<PROP_VERSION>`-keyed. (2026-09-18) |
|
||||
| 30 | **Prop Editor Round 2 interaction model** — vertex editing and shape transform are separated into two explicit canvas modes (`EditMode { TRANSFORM, POINTS }`, kid-facing "Move & Resize" / "Edit Points") driven by an always-visible toolbar toggle; "Create Point" inserts at the cursor's segment projection and flashes the new vertex (0.6 s) instead of inserting an invisible collinear midpoint. | Low | Open | Deliberate, user-approved design (`specs/phase_9_prop_editor_round2.md` §5): modes gate *input* only — all public math APIs stay mode-agnostic. "Create Point" stays outline-only per user decision; auto-begin-drag was rejected as modal/surprising. Revisit only if kids find the two modes confusing in practice. (2026-09-18) |
|
||||
| 31 | **Prop Editor Round 3 chrome/autosave decisions** — exit-save skips the thumbnail render (fast, deterministic quit; the PNG is a cache nicety), autosave is debounced 1.0 s to `user://prop_editor_autosave.prop` via `PropFile.save_safe` (atomic tmp/bak swap), and all human-facing strings (mode labels/emoji, menu copy) live in the `prop_editor.gd` controller while the canvas stays string-free. | Low | Open | User-approved (`specs/phase_9_prop_editor_round3.md` §6). `save_safe` leaves a `.bak` window during the rename — acceptable on desktop, revisit if autosaves ever run on a filesystem without atomic rename. (2026-09-18) |
|
||||
| 32 | **Prop Editor mode buttons drop keyboard focus** — `_make_mode_button` sets `focus_mode = FOCUS_NONE` because the Button `focus` stylebox draws after `pressed` and (with the themed `focus` = normal panel) masked the selected/accent state until the cursor moved away. | Low | Open | Round 4 fix (`specs/phase_9_prop_editor_round4.md`). Trade-off: the Arrange/Reshape toggle is mouse-only. Revisit if keyboard accessibility for the mode toggle becomes a requirement — a focus stylebox matching the pressed state (or a focus-visible-only border) would restore it. (2026-09-19) |
|
||||
| 33 | **Prop File save-serialization zeroed every point (fixed, Round 5)** — `PropFile._serialize_shape` assigned an export-format `Array` of `{x,y}` dicts directly to a typed `PackedVector2Array`; Godot's implicit conversion cannot build `Vector2` from a dictionary and silently yielded `Vector2.ZERO` per element, so every `.prop` saved by Round 1-4 wrote all points as `(0,0)` (loading as invisible/degenerate geometry). | High | ✅ Resolved | Round 5: `_serialize_shape` now routes points through `_coerce_points`; regression assertions check point *values* through `to_file_dict` and the full round-trip, plus an end-to-end canvas→save→load test. The previously saved `props/eye.prop` and `props/box.prop` are unrecoverable (coordinates were zeroed at save time) and were re-authored. Lesson: any typed `Packed*Array` assignment from dictionary/JSON data needs a Variant-coercion helper. (2026-09-19) |
|
||||
| 34 | **Prop Editor per-shape `reshaped` flag** — every shape carries `reshaped` (false by default; set by vertex insert/remove/drag and non-uniform circle scaling, cleared by `set_shape_radius`), which gates primitive-specific inspector fields (today: the circle Radius row, replaced by a muted "reshaped" note). | Low | Open | Round 6 (`specs/phase_9_prop_editor_round6.md`). Only the circle consumes the flag today; future primitive params (box W/H, plank length/thickness) should reuse it instead of adding per-type detection. An "un-reshape" affordance (restoring a clean primitive from its params) is a possible future feature. (2026-09-19) |
|
||||
| 35 | **Prop Editor selection uses a two-tone halo** — after Round 6's fill-based contrast failed for the reported "shape in front of a white shape" case (the selection extends beyond the shape onto the background), every selection element (outline polyline, bbox, rotation dot, scale crosses, vertex handles) is drawn as a dark backing pass + bright core pass. | Low | Open | Round 7 (`specs/phase_9_prop_editor_round7.md`). The pair is visible on any background but doubles the selection draw calls; negligible at sandbox scale. If a custom selection color is ever wanted (e.g. per-user theme), it should replace the core pass while keeping the halo. (2026-09-19) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user