Files
stickman/BUGS.md
T
ryan ab5c79ab6a feat: Implement draggable torso and head IK targets in the test harness
- Added draggable handles for the torso and head to the test harness.
- Updated `IK_HANDLE_PATHS` to include new entries for "Head" and "Torso".
- Implemented distinct colors for the torso (magenta) and head (yellow) markers.
- Added a visual aid (aim line) to indicate the head's LookAt target direction.
- Ensured that dragging the torso moves only the torso marker, allowing for limb stretching towards stationary targets.
2026-08-21 12:39:31 -04:00

117 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Stickman Studio Bugs
## Stickman editor (Phase 5 Round 1)
### Snap to grid
1. The snap to grid menu item checkbox is still not populating with a check mark no matter how many times it is clicked.
### Shape copy and paste
1. The paste item in the context menu is only displaying if a shape is selected and the context menu is brought up. If I have an empty window OR if I don't have a shape selected in that window, 'paste' do not show up in the menu. It should show up as long as something is in the clipboard. Pasting into an empty window should be possible.
## Stickman editor (Phase 5 Round 2)
### Snap to grid
1. The snap to grid menu item checkbox is still not populating with a check mark. Should we come up with another solution for this?
### Object scaling after rotation
1. When I rotate an object to a different angle than the original (0) and the try to scale the object, the object returns back to 0 rotation and then begins to scale. The scale should happen while the object is rotated, and the object keeps that rotation while being scaled.
## Stickman editor (Phase 5 Round 3)
### Snap to grid
1. The snap to grid menu item checkbox is still not populating with a check mark. Let's change the implementation. _Propose an alternate solution_
### Pasting a shape
1. If an object has been scaled or rotated, and then the object's corresponding shape is deleted from a shape editor window - when a new shape is pasted, that shape takes on the scale, rotation, and position of the previous deleted shape or object had. When a shape is deleted, it's corrsponding object need to have it's position, rotation, and scale reset.
## Stickman editor (Phase 5 Round 4)
### Snap to grid when moving an object
1. Currently snapping to the grid snaps the mouse cursor to the grid, however, that can lead to object still not lining up properly. The object's bounding box should be what snaps to the grid. If a reference point is needed for snapping, use the object's upper left point of the bounding box.
## Stickman editor (Phase 6 Round 1)
### Seletion bounding box as well as rotation 'dot' should stay in front of all other objects.
If an object is selected, it's bounding box and rotation dot should be in front of all other objects.
### Touchpad panning is too slow
Panning using the touchpad does not moves too slowly. We need to increase the distance the panning moves through touchpad.
### Zooming in/out
When zooming in, we should use the mouse cursor as the zoom in point. If the cursor is in the window should determine where the zoom should happen.
## Stickman editor (Phase 7 Round 1)
### Silhouette starting position (or camera)
When starting the application, the silhouette stickman should be in the center of the view. Right now it starts on the left upper side of the view so the user has to pan over.
Either move the silhouette or the camera.
### Showing the pose guide
When clicking View->Show Pose Guide the guide toggles on and off, but the text never changes.
By default the pose is visible so the menu text should say "Hide Pose Guide"
When it is hidden it should say "Show Pose Guide"
### Guide visibility
The guide and joints should slightly 'ghost' in front of the objects so that the use can see how well the objects are aligned to the joints and limbs.
## Stickman editor (Phase 9 Round 1)
> FIXED — 2026 Round 1: implemented per docs/phase9_round1_bugfix_spec.md; anisotropic scaling, joint-based anchors, and node/driver transform neutralization; verified with a 37-assertion headless smoke test.
## Stickman editor (Phase 9 Round 2)
> FIXED — 2026 Round 2: implemented per docs/phase9_round2_bugfix_spec.md; restored the `RemoteTransform2D` driver rotations (`update_rotation = true` again) so mounted shapes follow their bones under IK flexing, switched the mount to the rig's hanging convention (joint anchor at the local origin, far end along +Y, per-family alignment rotation), auto-detected the drawn long axis so only that axis scales to the bone length (cross-axis thickness 1:1), zeroed the Head driver's local position so the chin lands on the neck joint, dropped `DEFAULT_LINE_WIDTH` to 2.0 (editor's outline width), and rewrote the harness bone overlay (true parent→child segments + leaf bones drawn to their IK targets). Verified with a 46-assertion headless smoke test.
1. **Lower-limb bones/joints invisible in "Show Bones".** The harness `_draw_bones()` drew parent-origin → bone-origin lines, so for lower bones the segment duplicated the upper segment and wrist/ankle joints (bone ends, not origins) were never drawn. Fixed: the overlay now draws a joint dot per bone, parent→child bone segments, and leaf bones out to their IK targets.
2. **IK only moves lower-arm shapes; upper-arm shapes static.** Round 1's `_neutralize_driver_rotations()` set `update_rotation = false` on the 10 `RemoteTransform2D` drivers, so `Body/*` visuals sat unrotated at fixed joints. Fixed: driver rotation neutralization removed — the drivers keep their defaults and the hanging-convention mount rotates every part to follow its bone in any pose.
3. **Torso top connects at the hip joint.** With driver rotation suppressed, the torso (top-center anchor) hung with its top at the hip-driven origin. Fixed: the torso now mounts with the hip end (bottom-center anchor, θ = π) at the origin, so the top lands at the neck.
4. **Head features wrong scale / too thick / nose not triangular.** `DEFAULT_LINE_WIDTH = 16.0` dominated small face features, and the Head driver's local position `(0.05, 72)` floated the head above the neck. Fixed: line width is 2.0 (editor's 2 px outline) and the Head driver position is zeroed so the mounted head's chin sits on the neck joint.
## Stickman editor (Phase 9 Round 3)
> FIXED — 2026 Round 3: implemented per docs/phase9_round3_bugfix_spec.md; one node per shape (closed → single Polygon2D, open → single Line2D), the part's preview rotation/scale composed into the mount before the hanging-convention fit (anchor/θ/bone-fit scale computed on the transformed geometry; ±180° flips swap the attachment to the drawn far end so flips render), and the harness head-leaf overlay drawn along the bone's own direction instead of to the LookAt aim point. Verified with a 26-assertion headless smoke test.
1. **"The head bone has another bone extending out of it."** The harness bone overlay drew the Head leaf bone as a segment to `IK_Targets/Head` — the `SkeletonModification2DLookAt` aim point 232 px above the neck — a long line sticking out of the head. Fixed: the Head leaf now draws a ~90 px segment along the bone's own direction (`Vector2(length, 0)` rotated by `bone_angle` then `global_rotation`), so the head bone runs neck→head-top. Limb leaf bones (LeftLowerArm, RightLowerArm, LeftLowerLeg, RightLowerLeg) still draw to their IK targets.
2. **Duplicate Polygon2D + Line2D pairs per closed shape.** Closed shapes mounted as a `Polygon2D` fill **plus** a `Line2D` outline, producing two nodes per shape (e.g. `@Polygon2D@165` + `@Line2D@166`). Fixed: one node per shape — closed shapes mount as a single `Polygon2D`, open shapes as a single `Line2D` (width 2).
3. **Part rotation not applied.** The adapter ignored the per-part `rotation` (degrees) the user applied in the Whole Stickman preview — a torso rotated 180° looked identical to an unrotated one. Fixed: the mount now applies the preview's exact transform `E(P) = C + R(rot)·S·(P C)` (scale-then-rotate about the bbox center) **before** the hanging-convention mount, and the anchor/alignment θ/bone-fit scale are computed on the transformed geometry; rotations near ±180° (`|wrapf(rot)| > 0.75π`) additionally swap the attachment to the drawn far end so flips are visible (e.g. the 180° torso shows its drawn neck end at the hip joint).
4. **Part scale not applied / head too small.** The adapter ignored the per-part `scale`, so a head scaled ~2× in the editor (≈160 px face) rendered ~80×80 in the harness. Fixed: part scale composes into `E` (the head mounts upright with θ = 0, s = 1 but still applies the part scale via `E`, so the face mounts at ≈160 px and the chin sits on the neck joint); the bone-fit scale `s` is measured on the transformed extent, so user-scaled parts are not double-fitted.
### Fix Shape Mount Math & Point Scaling in StkRigAdapter.gd
Problem Summary:
When applying .stk v1.4 data to master*rig.tscn, shapes are severely distorted:Giant Polygon Explosions (Legs): Uniformly scaling points using scale_factor = bone_length / part_length on both $X$ and $Y$ multiplies the shape's thickness, turning thin leg segments into screen-filling blocks.Misaligned Joint Rotations (Head/Torso): Using (min + max) / 2 sets the pivot to the geometric center of the shape instead of its joint connection (e.g., neck base or hip joint).Required Fixes in StkRigAdapter.gd (or ActorFactory.gd):Please refactor \_mount_shapes() / point calculation logic using the following rules:1. Anisotropic Scaling (Primary Axis Only)Do not apply scale_factor to both axes. Only scale points along the bone's primary directional axis; leave cross-axis thickness at a $1.0$ scale multiplier:Arms (Primary Axis: $X$):$$\text{point}*{\text{local}}.x = (P*x - \text{anchor}\_x) \times \left(\frac{\text{upper_arm_length}}{\text{part_length}}\right)$$$$\text{point}*{\text{local}}.y = P*y - \text{anchor}\_y$$Legs / Torso (Primary Axis: $Y$):$$\text{point}*{\text{local}}.x = P*x - \text{anchor}\_x$$$$\text{point}*{\text{local}}.y = (P*y - \text{anchor}\_y) \times \left(\frac{\text{upper_leg_length}}{\text{part_length}}\right)$$Head: Keep unscaled ($1.0$ factor) on both axes:$$\text{point}*{\text{local}} = P - \text{anchor}$$(Guard against division by zero if part_length <= 0 by defaulting the scale factor to 1.0.)2. Joint-Based Anchor Alignment (Not BBox Center)Replace bounding-box midpoint anchors with joint origins so shapes rotate correctly around the bone joints:Head Anchor: Bottom-center of bounding box (x = (min_x + max_x) / 2, y = max_y).Torso & Legs Anchor: Top-center of bounding box (x = (min_x + max_x) / 2, y = min_y).Arms Anchor: Joint-end connection (x = min_x for right arms, x = max_x for left arms, y = (min_y + max_y) / 2).3. Node Transform ResetEnsure target Body/\* container nodes have their local scale reset to Vector2(1, 1) and rotation = 0 so Godot's
## Stickman editor (Phase 9 Round 4)
> FIXED — 2026 Round 4: implemented per docs/phase9_round4_bugfix_spec.md; the mounted head geometry is dropped +28 px (`HEAD_CHIN_DROP`) in rig space so the chin lands 28 px below the neck, aligned with the editor silhouette guide's head circle bottom and overlapping the torso. Verified with a 15-assertion headless smoke test.
1. **Head too high in the harness.** The head bone origin (neck) is at `y = 391.5`, and the mounted head's chin (its local origin) previously landed on that neck joint, so the head floated above the torso with no overlap. The editor's silhouette guide draws the head as a radius-100 circle centered at the Head joint `(0, 463.5)`, so the circle's bottom is `363.5` — 28 px below the neck, overlapping the torso's top region. Fixed: the mounted head points now receive a `Vector2(0.0, 28.0)` rig-space translation after the part transform and the (θ = 0, s = 1) transform, so the chin lands at world ≈ `(0, 363.5)` — the guide circle's bottom — overlapping the torso by 28 px, matching the editor guide. The drop is a rig-space fixture position (applied after part scale/rotation), so a flipped/rotated head drops identically. node hierarchy does not multiply the geometry scaling a second time.Deliverable:Please update StkRigAdapter.gd to implement these corrected coordinate transform calculations and return the full updated GDScript.
## Stickman editor (Phase 9 Round 5)
> ADDED — 2026 Round 5: implemented per docs/phase9_round5_bugfix_spec.md; the harness now reproduces the editor's guide-relative part placement **1:1**. The editor exports per-part `guide_offset` (bbox center guide joint, preview space; a pure master-space delta) as **write-only** metadata on save (`FILE_VERSION` bumped to `"1.5"`; the load path ignores the key). The head maps to the guide **Neck** joint — the head bone's rig attachment origin `(0, 391.5)` — **not** the circle center, which sits 72 px above the neck. `StkRigAdapter` applies the offset as a node-frame translation `t = (guide_offset + (A C)).rotated(c_node)` only when the key is present (A = the mount anchor incl. the 180° flip rule, C = the raw bbox center, `c_node` = the part's driver `RemoteTransform2D.global_rotation` at apply time); old files without the key keep the previous offset-0 behavior and the head falls back to the Round 4 `HEAD_CHIN_DROP`. **Note:** `.stk` files must be re-saved from the editor to populate the offsets — only files carrying `guide_offset` pick up the guide-relative placement in the harness.
## Stickman editor (Phase 9 Round 6)
> FIXED — 2026 Round 6: implemented per docs/phase9_round6_bugfix_spec.md; the mount anchor is now the transformed end nearest the part's stored guide joint when `guide_offset` is present. Verified with a 32-assertion headless smoke test.
1. **Lower-left-leg mounted 180° off its bone.** The leg's drawn knee was at the `min_x` end, but the per-side family rule anchored it at the `max_x` end, so the ankle attached at the joint and the shin hung backward. Root cause: the adapter picked the joint end with fixed per-side family rules (left limbs → `max_x`, right limbs → `min_x`) plus a 180° flip heuristic, but the user's drawn-side conventions are **inconsistent across parts** — no fixed rule can know which drawn end is the knee. Fix: when a part carries `guide_offset`, the anchor is whichever transformed end (`E(J_raw)` or `E(F_pt_raw)`) is **nearest `center guide_offset`** (the part's guide joint) — the knee is now at the joint. Old files without the key keep the previous family rules.
2. **Lower-right-arm mounted 180° off its bone.** Same root cause mirrored on the right: the drawn elbow was at the `max_x` end, but the family rule anchored the arm at the `min_x` end, so the wrist attached at the joint and the forearm hung backward. Fix: the same nearest-end-to-guide-joint anchor selection puts the elbow at the joint. Old files without the key keep the previous rules.
## Stickman editor (Phase 9 Round 7)
> ADDED — 2026 Round 7: implemented per docs/phase9_round7_feature_spec.md; the test harness now exposes **six** draggable IK handles. `IK_HANDLE_PATHS` gains `"Head"` (`IK_Targets/Head`, the `SkeletonModification2DLookAt` aim point) and `"Torso"` (`IK_Targets/Torso`, whose child `RemoteTransform2D` moves the hip bone). Dragging the **Torso** handle moves **bones only** — the marker's `RemoteTransform2D` translates the hip bone and the whole skeleton + `Body/*` visuals follow rigidly, while the limb/head targets stay put (dragging the figure away from them stretches the limbs toward the stationary targets, per user decision). Dragging the **Head** handle drives the Head bone's LookAt rotation (clamped at the authored ~55° constraint); `Body/Head` follows. `_handle_color()` colors the head marker yellow (`HANDLE_COLOR_HEAD`) and the torso marker magenta (`HANDLE_COLOR_TORSO`); hands stay green, feet blue. The IK overlay additionally draws a null-guarded semi-transparent yellow aim line from the Head bone origin to the head marker (visual aid for the LookAt test). Verified with a 17-assertion headless test (Torso moved by (60, 40) → `Skeleton2D/Torso` and `Body/*` translate by exactly (60, 40); Head marker moved → Head bone + `Body/Head` rotate).