- Updated BUGS.md with new issues related to selection bounding box, touchpad panning speed, and zooming behavior. - Enhanced PROJECT.md with detailed specifications for touchpad controls, recent colors in the color picker, and a status bar for project information. - Modified project.godot to update compatibility version to 4.7. - Added a status bar in stickman_editor.tscn to display cursor coordinates and snap status. - Updated body_part_panel.gd to handle recent colors and cursor detection over drawing areas. - Enhanced stickman_editor.gd to manage cursor coordinates display and recent colors tracking. - Improved whole_stickman_preview.gd to render selection gizmos on top of other parts. - Created master_rig.tscn for the stickman rig structure with bones and IK targets. - Developed master_rig_builder.gd to automate the rig building process with remote transforms and IK modifications.
8.2 KiB
8.2 KiB
AGENTS.md — stickman (Godot 4.4)
Project type
- Godot 4.4 2D/GUI project (Forward Plus renderer)
- No CLI build/test/lint commands; open in the Godot editor to run
- Main scene:
res://scenes/stickman_editor.tscn(set asrun/main_sceneinproject.godot)
Project overview
Stickman Studio is an editor tool for drawing and assembling stick figures. It is a
Control-based GUI (not physics/animation) in its current phase. Body-part vector shapes
are authored per-panel (each panel supports multiple shapes with Z-ordering) and
assembled in a "Whole Stickman" preview that supports translation, rotation, and scale.
Required addon
- Scalable Vector Shapes 2D (v2.27.7) at
addons/curved_lines_2d/- Declared dependency for the project. The current editor UI does not instantiate it directly,
but keep it present — it is required for the legacy
stick.tscnrig.
- Declared dependency for the project. The current editor UI does not instantiate it directly,
but keep it present — it is required for the legacy
Architecture
scripts/stickman_editor.gd—extends Control; the main controller. Owns the menu bar, save/load/clear flow, JSON (de)serialization, and populates the 10 body-part panels. WritesFILE_VERSION "1.2"; auto-migrates"1.0"/"1.1"files on load. Coordinates cross-panel selection so only one shape is selected at a time (shape_selected→ deselect others). Collects per-part{shapes[], position, rotation, scale}for save/load.- Phase 6 recent colors: stores
_recent_colors: Array[String](max 8, most-recent-first), loads fromsettings.json(recent_colorskey) in_load_settings(), saves on each color selection via_save_settings(), and broadcasts to all 10 panels via_broadcast_recent_colors(). _on_color_selected(color, part_name): deduplicates, inserts the hex string at the front, trims to 8 entries, saves settings, then broadcasts to all panels._broadcast_recent_colors(): pushes_recent_colorsto every panel viaBodyPartPanel.set_recent_colors(_recent_colors).- Phase 6 status bar (cursor coords):
_process()pollsget_global_mouse_position()each frame, checks each panel viais_cursor_over_drawing(global_pos)and the preview viais_cursor_over_preview(global_pos), converts to world space viaglobal_to_world(global_pos), and writes"X: ### Y: ###"to_status_cursor_coords. - Phase 6 snap status:
_status_snap_statusdisplays"SNAP: ON"/"SNAP: OFF", set in_ready()and re-synced when snap is toggled (_on_edit_menu_id_pressed).
- Phase 6 recent colors: stores
scripts/body_part_panel.gd—class_name BodyPartPanel,extends PanelContainer. Reusable per-part editor. Public API:set_shape_data(data: Variant)— import shape data (Array or single Dictionary; used on Load/Clear)get_shape_data() -> Array[Dictionary]— export array of{shape_type, points, color, closed, vertex_flags}clear_shape()— reset panel, clears all shapes (does not emitshape_changed)select()— mark the panel's topmost shape as selected (white outline highlight)deselect()— clear selection and cancel any in-progress vertex dragsignal shape_changed(shapes: Array)— emitted when any shape is created, modified, deleted, or reorderedsignal shape_selected()— emitted on left-click; the editor deselects all other panelssignal color_selected(color: Color)— emitted when the color is confirmed (OK button)set_recent_colors(colors_hex: Array)— clears existing ColorPicker presets and populates with the given hex colorsis_cursor_over_drawing(global_pos: Vector2) -> bool— true ifglobal_posis over the drawing surfaceglobal_to_world(global_pos: Vector2) -> Vector2— maps a global position to drawing ("world") space- Phase 2 vertex editing: left-click on a shape selects it; drag a vertex handle to
reshape in real time; with a shape selected, right-click near an outline edge offers
"Create Point" (inserts a vertex flagged
1at the edge midpoint). Original vertices are filled circles; user-created vertices are hollow rectangles. - Phase 4 multi-shape: panels store a
shapes[]array. Right-click context menu includes "Send Back" (id 7) and "Bring Forward" (id 8) for Z-ordering. "Delete" (id 5) removes the specific shape under the mouse._selected_shape_idxtracks which shape is active for vertex editing. - Per-panel zoom: mouse wheel multiplies
_zoomby 1.10, clamped to[0.3, 3.0]; drawing and input hit-testing both run in world space viadraw_set_transform. - Phase 6 touchpad:
_gui_inputhandlesInputEventMagnifyGesture(pinch zoom) andInputEventPanGesture(2-finger drag panning), both checked beforeInputEventMouseButton. Pan gesture delta is multiplied by 3.0 for speed parity with mouse panning. - Phase 6 cursor-centered zoom: both mouse wheel and pinch zoom adjust
_pan_offsetso the world point under the cursor stays fixed during zoom. - Selection gizmos always on top: bounding box, rotation circle, and scale
crosses for the selected part are drawn in a second pass after all parts,
via
_selected_gizmo_bounds, so they always render in front.
- Scenes:
scenes/stickman_editor.tscn— main editor layout; unique-name nodes (%Prefix) used for typed@onreadyaccess:%MenuBar,%StickmanNameEdit,%LeftColumn,%CenterColumn,%WholeStickmanPreview,%SaveDialog,%LoadDialog,%ClearConfirmDialog,%ErrorDialog,%StatusBar,%CursorCoords,%SnapStatus.- Phase 6 status bar:
StatusBaris anHBoxContainerbottom-anchored at 28 px height containingCursorCoords(left) andSnapStatus(right);MainLayoutoffset_bottomis-28.0to leave room for it.
- Phase 6 status bar:
scenes/body_part_panel.tscn— instantiated 10× at runtime (5 per column). Each panel setssize_flags_vertical = SIZE_EXPAND_FILLso the panels expand to fill the column height in their parent VBoxContainer.
Body-part data model
- 10 internal part keys (ordered):
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. - Shape dictionary:
{ "shape_type": String, "points": Array[{x,y}], "color": "#hex", "closed": bool, "vertex_flags": Array[int] }. shape_typevalues:"line","rectangle","circle",""(empty). Descriptive tag in Phase 2 — rendering usesclosed.closed:true= filled + closed outline,false= open outline-only.vertex_flags: same length aspoints;0= original vertex (filled circle),1= user-created via "Create Point" (hollow rectangle).- Phase 4: A panel stores a
shapes[]array of shape dictionaries. Z-order = array position (first = back, last = front). Per-part data includes{shapes[], position, rotation, scale}. - The JSON
.stkformat is defined inREADME.md(versioned"1.2", extensible;"1.0"/"1.1"files auto-migrate on load).
settings.json (Phase 6)
- Persisted editor preferences written to
settings.jsonvia_save_settings()and loaded in_load_settings(). - Keys:
version,grid_size,snap_to_grid,recent_colors. recent_colors: Array[String]— the last up-to-8 selected hex colors, most-recent-first. Populated on load and flushed on every color selection.
Legacy scene (do not delete)
stick.tscn— the original rigged/animated figure usingSkeleton2D+ IK targets +RemoteTransform2D+Line2Dlimbs, plus an embedded@toolscript drawing the head circle. Animations: "walk", "walk_to", "RESET". Not the current main scene; kept for future animation/rigging phases.
Editor conventions
.godot/is gitignored; never edit it manually.- Scene files (
*.tscn) and.importfiles are text-based; use Godot's editor for complex changes. - UID references (Godot 4 native) exist in scenes; do not change them by hand.
- Use standard Godot
Controlnodes where applicable. - Use
class_namefor globally referenced scripts (BodyPartPanel,WholeStickmanPreview). - Prefer
%UniqueNameaccess over exported node paths instickman_editor.gd/body_part_panel.gd. - Keep the
.stkJSON format backward compatible — never change the meaning of an existing key.