ryan 1252728c06 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.
2026-08-18 21:44:56 -04:00
2026-08-08 00:00:50 -04:00
2026-08-08 00:00:50 -04:00
2026-08-08 00:00:50 -04:00
2026-08-08 00:00:50 -04:00
2026-08-17 13:42:18 -04:00
2026-08-17 13:42:18 -04:00
2026-08-08 00:00:50 -04:00
2026-08-08 00:00:50 -04:00
2026-08-17 13:42:18 -04:00
2026-08-17 13:42:18 -04:00

Stickman Studio

A Godot 4.4 editor tool for creating and assembling stick figures. Stickman Studio lets you draw individual body-part shapes, edit vertices, assemble them into a whole stickman, and save/load your figure to a JSON file (.stk) for later use or animation scripting.

Overview

The editor is organized as 11 sub-windows in a 3-column layout:

  • Left column (5) — Head, Left Upper Arm, Left Lower Arm, Left Upper Leg, Left Lower Leg
  • 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 / 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.

Drawing surfaces clip their content to the panel bounds: shapes and parts no longer render outside a panel's borders when dragged or panned. A selected shape can be dragged to reposition it within its panel.

Requirements

Item Version
Engine Godot 4.4 or newer
Addon Scalable Vector Shapes 2D (addons/curved_lines_2d/)

The legacy stick.tscn scene (a rigged walk animation using Skeleton2D + IK) remains in the project root for reference but is no longer the main scene.

Running the project

No CLI build, test, or lint commands are used. Run the project from the Godot editor:

  1. Open the project folder in Godot 4.4.
  2. Press F5, or open and run res://scenes/stickman_editor.tscn.

The main scene is configured as run/main_scene="res://scenes/stickman_editor.tscn" in project.godot.

Quick Start

1. Create a body part

  1. Locate one of the 10 body-part panels (e.g. Head).
  2. Right-click anywhere inside its drawing area to open the context menu.
  3. Choose a starter shape:
    • Line — a 120 px horizontal segment (2 vertices, open shape).
    • Rectangle — a 100 × 60 px rectangle (4 vertices, closed shape).
    • Circle — a 12-segment polygon (12 vertices, closed shape, radius 40).

The shape draws immediately and syncs to the Whole Stickman panel.

Rendering behavior:

  • Closed shapes (closed: true) fill their interior with the chosen color (draw_colored_polygon) and draw a 2 px outline.
  • Open shapes (closed: false) render as an outline-only segment with no fill.

Body-part panels expand vertically to fill their column height.

2. Edit vertices

Each panel supports vertex-level editing:

  1. Select a shapeLeft-click anywhere inside a shape to select it. The outline turns white.
  2. Create a vertex — With a shape selected, right-click on its outline and choose "Create Point". A new vertex (shown as a hollow rectangle) is added at the nearest edge midpoint.
  3. Drag verticesLeft-click on any vertex handle (filled circle = original, hollow rectangle = user-created) and drag to reshape. The shape conforms in real time. Release to apply. With Snap to Grid enabled, the dragged vertex jumps to the nearest grid intersection.
  4. Delete a vertexRight-click on a vertex handle and choose Remove Point (see Deleting below).
  5. Deselect — Left-click outside the shape or select a different panel. Only one shape is selected at a time.

Move a whole shape (Phase 5):

  1. Left-click a shape not on a vertex handle and drag to reposition the entire shape within the panel.
  2. Release to commit. All vertices translate together; the shape's Z-order is unchanged.
  3. With Snap to Grid enabled, the dragged shape jumps to the nearest grid intersection on release.

3. Zoom & Pan

Scroll the mouse wheel inside any body-part panel or the Whole Stickman preview to zoom. Pan the view with the middle-mouse button:

  • Wheel up — zoom in by 10%
  • Wheel down — zoom out by 10%
  • Middle-mouse drag — pan the view in any direction
  • Range — 30% (minimum) to 300% (maximum)
  • Vertex handles remain visible at all zoom levels.
  • Each panel has independent zoom and pan offset.
  • Panning takes priority over vertex dragging (middle-mouse press cancels any in-progress drag).
  • Content is clipped to the panel bounds (Phase 5) — shapes, grid, and gizmos cannot render outside a panel's drawing area, even when panned or dragged beyond its edge. This keeps each panel self-contained.
  • Use View → Reset Views to restore all panels to 100% zoom and the origin pan offset.

4. Assemble a stickman

  1. Create shapes for every part you want in the figure.
  2. In the Whole Stickman panel, drag any part to reposition it in the figure.
    • Parts get a generous hit area and show a yellow highlight while being dragged.
    • A short label (H, T, LUA, RUA, LUL, RLL, …) marks each part.
    • Use the mouse wheel to zoom in/out and middle-mouse to pan for precise positioning.
    • With Snap to Grid enabled, the mouse pointer snaps to the nearest grid intersection and the part follows.
  3. Optionally type a name in the Stickman Name field at the top.
  4. Right-click a selected part (Phase 5) to reorder or mirror it:
    • 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. 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):

  1. Click Edit → Configure Grid... and set the grid size.
    • SpinBox accepts 1100 px per cell.
    • The setting is applied to every panel simultaneously and persists to user://settings.json.
  2. Toggle Edit → Snap to Grid to enable snapping (Phase 5: the checkable menu item now reliably shows its ✓ checkmark when toggled):
    • On vertices — while dragging a vertex handle, it jumps to the nearest grid intersection.
    • On assembly — while dragging a part in the Whole Stickman preview, the pointer snaps and the part follows.
    • On shape drag — while dragging a whole shape (Phase 5), it snaps on release.
    • Existing vertices are not retroactively snapped; snapping only applies to new drags.
  3. Pan — hold the middle-mouse button and drag anywhere in a panel to pan the view.
    • Panning uses the same transform as zoom, and each panel keeps an independent offset.
    • 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.

7. Changing Colors

Colors are easy to change on any existing shape:

  1. Right-click on a shape (either selected or with the cursor over it) and choose Color....
  2. A ColorPicker popup appears with the shape's current color pre-loaded.
  3. Adjust the color — the shape updates live as a preview.
  4. Click OK to commit the change or Cancel to revert to the original color.

The chosen color is stored in the shape's color field and is saved/loaded with the .stk file.

8. Deleting

Two levels of deletion are available:

Delete an entire shape:

  1. Right-click on a shape (either selected or with the cursor over it) and choose Delete.
    • Delete is only offered when a shape exists and the mouse is over it.
  2. The shape is removed from the panel and the Whole Stickman preview.

Remove a single vertex:

  1. Right-click on a vertex handle and choose Remove Point.
  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.

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).

Z-ordering controls:

  • Right-click on a shape and choose Send Back to move it one step behind (earlier in draw order).
  • Right-click on a shape and choose Bring Forward to move it one step ahead (later in draw order).

Z-order is preserved in the .stk save file (shapes are stored in draw order within the shapes array).

Only one shape within a panel can be selected at a time for vertex editing. Left-click a shape to select it; right-click also selects the shape under the mouse for context menu operations.

Shape Copy & Paste (Phase 5):

  1. Right-click on a shape and choose Copy to place a deep copy of the shape on the editor-wide clipboard.
  2. Right-click (on empty space or a shape) and choose Paste to insert the clipboard shape at the click position.
    • Paste only appears while the clipboard is populated.
    • The clipboard persists after pasting and is shared across all 10 body-part panels — a shape copied in one panel can be pasted into any other.
    • The pasted shape becomes the newly selected (topmost) shape.
    • Copy → Clear → Paste semantics: the clipboard survives figure clear.

Shape Mirroring (Phase 5):

  1. Right-click on a selected shape and choose Mirror X or Mirror Y.
  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.

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.

Selection:

  • Left-click on any part in the Whole Stickman preview to select it.
  • A white bounding box appears around the selected part, along with manipulation gizmos.
  • Click empty space to deselect.

Translation:

  • Left-click and drag a selected part to reposition it. Snap-to-grid applies to the pointer position when enabled.

Rotation:

  • When a part is selected, a filled circle appears centered below the bounding box.
  • Click and drag the rotation circle to rotate the part around its center.
  • Hold Ctrl while rotating to snap to 15-degree increments (relative to the original 0° position).
  • Rotation is absolute: 0° always means the original orientation the object was created with.
  • The accumulated rotation value is saved in the .stk file.

Scale:

  • When a part is selected, cross/plus markers appear at all four corners of the bounding box.
  • Click and drag any corner cross to freely scale the part.
  • Hold Ctrl while scaling to lock the aspect ratio (scale uniformly).
  • Grid snapping snaps the corner position to the nearest grid intersection.
  • Scale is relative to the created size: (1.0, 1.0) = original size.
  • The scale value is saved in the .stk file. Scale may be negative for mirrored parts.
  • Part mirroring (Phase 5) — right-click a selected part and choose Mirror X or Mirror Y to mirror it around its bounding-box center. This is implemented by negating the part's scale factor along the chosen axis (no vertex data is changed).

Part Z-ordering (Phase 5):

  • Right-click a selected part and choose Send Back or Bring Forward to move it one step within the preview's draw order.
  • 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.

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.

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, 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.

13. Clear

  1. Click File → Clear.
  2. A confirmation dialog warns that the current stickman will be cleared.
  3. Confirm to reset all panels and the preview (zoom resets to 100%, pan offset to origin).

14. Test Harness & Stickman Factory (Phase 9)

Phase 9 adds the runtime pipeline that turns a saved .stk file into a live, rigged master_rig.tscn instance — plus a standalone staging scene for debugging it in isolation. Neither is wired into the editor.

Stickman Factory (res://scripts/stickman_factory.gd) — the runtime entry point:

Method Signature Behavior
load_stk static func load_stk(path: String) -> Dictionary Reads a .stk file via FileAccess + JSON.parse_string. Returns {} and push_warning on failure.
spawn_from_data static func spawn_from_data(stk_data: Dictionary) -> Node2D Instantiates res://master_rig.tscn, calls StkRigAdapter.apply(stk_data, rig), returns the rig root.
spawn static func spawn(path: String) -> Node2D Chains load_stk()spawn_from_data(). Returns null on empty data.

The factory is the intended runtime API: StickmanFactory.spawn("res://stickmen/basic.stk") yields a rigged Node2D ready to add to the scene tree. StkRigAdapter (Phase 8, extended by Phase 9) now also fits the head bone (Head.position.y = -proportions.torso_length) and mounts the head as full geometry like every other part (clearing its inline @tool circle script).

Test Harness (res://scenes/test_harness.tscn) — run via F6 on the scene (NOT via the main editor scene). Controls:

  • Open .stk…FileDialog filtered to *.stk; quick-select buttons for res://stickmen/break.stk, res://stickmen/basic.stk, res://stickmen/test.stk.
  • Show Bones / Show IK Handles — checkboxes toggling the debug overlay.
  • Loaded filename — status label showing the currently loaded file.
  • Pan / zoom — middle-mouse drag to pan, mouse-wheel to zoom the Camera2D; the camera recenters on each spawn.
  • IK drag — click and drag any of the 4 limb Marker2D IK targets (IK_Targets/Left_Hand, Right_Hand, Left_Leg, Right_Leg); the scene's SkeletonModificationStack2D TwoBoneIK flexes the limb live. The harness enables the modification stack after each spawn.

Debug overlay (a world-space Node2D _draw()): bone lines drawn between each Bone2D global origin and its parent's (color-coded left cyan / right orange / central white, with joint dots) when Show Bones is on; colored markers at the four IK targets when Show IK Handles is on. Each load frees the previous rig and spawns a fresh one.

File format (.stk)

Files are UTF-8 JSON, pretty-printed with tab indentation. The format is versioned and designed to remain backward/forward compatible — new fields can be added without breaking older files.

{
  "version": "1.4",
  "stickman_name": "Bob",
  "part_order": [
    "head",
    "torso",
    "left_upper_arm",
    "left_lower_arm",
    "right_upper_arm",
    "right_lower_arm",
    "left_upper_leg",
    "left_lower_leg",
    "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": [
        {
          "shape_type": "circle",
          "closed": true,
          "points": [
            { "x": 120, "y": 40 },
            { "x": 124, "y": 39 }
          ],
          "color": "#000000",
          "vertex_flags": [0, 0, 1, 0]
        }
      ],
      "position": { "x": 150, "y": 40 },
      "rotation": 0.0,
      "scale": { "x": 1.0, "y": 1.0 },
      "pivot": { "x": 122.0, "y": 39.5 },
      "length": 10.0
    }
  },
  "metadata": {
    "created_at": "2026-08-05T12:00:00",
    "modified_at": "2026-08-05T12:00:00"
  }
}

Root object

Key Type Description
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.

Part keys

head, torso, left_upper_arm, left_lower_arm, right_upper_arm, right_lower_arm, left_upper_leg, left_lower_leg, right_upper_leg, right_lower_leg

Part object

Each body part is an object with the following keys:

Key Type Description
shapes array Array of shape objects (see below). Draw order = array order (first = back, last = front). Wrapped as a single-element array when migrating v1.0/v1.1 files.
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

Each entry in the shapes array:

Key Type Description
shape_type string "line", "rectangle", "circle", or "" (empty). Descriptive tag only — rendering uses closed.
closed bool Whether the polygon is closed (filled) or open (outline-only).
points array Array of { "x": float, "y": float } vertex positions local to the drawing area.
color string Hex colour, e.g. "#000000". Changeable in-app via right-click → Color... (Phase 3).
vertex_flags array[int] Same length as points. 0 = original vertex, 1 = user-created via "Create Point". Controls handle appearance.

On load, parts missing from the file fall back to built-in default preview positions. v1.0 files have closed inferred from shape_type and vertex_flags default to all zeros. v1.0/v1.1 files have their single shape wrapped in a shapes array and default rotation/scale applied. Files without part_order (v1.0v1.2) use the default part-key order. Note that shape mirroring (Phase 5) rewrites the points array in place, so no new shape fields are required — the resulting vertices load identically across all supported versions.

Settings file (user://settings.json)

Phase 3 introduces a global settings file stored in Godot's user data directory (user://), separate from the .stk figure files. It persists the grid configuration and is versioned for future extensibility:

{
  "version": "1.0",
  "grid_size": 15,
  "snap_to_grid": false,
  "show_pose_guide": true
}

Settings keys

Key Type Default Description
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, 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".

Project structure

Path Purpose
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.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, extended by Phase 9. 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
res://scripts/stickman_factory.gd Phase 9. Runtime entry point (class_name StickmanFactory, extends RefCounted); a static factory that turns a .stk file into a live, rigged master_rig.tscn instance. load_stk(path) reads + parses the file ({} + push_warning on failure); spawn_from_data(stk_data) instantiates res://master_rig.tscn and calls StkRigAdapter.apply(stk_data, rig); spawn(path) chains them (null on empty data). Not used by the editor.
res://scripts/test_harness.gd Phase 9. Standalone staging scene (run via F6 on res://scenes/test_harness.tscn, not wired into the editor) for debugging bone scales, vector-drawing offsets, and IK limits in isolation. Top UI bar: "Open .stk…" / quick-select buttons (stickmen/break.stk, stickmen/basic.stk, stickmen/test.stk), "Show Bones" / "Show IK Handles" toggles, loaded-filename label. SubViewport world + enabled Camera2D (middle-mouse pan, wheel zoom, recenter on spawn); each load frees the previous rig and spawns a fresh one via StickmanFactory.spawn(). A world-space debug overlay draws bone lines and IK-target markers; the 4 limb Marker2D IK targets are click-draggable, flexing limbs live via SkeletonModificationStack2D TwoBoneIK (enabled after each spawn).
res://scenes/test_harness.tscn Phase 9. Standalone staging scene backing scripts/test_harness.gd (run via F6; not wired into the editor).
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, 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.

Menu bar structure

File          Edit                  View
────────────  ────────────────────  ───────────
Save          Configure Grid...     Reset Views
Load          ─────────             ─────────────
────────      Snap to Grid  (check) Hide/Show Pose Guide
Clear
  • File — Save, Load, Clear (Phase 1).
  • EditConfigure Grid... (dialog with a 1100 SpinBox) and the checkable Snap to Grid toggle (Phase 3).
  • ViewReset 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)

The right-click context menu is context-sensitive. Item IDs:

ID Label Shown when
0 Line Empty space right-click
1 Rectangle Empty space right-click
2 Circle Empty space right-click
3 Create Point Shape under mouse, near outline
4 Color... Shape under mouse
5 Delete Shape under mouse
6 Remove Point Right-click on a vertex handle
7 Send Back Shape under mouse
8 Bring Forward Shape under mouse
9 Copy Shape under mouse (Phase 5)
10 Paste Shape or empty space right-click; shown only when the clipboard is populated (Phase 5)
11 Mirror X Shape under mouse (Phase 5)
12 Mirror Y Shape under mouse (Phase 5)

Context menu (Whole Stickman preview)

Right-clicking a selected part opens the preview's context menu:

ID Label Description
0 Send Back Move the selected part one step back in part_order (Phase 5)
1 Bring Forward Move the selected part one step forward in part_order (Phase 5)
2 Mirror X Mirror the selected part around its bounding-box center (scale X negated) (Phase 5)
3 Mirror Y Mirror the selected part around its bounding-box center (scale Y negated) (Phase 5)

Signal flow

BodyPartPanel.shape_changed(data) ---(bound to part_name)---> stickman_editor
        |                                                           |
        |  _on_body_part_shape_changed                                |
        +--------------------------> WholeStickmanPreview            |
                                       .set_body_parts(all_data)       |
                                             ^                         |
        WholeStickmanPreview.part_moved(name, pos)  (drag handling) --+

BodyPartPanel.shape_selected() ---(bound to part_name)---> stickman_editor
                                                              |
                                      _on_body_part_shape_selected
                                         (deselects all other panels)
  • BodyPartPanel emits shape_changed(shapes_array) whenever a shape is created, a vertex is dragged (on release), a color is committed via the ColorPicker (on OK), a shape is deleted, a vertex is removed via "Remove Point", or Z-order changes via "Send Back"/"Bring Forward". The signal carries the full Array[Dictionary] of all shapes in the panel. Note: clear_shape() does not emit the signal; the editor's Clear flow refreshes the preview directly.
  • BodyPartPanel emits shape_selected when left-clicked; the editor deselects all other panels.
  • stickman_editor.gd collects shape data from all 10 panels and forwards it to WholeStickmanPreview.set_body_parts().
  • WholeStickmanPreview emits part_moved(part_name, new_position) during translation drags. Rotation and scale are stored internally and polled by the editor at save time via get_part_rotation() / get_part_scale(). Part Z-order is polled the same way via get_part_order() and saved to the top-level part_order field (Phase 5).
  • Shape Copy/Paste (Phase 5) is owned by the editor: _copy_shape() stores a deep duplicate in _shape_clipboard, _broadcast_clipboard_state() tells every panel whether Paste should be offered, and _paste_shape() inserts the clipboard into the target panel at the click position. The clipboard persists after pasting and is shared across all panels.

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 changeFILE_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.

Phase 9: Adds the runtime pipeline for turning a .stk file into a live, rigged master_rig.tscn instance, plus a standalone staging scene to debug it. A new res://scripts/stickman_factory.gd (class_name StickmanFactory) provides the runtime entry point: load_stk(path) reads/parses a .stk (FileAccess + JSON.parse_string, {} + push_warning on failure), spawn_from_data(stk_data) instantiates master_rig.tscn and applies StkRigAdapter.apply(stk_data, rig), and spawn(path) chains them (null on empty data). StkRigAdapter is extended to also fit the head bone (Head.position.y = -proportions.torso_length) and to mount the head as full geometry like every other part — clearing its inline @tool circle script and mounting .stk head shapes as Line2D/Polygon2D (removed the dead _mount_head_circle, _compute_shapes_bbox, and _first_shape_color helpers). A new standalone scene/resource pair, res://scenes/test_harness.tscn + res://scripts/test_harness.gd (run via F6), loads .stk files (open dialog + quick-select for stickmen/break.stk, stickmen/basic.stk, stickmen/test.stk), toggles a world-space debug overlay (bone lines + IK-target markers), pans/zooms a Camera2D, and lets you click-drag the 4 limb IK targets with live TwoBoneIK flexing (SkeletonModificationStack2D enabled on spawn). Neither the factory nor the harness is wired into the editor. No .stk format changeFILE_VERSION stays "1.4".

S
Description
Stickman for Godot
Readme
2.3 MiB
Languages
GDScript 100%