Add StkRigAdapter for runtime skeleton fitting and shape mounting

- Implemented StkRigAdapter class to adapt a master rig to a loaded .stk dictionary.
- Added methods for fitting bone lengths, recalibrating IK targets, and mounting vector shapes.
- Defined constants for default proportions and bone paths.
- Included error handling for missing nodes and invalid data structures.
This commit is contained in:
2026-08-18 17:12:54 -04:00
parent 1eeeb64b39
commit 48d98ce0fe
13 changed files with 1994 additions and 108 deletions
+62 -21
View File
@@ -10,7 +10,7 @@ The editor is organized as **11 sub-windows** in a 3-column layout:
- **Center column (5)** — Torso, Right Upper Arm, Right Lower Arm, Right Upper Leg, Right Lower Leg
- **Right column (1)** — **Whole Stickman** preview
The editor is driven by three menus: **File** (Save / Load / Clear), **Edit** (Configure Grid... / Snap to Grid), and **View** (Reset Views).
The editor is driven by three menus: **File** (Save / Load / Clear), **Edit** (Configure Grid... / Snap to Grid), and **View** (Reset Views / Hide or Show Pose Guide).
Each body-part panel is an independent vector drawing surface with per-panel zoom **and panning (middle-mouse drag)**. A configurable background grid helps align vertices, and snap-to-grid can be enabled for both vertex dragging and whole-figure assembly. **Each panel supports multiple shapes** with Z-ordering controls (Send Back / Bring Forward) and shape-level Copy/Paste and Mirror operations. The Whole Stickman panel assembles every part into one figure — treating all shapes in a panel as a single unit — and lets you reposition, rotate, and scale each part, reorder the parts (Z-order), and mirror them.
@@ -96,7 +96,29 @@ Scroll the mouse wheel inside any body-part panel or the Whole Stickman preview
- **Send Back / Bring Forward** — change the part's draw order in the preview.
- **Mirror X / Mirror Y** — flip the part around its bounding-box center.
### 5. Grid & Panning
### 5. Pose Silhouette Guide
The Whole Stickman preview can render a **pose silhouette guide**: a semi-transparent, color-coded stick figure that marks the rest-pose pivot joints of the future rig defined by `master_rig.tscn`. Its 13 joint anchors (Head, Neck, Left/Right Shoulder, Left/Right Elbow, Left/Right Wrist, Hips, Left/Right Knee, Left/Right Ankle) correspond to the exact pivot locations a future `Skeleton2D` rig will use, so you can align your body-part shapes to the same pivots.
The guide is a **view aid only**: it is drawn above the grid **and in front of user parts** (ghosting over them), moves with pan/zoom, is **not** hit-testable (it never intercepts part dragging or selection), and is **not** saved to the `.stk` file.
**Color coding** (both lines and joint dots use these color groups):
| Group | Joints | Color | Line alpha | Joint alpha |
|---|---|---|---|---|
| Left (cyan/blue) | LeftShoulder, LeftElbow, LeftWrist, LeftKnee, LeftAnkle | `(0.35, 0.70, 1.00)` | `0.45` | `0.65` |
| Right (orange/red) | RightShoulder, RightElbow, RightWrist, RightKnee, RightAnkle | `(1.00, 0.50, 0.20)` | `0.45` | `0.65` |
| Central (white) | Hips, Neck, Head | `(1.00, 1.00, 1.00)` | `0.45` | `0.65` |
- **Lines** (limbs + spine) render semi-transparent with line alpha `0.45`; the **head outline** is a white semi-transparent circle of radius 100 (1:1 `master_rig.tscn` scale) centered on the Head joint.
- **Joint dots** are constant **6 px** on screen at every zoom level (`GUIDE_JOINT_RADIUS / _zoom`).
- The guide is **ON by default**. Toggle it via **View → Hide Pose Guide** / **View → Show Pose Guide** (the menu item is a dynamic, text-only label — no checkmark — reading "Hide Pose Guide" while the guide is visible and "Show Pose Guide" while it is hidden); the setting persists to `user://settings.json` (`show_pose_guide`).
**Centered at the default view:** the guide's figure bounding box is centered at the preview-area center, computed at draw time from the live preview size (`GUIDE_FIGURE_CENTER = (0, -93.75)`; `_guide_to_preview()` maps `master_pos` to `(master_pos - GUIDE_FIGURE_CENTER) * GUIDE_SCALE + preview_area.size * 0.5`). It is centered at startup and after **Reset Views** (zoom 1 / pan 0), and re-centers automatically when the window is resized. Because it remains a **world-space fixture**, panning/zooming moves it with the grid and parts.
**1:1 master-rig scale (deliberate):** the guide matches `master_rig.tscn` proportions exactly (a figure of ≈ 336 × 940 px, roughly x ∈ [-168, 168], y ∈ [-563.5, 376]). Because the default starter parts are small, the guide intentionally **dwarfs** them. At 1:1 zoom the ~940 px figure is taller than a typical panel, so the head and feet clip equally above/below the fold when centered — accepted. `GUIDE_SCALE`/`GUIDE_FIGURE_CENTER` are the tunables if a different size or placement is wanted later.
### 6. Grid & Panning
All 10 body-part panels and the Whole Stickman preview share a global background grid (default cell size **15 px**, Phase 5; previously 5 px):
@@ -113,7 +135,7 @@ All 10 body-part panels and the Whole Stickman preview share a global background
- **View → Reset Views** restores 100% zoom and the origin offset on all panels.
4. Grid lines are drawn behind shapes and scale with pan/zoom, so they stay aligned to world coordinates.
### 6. Changing Colors
### 7. Changing Colors
Colors are easy to change on any existing shape:
@@ -124,7 +146,7 @@ Colors are easy to change on any existing shape:
The chosen color is stored in the shape's `color` field and is saved/loaded with the `.stk` file.
### 7. Deleting
### 8. Deleting
Two levels of deletion are available:
@@ -138,7 +160,7 @@ Two levels of deletion are available:
2. If 2 vertices remain, the shape becomes an open **line** (`closed = false`).
3. If 1 vertex or fewer remains, the entire shape is cleared.
### 8. Multiple Shapes & Z-Ordering
### 9. Multiple Shapes & Z-Ordering
Each body-part panel can contain **more than one shape**. New shapes are created via the standard right-click context menu and are drawn on top of existing shapes. Shapes are drawn in Z-order (last in the list = frontmost).
@@ -164,7 +186,7 @@ Only one shape within a panel can be selected at a time for vertex editing. Left
2. The shape's vertices are mirrored around the shape's bounding-box center.
3. Mirroring recomputes the `points` array in place — no extra fields are stored; the result is saved as normal vertex data.
### 9. Whole Stickman Manipulation (Selection, Rotation, Scale)
### 10. Whole Stickman Manipulation (Selection, Rotation, Scale)
The Whole Stickman preview treats all shapes in a body-part panel as **one combined object**. Each part can be independently translated, rotated, and scaled.
@@ -197,21 +219,21 @@ The Whole Stickman preview treats all shapes in a body-part panel as **one combi
- Selection respects Z-order: hit-testing runs **front-to-back**, so the frontmost part under the pointer is selected.
- Part Z-order is saved in the `.stk` file as the top-level `part_order` array.
### 10. Save
### 11. Save
1. Click **File → Save**.
2. Choose a location and name. The default extension is `.stk` (appended automatically if omitted).
3. Click **Save**. The figure is written as JSON.
### 11. Load
### 12. Load
1. Click **File → Load**.
2. Select a `.stk` file.
3. On success, all body-part panels and the Whole Stickman preview are populated. On failure, an error dialog reports the problem (missing file, parse error, or unsupported version).
> v1.0, v1.1, and v1.2 files are automatically migrated to v1.3 on load (v1.0/v1.1 single shapes wrapped in a `shapes` array, rotation defaults to 0, scale defaults to (1,1); files without `part_order` fall back to the default part order).
> v1.0, v1.1, v1.2, and v1.3 files are automatically migrated to v1.4 on load (v1.0/v1.1 single shapes wrapped in a `shapes` array, rotation defaults to 0, scale defaults to (1,1); files without `part_order` fall back to the default part order). `pivot`, `length`, and `proportions` are **write-only** metadata recomputed from live shapes on every save — never read back — so old files load unchanged and gain these keys on their next save.
### 12. Clear
### 13. Clear
1. Click **File → Clear**.
2. A confirmation dialog warns that the current stickman will be cleared.
@@ -223,7 +245,7 @@ Files are UTF-8 JSON, pretty-printed with tab indentation. The format is version
```json
{
"version": "1.3",
"version": "1.4",
"stickman_name": "Bob",
"part_order": [
"head",
@@ -237,6 +259,13 @@ Files are UTF-8 JSON, pretty-printed with tab indentation. The format is version
"right_upper_leg",
"right_lower_leg"
],
"proportions": {
"upper_arm_length": 168.0,
"lower_arm_length": 200.0,
"upper_leg_length": 200.0,
"lower_leg_length": 200.0,
"torso_length": 391.5
},
"body_parts": {
"head": {
"shapes": [
@@ -253,7 +282,9 @@ Files are UTF-8 JSON, pretty-printed with tab indentation. The format is version
],
"position": { "x": 150, "y": 40 },
"rotation": 0.0,
"scale": { "x": 1.0, "y": 1.0 }
"scale": { "x": 1.0, "y": 1.0 },
"pivot": { "x": 122.0, "y": 39.5 },
"length": 10.0
}
},
"metadata": {
@@ -267,9 +298,10 @@ Files are UTF-8 JSON, pretty-printed with tab indentation. The format is version
| Key | Type | Description |
|---|---|---|
| `version` | `string` | Format version. Currently `"1.3"`. Loading supports `"1.0"``"1.3"` (auto-migrated). |
| `version` | `string` | Format version. Currently `"1.4"`. Loading supports `"1.0"``"1.4"` (auto-migrated). |
| `stickman_name` | `string` | Optional display name for the figure. |
| `part_order` | `array[string]` | **Phase 5.** Render/Z-order of parts in the Whole Stickman preview, front-to-back semantics per array position (first = back, last = front). Absent on v1.0v1.2 files; defaults to the internal part-key order when missing. |
| `proportions` | `object` | **Phase 8.** Rig bone lengths used by the runtime `StkRigAdapter`. Object with 5 float keys: `upper_arm_length` (168.0), `lower_arm_length` (200.0), `upper_leg_length` (200.0), `lower_leg_length` (200.0), `torso_length` (391.5). Hardcoded **master-rig rest-pose constants** (from `master_rig.tscn`), not measured from the user's shapes. Write-only metadata — never read back on load. |
| `body_parts` | `object` | Map of `body_part_name → shape` objects. Keyed by the 10 internal part names below. |
| `metadata.created_at` | `string` | Timestamp written on save. |
| `metadata.modified_at` | `string` | Timestamp written on save. |
@@ -288,6 +320,8 @@ Each body part is an object with the following keys:
| `position` | `object` | `{ "x": float, "y": float }` position of the part within the Whole Stickman preview. |
| `rotation` | `float` | Rotation in degrees. `0.0` = original orientation. Defaults to `0.0` for v1.0/v1.1 files. |
| `scale` | `object` | `{ "x": float, "y": float }` scale factors relative to created size. `1.0` = original size. May be **negative** (Phase 5) to represent mirroring along an axis. Defaults to `{ "x": 1.0, "y": 1.0 }` for older files. |
| `pivot` | `object` | **Phase 8.** `{ "x": float, "y": float }` — the **local rotation origin**, i.e. the bounding-box center of all shape points in the part's local drawing space (before `position` is applied). Always written for all 10 parts; `{ "x": 0.0, "y": 0.0 }` for an empty part. Write-only metadata — never read back on load. |
| `length` | `float` | **Phase 8.** The part's bounding-box extent along its **segment axis**, in local pixels: **width** (`max_x - min_x`) for the 4 arm parts, **height** (`max_y - min_y`) for torso, legs, and head. `0.0` for an empty part. Write-only metadata — never read back on load. |
### Shape object
@@ -311,7 +345,8 @@ Phase 3 introduces a global settings file stored in Godot's **user data** direct
{
"version": "1.0",
"grid_size": 15,
"snap_to_grid": false
"snap_to_grid": false,
"show_pose_guide": true
}
```
@@ -322,10 +357,11 @@ Phase 3 introduces a global settings file stored in Godot's **user data** direct
| `version` | `string` | `"1.0"` | Settings file version (for future extensibility). |
| `grid_size` | `int` | `15` | Grid interval in pixels, applied equally to width and height. Default changed from `5` to `15` in Phase 5. Clamped to 1100 on load. |
| `snap_to_grid` | `bool` | `false` | Whether snap-to-grid is active. |
| `show_pose_guide` | `bool` | `true` | Whether the pose silhouette guide is visible in the Whole Stickman preview. |
Behavior:
- **Load** — read on editor startup; if the file is missing or fails to parse, defaults (`grid_size = 15`, `snap_to_grid = false`) are used silently (no error dialog).
- **Save** — written whenever the user changes the grid size or toggles Snap to Grid.
- **Load** — read on editor startup; if the file is missing or fails to parse, defaults (`grid_size = 15`, `snap_to_grid = false`, `show_pose_guide = true`) are used silently (no error dialog).
- **Save** — written whenever the user changes the grid size, toggles Snap to Grid, or toggles the pose guide.
- **Scope** — global; all body-part panels and the Whole Stickman preview share the same grid size and snap setting.
- **Pan offsets are NOT persisted** — they reset on load, clear, and "Reset Views".
@@ -336,9 +372,10 @@ Behavior:
| `res://project.godot` | Engine config; sets main scene to the editor and enabled features. |
| `res://scenes/stickman_editor.tscn` | **Main scene** — editor layout, File/Edit/View menu bar, dialogs (`GridConfigDialog` + SpinBox), column containers (unique-name nodes). |
| `res://scenes/body_part_panel.tscn` | Reusable single body-part editor panel (title, drawing area, context menu, `ColorPickerPopup`); expands vertically in its column. |
| `res://scripts/stickman_editor.gd` | Editor controller — File/Edit/View menu actions, save/load/clear, JSON v1.3 serialization with multi-shape/rotation/scale and `part_order`, `settings.json` load/save, editor-wide shape clipboard (Copy/Paste across panels), broadcast of grid/snap settings to panels, Reset Views, populates panels, coordinates selection across panels. |
| `res://scripts/stickman_editor.gd` | Editor controller — File/Edit/View menu actions, save/load/clear, JSON v1.4 serialization with multi-shape/rotation/scale, `part_order`, and Phase 8 `proportions`/`pivot`/`length`, `settings.json` load/save, editor-wide shape clipboard (Copy/Paste across panels), broadcast of grid/snap settings to panels, Reset Views, populates panels, coordinates selection across panels. |
| `res://scripts/stk_rig_adapter.gd` | **Phase 8.** Standalone runtime adapter (`class_name StkRigAdapter`, `static func apply(stk_data, rig)`): fits an instantiated `master_rig.tscn` to a loaded `.stk` by re-fitting the 8 limb bones (`Skeleton2D/Torso/...` `Bone2D` lengths + lower-bone origins), recalibrating the IK targets (`IK_Targets/Left|Right_Hand`, `Left|Right_Leg`), and mounting the `.stk` shapes onto the `Body/*` visual nodes (open shapes → `Line2D`, closed → `Polygon2D` fill + `Line2D` outline, width 16). **Not used by the editor** — consumed by a future runtime pipeline. |
| `res://scripts/body_part_panel.gd` | Multi-shape creation, vertex editing, shape dragging, per-panel zoom & pan, grid drawing & snap-to-grid, ColorPicker, shape/vertex delete, Z-ordering (Send Back / Bring Forward), shape Copy/Paste, shape Mirror X/Y, drawing (fill + outline for closed shapes). |
| `res://scripts/whole_stickman_preview.gd` | Assembly preview, drag-to-reposition, part selection with white bounding box, rotation gizmo (circle below box) with Ctrl 15° snap, scale gizmo (corner crosses) with Ctrl aspect lock, part Z-ordering (Send Back / Bring Forward) via `part_order`, part Mirror X/Y (scale negation), zoom & pan, grid drawing & snap-to-grid, part hit-bounds, labels. |
| `res://scripts/whole_stickman_preview.gd` | Assembly preview, drag-to-reposition, part selection with white bounding box, rotation gizmo (circle below box) with Ctrl 15° snap, scale gizmo (corner crosses) with Ctrl aspect lock, part Z-ordering (Send Back / Bring Forward) via `part_order`, part Mirror X/Y (scale negation), zoom & pan, grid drawing & snap-to-grid, pose silhouette guide (Phase 7), part hit-bounds, labels. |
| `res://addons/curved_lines_2d/` | Scalable Vector Shapes 2D addon (v2.27.7) — required dependency. |
| `res://stick.tscn` | **Legacy** rigged/animated stick figure scene (Skeleton2D + IK). Not used by the editor. |
| `res://AGENTS.md` | Guidance for AI agents working in this codebase. |
@@ -349,14 +386,14 @@ Behavior:
File Edit View
──────────── ──────────────────── ───────────
Save Configure Grid... Reset Views
Load ─────────
──────── Snap to Grid (check)
Load ───────── ─────────────
──────── Snap to Grid (check) Hide/Show Pose Guide
Clear
```
- **File** — Save, Load, Clear (Phase 1).
- **Edit** — `Configure Grid...` (dialog with a 1100 SpinBox) and the checkable `Snap to Grid` toggle (Phase 3).
- **View** — `Reset Views` (resets zoom to 100% and pan offset to origin on every panel) (Phase 3).
- **View** — `Reset Views` (resets zoom to 100% and pan offset to origin on every panel) (Phase 3) and the dynamic text-only `Hide/Show Pose Guide` toggle (Phase 7): reads **"Hide Pose Guide"** while the guide is visible and **"Show Pose Guide"** while it is hidden.
### Context menu (per body-part panel)
@@ -415,3 +452,7 @@ BodyPartPanel.shape_selected() ---(bound to part_name)---> stickman_editor
> **Phase 4:** Each body part can have multiple shapes in Z-order. The Whole Stickman preview treats all shapes in a panel as one combined object, with selection (white bounding box), rotation (circle gizmo below box), and scale (cross gizmos at corners). The `.stk` format evolved to v1.2 with a `shapes` array per part plus `rotation` and `scale` fields. Rotation snaps to 15° with Ctrl; scale locks aspect ratio with Ctrl.
> **Phase 5:** Adds drawing-surface clipping, shape dragging, an editor-wide shape clipboard (Copy/Paste across panels), shape Mirror X/Y (vertex recompute), and preview object Z-ordering (Send Back/Bring Forward) with Mirror X/Y (scale negation). The format evolved to v1.3: a new top-level `part_order` array stores preview Z-order; scale may be negative for mirrored parts; shape mirroring stores no new fields because it rewrites `points`. The default grid size changed from 5 px to 15 px, and the Snap to Grid checkmark now renders correctly when toggled. v1.0v1.2 files remain backward compatible and are migrated on load.
> **Phase 7:** Adds the pose silhouette guide to the Whole Stickman preview — a semi-transparent, color-coded stick figure (left cyan-blue, right orange-red, central white) whose 13 joint anchors match the rest-pose pivots of the future `master_rig.tscn` rig, drawn above the grid and in front of user parts (ghosting over them, below the selection gizmos and drag highlight), centered in the preview at the default view. Toggleable via the dynamic **View → Hide/Show Pose Guide** label (on by default, persisted to `settings.json`). The guide is a view aid only: **no `.stk` format change** — `FILE_VERSION` stays `"1.3"`.
> **Phase 8:** The `.stk` export evolved to **v1.4** with write-only metadata the editor never reads back. A top-level `proportions` object stores the 5 master-rig rest-pose bone lengths (`upper_arm_length` 168.0, `lower_arm_length` 200.0, `upper_leg_length` 200.0, `lower_leg_length` 200.0, `torso_length` 391.5) — hardcoded constants from `master_rig.tscn`, not measured from the user's shapes. Each `body_parts` entry gains `pivot` (local bounding-box center = rotation origin) and `length` (bbox extent along the segment axis: width for arms, height for torso/legs/head). v1.0v1.3 files load unchanged and gain these keys on their next save. A new standalone `res://scripts/stk_rig_adapter.gd` (`class_name StkRigAdapter`) fits an instantiated `master_rig.tscn` to a loaded `.stk` (bone fitting + IK recalibration + visual shape mount); it is **not** used by the editor and is reserved for a future runtime pipeline.