feat: Implement Stickman Factory and Test Harness for runtime rigging

- Added StickmanFactory to load and instantiate .stk files into master_rig.tscn.
- Created a Test Harness scene for debugging bone scales, vector drawing offsets, and IK limits.
- Updated stk_rig_adapter to fit head bone and mount head shapes as full geometry.
- Enhanced README and PROJECT documentation to reflect new features and usage.
- Introduced UI elements for file selection and visual debugging in the Test Harness.
- Refactored code to improve clarity and maintainability, including removal of unused functions.
This commit is contained in:
2026-08-18 21:44:56 -04:00
parent 48d98ce0fe
commit 1252728c06
10 changed files with 618 additions and 95 deletions
+41 -8
View File
@@ -108,14 +108,42 @@ assembled in a "Whole Stickman" preview that supports translation, rotation, and
size). The guide is pure drawing — **no hit-testing** is added, so it never intercepts
part dragging/selection.
- `scripts/stk_rig_adapter.gd``class_name StkRigAdapter`, `extends RefCounted`; a **standalone
runtime adapter** (Phase 8, **not referenced by the editor**). `static func apply(stk_data, rig)`
fits an instantiated `master_rig.tscn` to a loaded `.stk` dictionary, calling three private
helpers in order: `_fit_bones` (re-fits the 8 limb `Bone2D` lengths + lower-bone origins),
`_recalibrate_ik` (repositions the `IK_Targets/Left|Right_Hand` and `Left|Right_Leg` targets),
and `_mount_shapes` (mounts `.stk` shapes onto the `Body/*` visual nodes — open → `Line2D`,
closed → `Polygon2D` fill + `Line2D` outline, width 16). Targets `master_rig.tscn` node paths;
every node lookup is null-guarded (missing node → `push_warning` + skip, never crash). Consumed
by a future runtime pipeline.
runtime adapter** (Phase 8, **not referenced by the editor**, extended by Phase 9).
`static func apply(stk_data, rig)` fits an instantiated `master_rig.tscn` to a loaded `.stk`
dictionary, calling three private helpers in order: `_fit_bones` (re-fits the 8 limb `Bone2D`
lengths + lower-bone origins), `_recalibrate_ik` (repositions the `IK_Targets/Left|Right_Hand`
and `Left|Right_Leg` targets), and `_mount_shapes` (mounts `.stk` shapes onto the `Body/*`
visual nodes — open → `Line2D`, closed → `Polygon2D` fill + `Line2D` outline, width 16).
- **Phase 9 extension:** also fits the head bone (`Skeleton2D/Torso/Head.position.y =
-proportions.torso_length`, x preserved) and mounts the head as **full geometry** like every
other part — it clears the `Body/Head` node's inline `@tool` circle script via
`set_script(null)` and mounts `.stk` head shapes as `Line2D`/`Polygon2D`. Dead helpers
`_mount_head_circle`, `_compute_shapes_bbox`, and `_first_shape_color` were removed.
Targets `master_rig.tscn` node paths; every node lookup is null-guarded (missing node →
`push_warning` + skip, never crash). Consumed by a future runtime pipeline.
- `scripts/stickman_factory.gd` — `class_name StickmanFactory`, `extends RefCounted`; a **static
factory** and the **runtime entry point** (Phase 9, **not used by the editor**) that turns a
`.stk` file into a live, rigged `master_rig.tscn` instance:
- `static func load_stk(path: String) -> Dictionary` — reads a `.stk` file (`FileAccess` +
`JSON.parse_string`); returns `{}` + `push_warning` on failure.
- `static func spawn_from_data(stk_data: Dictionary) -> Node2D` — instantiates
`res://master_rig.tscn`, calls `StkRigAdapter.apply(stk_data, rig)`, returns the rig root.
- `static func spawn(path: String) -> Node2D` — `load_stk()` then `spawn_from_data()`;
returns `null` on empty data.
- `scripts/test_harness.gd` — **standalone staging scene** (Phase 9, **not wired into the editor**;
run via **F6** on `res://scenes/test_harness.tscn`) for debugging bone scales, vector drawing
offsets, and IK limits in isolation. Top UI bar: "Open .stk…" button → `FileDialog` (`*.stk`);
quick-select buttons for `stickmen/break.stk`, `stickmen/basic.stk`, `stickmen/test.stk`; "Show
Bones" / "Show IK Handles" checkboxes; a status label showing the loaded filename. Viewport:
`SubViewportContainer` → `SubViewport` → world `Node2D` + enabled `Camera2D`; middle-mouse pan,
mouse-wheel zoom, camera recenters on each spawn. Each load frees the previous rig and spawns a
fresh one via `StickmanFactory.spawn()`. Debug overlay (a world-space `Node2D` `_draw()`): bone
lines between each `Bone2D` global origin and its parent's (color-coded left cyan / right orange /
central white + joint dots) when "Show Bones" is on; colored markers at
`IK_Targets/{Left_Hand,Right_Hand,Left_Leg,Right_Leg}` when "Show IK Handles" is on. Interactive
IK: click-drag the 4 limb `Marker2D` IK targets; the scene's `SkeletonModificationStack2D`
TwoBoneIK flexes limbs live. The harness enables the modification stack (`enabled = true`) after
each spawn.
- Scenes:
- `scenes/stickman_editor.tscn` — main editor layout; unique-name nodes (`%Prefix`) used
for typed `@onready` access: `%MenuBar`, `%StickmanNameEdit`, `%LeftColumn`,
@@ -127,6 +155,11 @@ assembled in a "Whole Stickman" preview that supports translation, rotation, and
- `scenes/body_part_panel.tscn` — instantiated 10× at runtime (5 per column). Each panel
sets `size_flags_vertical = SIZE_EXPAND_FILL` so the panels expand to fill the column
height in their parent VBoxContainer.
- `scenes/test_harness.tscn` — **standalone staging scene** (Phase 9, not wired into the
editor; run via **F6**). Backed by `scripts/test_harness.gd`. Top UI bar with file open /
quick-select, "Show Bones" / "Show IK Handles" toggles, and a loaded-filename status label;
`SubViewport` world with an enabled `Camera2D` (middle-mouse pan, wheel zoom, recenter on
spawn); interactive limb IK via `SkeletonModificationStack2D` TwoBoneIK.
### Body-part data model
- 10 internal part keys (ordered): `head`, `torso`, `left_upper_arm`, `left_lower_arm`,