Add new stage editor scripts for target capture, terrain painting, theme management, rule engine, and spatial indexing
- Implement `StageTargetCaptureSession` for managing target capture sessions with throw and set down positions. - Create `StageTerrainPainter` for terrain drag painting and overlap classification with stroke preview. - Introduce `StageThemeController` to handle theme values and resource loading for the Sandbox Stage. - Develop `StageRuleEngine` for runtime event matching and collision bookkeeping. - Add `StageSpatialIndex` for broadphase stage lookups with advisory spatial indexing.
This commit is contained in:
@@ -76,6 +76,7 @@ This document tracks known technical debt, optimization opportunities, and minor
|
||||
| 64 | **Legacy scene draw order can interleave props and characters** — the new two-choice depth control cannot exactly encode an older prop between two characters. | Low | Planned | Preserve `World` order with a persisted `legacy_draw_order` marker and z-index zero until the child explicitly picks Behind or In front. Show an Old scene order cue in the card; selecting a depth applies that choice relative to every character. See `docs/specs/phase_17a_prop_roles.md`. (2026-10-05) |
|
||||
| 65 | **Large custom prop switches need state parity with native buttons** — a drawn 64 × 34 px switch inside a full-row `Button` replaces the stock small `CheckButton` icon. | Low | Planned | The proposed `PropSettingsToggleRow` should keep native focus, keyboard activation, disabled state, and one `toggled` emission per press; its child labels must ignore pointer input. A compact depth cue lives inside each choice button, while the stage remains the live preview. See `docs/specs/prop_settings_card_refinement.md`. (2026-10-09) |
|
||||
| 66 | **Stage selection panels duplicate layout and visual rules** — the prop card owns its own shell sizing, choice styles, and `stage_prop_settings` tokens, making later inspector cards prone to drift. | Low | Planned | Promote the current prop card to a small shared Stage inspector shell, choice group, and toggle row with `stage_panels` theme tokens. Keep domain handlers in `SandboxStage`; preserve the existing prop role schema. During migration, resolve old prop tokens as fallback only temporarily and remove duplicate reads once the prop card uses the shared controls. See `docs/specs/stage_panel_ui_system.md`. (2026-10-09) |
|
||||
| 67 | **SandboxStage controller is too large for comfortable Godot IDE editing** — stage UI, terrain painting, document workflow, runtime rules, and speech coordination shared one roughly 7,600-line script. | High | In Progress | Approved slices 1–16 extracted reusable stage components and reduced `sandbox_stage.gd` to 5,009 lines (about 34%); the below-3,800-line target remains unmet by 1,209 lines. Root input/selection, authored queue/rule writes, recovery application, and save/commit ordering remain coordinated there. Root `--check-only` parse passes; behavior and in-editor responsiveness checks are pending. See `docs/specs/sandbox_stage_composition_refactor.md`. (2026-10-10) |
|
||||
|
||||
---
|
||||
|
||||
@@ -157,5 +158,7 @@ This document tracks known technical debt, optimization opportunities, and minor
|
||||
| 2026-10-05 | Phase 17a prop roles and Set Down architecture specification written for final user sign-off (`docs/specs/phase_17a_prop_roles.md`). Retain `PropBlock` as a stable `RigidBody2D` with authored-start/held/released profiles; make Set Down a world release target with terrain-grounded reach and physics settling; use explicit contact-pair policy and a grounded walking sweep. Legacy scenes migrate with dynamic prop behavior and a saved draw-order marker. Logged #62–#64. No implementation code changed. |
|
||||
| 2026-10-09 | Proposed Prop settings card refinement written for user approval (`docs/specs/prop_settings_card_refinement.md`): full-width 64 × 34 px switches, explicit selected choice styling, plain-language copy, nearby help, compact scrollable card, and small front/behind cues. Logged #65 for custom control state parity. No implementation code changed. |
|
||||
| 2026-10-09 | Proposed Stage selection panel UI system drafted for user approval (`docs/specs/stage_panel_ui_system.md`). The current prop card is the reference; a shared shell, choice group, toggle row, and theme tokens support later Stage inspectors. Logged #66 for duplicated panel presentation. No implementation code changed. |
|
||||
| 2026-10-10 | Sandbox Stage composition refactor specified for developer handoff (`docs/specs/sandbox_stage_composition_refactor.md`). Defines state ownership, explicit component APIs, compatibility facades, and an ordered migration beginning with spatial indexing and terrain painting. Logged #67; implementation followed in the entries below. |
|
||||
| 2026-10-10 | Sandbox Stage composition refactor slices 1–16 implemented (`docs/specs/sandbox_stage_composition_refactor.md`): extracted spatial indexing, terrain painting, stage chrome and views, document/scene adapters, run/director/rule/action/speech sessions, asset browsing, theme loading, and target capture. `sandbox_stage.gd` is 5,009 lines, about 34% smaller than the approximate 7,600-line baseline; the below-3,800-line target remains open. Godot 4.7.1 root `--check-only` parse passes. No behavior tests or in-editor checks were run; #67 remains In Progress. |
|
||||
|
||||
_End of Log_
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
# Sandbox Stage composition refactor
|
||||
|
||||
## Status and goal
|
||||
|
||||
Architecture specification for a behavior-preserving refactor of `scripts/editors/stage/sandbox_stage.gd`. The script is roughly 7,600 physical lines and combines scene orchestration with terrain painting, stage UI construction, document workflow, rule dispatch, and speech editing. The goal is to make the Godot script editor practical to use by moving coherent state and behavior into smaller scripts. This is an internal refactor: the stage's visible behavior, `.scene` format, and launch path stay the same.
|
||||
|
||||
**Implementation status (2026-10-10):** Approved extraction slices 1–16 are implemented. The root is 5,009 lines, down from the approximate 7,600-line baseline (about 34%); the below-3,800-line target remains unmet by 1,209 lines. A focused Godot 4.7.1 `--check-only` parse of the root passes and loads its component scripts. Behavior and in-editor responsiveness checks remain pending. Further reduction would require revisiting the coordinator boundary for world input/selection, scene recovery application, or save and commit transactions.
|
||||
|
||||
Implement this in the ordered slices below. Each slice must leave the stage usable and independently reviewable. Do not move methods merely to reduce line count: move the state they own, and remove the old implementation after the replacement is wired.
|
||||
|
||||
## Existing boundaries and constraints
|
||||
|
||||
- `SandboxStage` is the `Node2D` root of `scenes/stage/sandbox_stage.tscn`; its `Camera2D` and `World` children are stable. Keep `SandboxStage` as the scene script and public stage facade.
|
||||
- Existing helpers already own spawning, selection, gizmos, grid drawing, director visuals, placement overlay, action/trigger registries, and JSON schema conversion. Extend these boundaries rather than duplicating their logic.
|
||||
- `StageSceneIO` remains the `.scene` schema authority. Do not change `FILE_VERSION`, serialized fields, migration, or validation as part of this refactor. Route persisted paths through `ContentPaths.canonicalize` as today.
|
||||
- The shared Stage inspector controls and `stage_panels` theme tokens remain the basis for selected-object cards. The prop settings presentation may move, but its role writes, dirty marking, and contact reconciliation remain coordinated by the stage.
|
||||
- Current tests and tools call some underscored stage methods and inspect fields. Preserve compatibility through small forwarding methods or references during this refactor; remove a facade only in a separately approved API cleanup.
|
||||
- The working tree may contain unrelated edits to `sandbox_stage.gd`. Preserve them. Do not use a wholesale file replacement or revert.
|
||||
|
||||
## Composition rules
|
||||
|
||||
1. The root owns `current_mode`, run-state transitions, the `World` and camera lifecycle, input priority, authored object state, selection, and the final decision to mutate the scene. `_ready`, `_process`, `_physics_process`, `_input`, and `_unhandled_input` should become dispatchers with explicit component calls.
|
||||
2. A component owns its private state and exposes a small typed API. Give it references it actually needs in `configure(...)` or construction. It must not discover the stage with `get_parent()` or call arbitrary stage methods through a stored `SandboxStage` reference.
|
||||
3. Components report intents or results with signals or typed return values. The root handles cross-domain effects such as `_finalize_placed_node`, `_mark_scene_dirty`, navigation invalidation, queue/rule commits, and mode changes. Avoid generic `Callable` bags and duplicated writable state.
|
||||
4. Use `RefCounted` for data and calculation services without a tree lifecycle; use `Node` or `Control` only for components that need `_process`, input, children, popups, or rendering. The root creates and owns tree components in `_ready` or through a small scene child. Keep the dependency direction root -> component -> existing lower-level helpers. Avoid circular script preloads and new autoloads.
|
||||
5. One owner per fact. When the root needs a state for input priority, ask the component (for example, `is_dragging()` or `is_open()`) instead of mirroring a boolean. Keep compatibility accessors only for concrete existing callers; if a caller currently mutates an exposed value (the terrain tests seed `_drag_painted` directly), temporarily expose the component-owned value rather than keeping a second copy, and record that exception for later API cleanup.
|
||||
6. Scene input order is a contract. Speech UI and stage bubble input have first refusal, then palette dragging, camera gestures, placement/director capture, and world selection. A component's `handle_input(event) -> bool` reports consumption; the root alone calls `get_viewport().set_input_as_handled()` at the same points as today.
|
||||
|
||||
## Component boundaries
|
||||
|
||||
| Component and location | Owns | Root-facing contract | Explicitly outside its ownership |
|
||||
| --- | --- | --- | --- |
|
||||
| `StageSpatialIndex`, `scripts/stage/stage_spatial_index.gd` (`RefCounted`) | Advisory 16 px cell dictionary, AABB rasterization, rebuild/add/clear, candidate lookup | `rebuild(nodes)`, `add(node)`, `clear()`, `candidates_for_aabb(aabb)`, `candidates_at(world_pos)` | Collision authority, terrain painting, selection decisions |
|
||||
| `StageTerrainPainter`, `scripts/editors/stage/stage_terrain_painter.gd` (`Node`) | Terrain drag start/threshold, cell path, overlap classification, painted-cell suppression, multiple ghosts and guide | `configure(spawner, world, camera, ghost_holder, overlay, spatial_index)`, `begin(...)`, `update(...)`, `commit(...)`, `cancel()`, `is_dragging()`; emit `placement_requested(node)` for each created block and `stroke_finished(placed_count)` once | Authored state, dirty flag, navigation rebuild, `object_placed` stage signal, single cursor ghost |
|
||||
| `StageChrome`, `scripts/editors/stage/stage_chrome.gd` (`CanvasLayer`) | Top/status bars, mode controls, menus/dialog presentation, cursor/status visuals, theme application and layout | `configure(theme, initial_state)`, `set_mode(...)`, `set_status(...)`, `set_scene_title(...)`, `set_run_state(...)`; typed signals for user requests. Root may retain references to old controls through forwarding accessors during migration | Stage mode transitions, save/load decisions, world mutation |
|
||||
| `StagePropSettingsView`, `scripts/editors/stage/stage_prop_settings_view.gd` (`Control`) | Selected prop card construction, layout, choice/toggle presentation and dismissal UI | `show_prop(prop, roles, safe_rect)`, `hide_card()`, `set_dismissed(...)`; signals `role_choice_requested`, `role_toggle_requested`, `close_requested` | Writing `PropBlock` roles, contact reconciliation, dirty flag. Use existing `StageInspectorPanel`, `StagePanelChoiceGroup`, `StagePanelToggleRow`, and theme tokens |
|
||||
| `StageDocumentController`, `scripts/editors/stage/stage_document_controller.gd` (`RefCounted` or `Node` if timer needed) | Current path/name/created time, dirty/recent list, autosave path and recovery bookkeeping, file read/write and CLI file request coordination | `save(path, snapshot, autosave) -> bool`, `read(path) -> Dictionary`, `mark_dirty()`, `accept_loaded_document(...)`, `recent_paths()`; signals for errors/recovery prompts | Building or applying world snapshots, `StageSceneIO` schema implementation, speech save gate decisions |
|
||||
| `StageSceneAdapter`, `scripts/editors/stage/stage_scene_adapter.gd` (`RefCounted`) | Mapping live objects and authored transforms to a scene dictionary; reconstructing objects and runtime IDs from a validated scene dictionary | `collect(world, authored, rules, camera_state, document_metadata) -> Dictionary`; `apply(data, world, spawner) -> Dictionary` with loaded objects, ID map, warnings and missing paths | Opening files, recent list, UI dialogs, mode switching, dirty state. Stage performs post-load signal wiring/finalization and rule/view refresh |
|
||||
| `StageRuleEngine`, `scripts/stage/stage_rule_engine.gd` (`RefCounted` or `Node`) | Runtime event matching, area entry edges, collision pair suppression and reset/baseline bookkeeping | `handle_event(event, rules)`, `physics_tick(rules, ...)`, `reset_runtime_state()`; signal `rule_triggered(rule)` | Rule-builder UI, authored rule storage/edits, action queue mutation. Root executes matched consequences |
|
||||
| `StageSpeechSession`, `scripts/editors/stage/stage_speech_session.gd` (`Node`) | Active composer/preview/toolbar session, bubble pointer routing, temporary popups | `open(actor, initial, context)`, `handle_input(event) -> bool`, `update(delta)`, `close(...)`, `is_open()`, `is_save_blocked()`; signals for commit/cancel, target capture and save-gate resolution | Draft file persistence and recovery identity, final queue/rule write, scene save, generic camera controls, mode transition |
|
||||
| `StageSpeechDraftStore`, `scripts/editors/stage/stage_speech_draft_store.gd` (`RefCounted`) | Speech draft debounce and atomic file persistence, serialized payload conversion, canonical recovery origin and actor/queue identity validation | `configure(world, composer)`, `arm_draft_save()`, `update(delta)`, `capture_origin(...)`, `validate_origin(...)`, `read_draft_document()`, `persist_draft_now()`, `clear_draft_file()` | Preview/input routing, final queue/rule write, scene save decision, mode transition |
|
||||
|
||||
These contracts describe ownership, not a demand for one giant constructor. Small parameter objects are acceptable where they make call sites clearer, provided state still has one owner. The developer may split `StageChrome` and `StageSpeechSession` further if either remains unwieldy; keep each split aligned with a distinct state lifecycle.
|
||||
|
||||
## Ordered implementation slices
|
||||
|
||||
### 1. Spatial index and terrain painter
|
||||
|
||||
Extract `_world_to_grid_cell`, `_rasterize_aabb_to_cells`, `_rebuild_grid_cells`, `_add_node_to_grid_cells`, and all reads of `_grid_cells` into `StageSpatialIndex`. The index is advisory only. Its queries must return the same candidates and use the current edge-cell treatment. Director target validity currently reads this index, so route that read through its API before moving the painter.
|
||||
|
||||
Extract `_terrain_stride` through `_end_terrain_drag`, including `_bresenham_cells`, `_classify_cell`, and the multiple-ghost state, into `StageTerrainPainter`. Preserve the current single-click behavior, drag threshold in screen pixels, Shift axis constraint, three classification states, strict interior overlap, snap behavior, guide/ghost visuals, and duplicate-cell suppression. The stage receives each created node, finalizes it once, emits its existing `object_placed` signal once, then marks dirty/rebuilds navigation/index once per completed nonempty stroke. Cancellation must free ghosts and guide and rearm the single cursor ghost exactly as today. Keep old stage method names as small forwarding methods where callers need them.
|
||||
|
||||
### 2. Stage presentation
|
||||
|
||||
Move `_build_ui` and visual chrome update/style methods into `StageChrome` in sections, while the root connects its signals to existing handlers. Move the prop settings card into `StagePropSettingsView` using the shared Stage panel system. Keep the present control order, focus, popup anchoring, sizing, theme values, and mode-specific visibility. The root remains the only caller that changes modes or roles. Retain explicit references or forwarding accessors for tools that inspect `_file_menu`, `_selector_dim`, `_palette_buttons`, or other existing controls until those callers are migrated separately.
|
||||
|
||||
### 3. Document workflow and scene adapter
|
||||
|
||||
Separate the current `_collect_scene_data` / `_apply_scene_data` mapping from file workflow. `StageSceneAdapter` must preserve missing stickman/prop placeholders, stable file/runtime ID mapping, authored transforms, prop roles/material/depth, queues/rules, camera, warning messages, and post-load hooks. The root controls the reset/apply transaction: validate before destructive reset, suppress dirty during reconstruction, then rebuild the index/navigation and refresh visuals once. `StageDocumentController` owns file paths, recents, autosave/recovery metadata, safe writes via `StageSceneIO`, and CLI requests. Keep the existing speech-save gate before normal scene writes. Keep old `SandboxStage` save/load/collect/apply methods as facades for callers.
|
||||
|
||||
### 4. Runtime rule engine
|
||||
|
||||
Move event matching, edge tracking, and contact pair cleanup into `StageRuleEngine`. The root supplies its current authored rules to each dispatch rather than giving the engine a second mutable rule list; this also keeps existing callers that assign `_event_rules` directly working. The root controls whether PLAY dispatch is enabled. Reset all runtime pairs and area baselines on the same mode transitions as now, including pause/resume behavior. Emit a matched rule in stored order; the root keeps `_execute_rule_actions` and its existing queue semantics. Preserve rule IDs, source/target matching, waypoint tolerance, visible-AABB area detection, and one event per contact/entry until separation.
|
||||
|
||||
### 5. Speech session
|
||||
|
||||
Move speech state and handlers in two steps: first draft/recovery/origin logic, then preview/toolbar/pointer routing. `SpeechComposer` remains the authority for draft payloads; `StageSpeechSession` coordinates the stage-side session and preview without writing an authored action. Root handlers for `committed` apply one action to the existing direct/queue/rule destination. Preserve input suppression while composing, camera navigation where currently allowed, bubble overlap picker, placement, token selection, toolbar focus, draft recovery, the explicit Done/Cancel boundary, and deferred scene save. The root calls session input before ordinary stage input, preserving Escape and pointer priority.
|
||||
|
||||
### 6. Final root cleanup
|
||||
|
||||
Remove obsolete duplicate state and helpers after all callers use component APIs. Keep `SandboxStage` readable as a coordinator: lifecycle, top-level input dispatch, mode transitions, object finalization, cross-domain event handlers, and compatibility facades. Aim to reduce the root by more than half without creating another monolithic script; review any new component approaching roughly 1,000 lines for a natural second boundary. Do not change the root scene path or class name.
|
||||
|
||||
### 7. Director and authoring workflow consolidation (approved continuation)
|
||||
|
||||
The first extraction pass leaves the root at roughly 6,200 lines because DIRECT actions, target-capture presentation, queue/action editing, and authored rule-building still live together. Continue the refactor with these bounded components:
|
||||
|
||||
| Component and location | Owns | Root-facing contract | Explicitly outside its ownership |
|
||||
| --- | --- | --- | --- |
|
||||
| `StageDirectorController`, `scripts/editors/stage/stage_director_controller.gd` (`Node`) | Direct-action popups and context menus, direct-move draft/style state, director hint text and overlay presentation inputs | `configure(...)`, `build_ui(...)`, `handle_direct_click(world_pos)`, `update_presentation(...)`; signals for queue-action, speech, capture, panel, toast, and status requests | Queue mutation, rule mutation, scene dirty state, mode transitions, world hit-testing priority |
|
||||
| `StageRuleAuthoringController`, `scripts/editors/stage/stage_rule_authoring_controller.gd` (`RefCounted`) | Rule-builder draft/step state, trigger/action chooser presentation, RulePanel and RuleEditor presentation and local filters; target-result and parameter callbacks that update its draft | Typed begin/click/edit APIs that accept current rules or identifiers; emit explicit capture/editor requests; expose read-only state needed by director hints | Persistent `_event_rules` storage, rule IDs, world hit-testing, save gate, rule execution, authored rule commit/reorder/delete/clear, dirty marking |
|
||||
| `StageActionQueueController`, `scripts/editors/stage/stage_action_queue_controller.gd` (`RefCounted`) | QueuePanel and ActionEditor presentation, action-editor context, reorder/edit workflow state, action parameter UI, queue delete/clear confirmation prompts, and action target request details | Typed `open_queue`, `open_editor`, and result APIs; signals for confirmation presentation, action commit, target capture, speech composition, and panel requests | `StickmanRig` queue writes, authored-world state, target hit-testing/capture ownership, scene save and dirty decisions |
|
||||
|
||||
The components may be split further by lifecycle if one approaches 1,000 lines. The root remains the sole owner of the authored rule array and action-queue writes. Components may return proposed values or emit typed requests; they must not retain a copied mutable rules/queue collection. Pass the current rules to a method when a view needs them. Keep stage input ordering in `SandboxStage`: it decides which workflow receives a world click, translates the event position, and applies the resulting request. Preserve current test-facing underscored methods and state through forwarding facades while callers are migrated.
|
||||
|
||||
The continuation target is a root below roughly half of the original ~7,600-line script, without transferring world mutation, mode ownership, or input priority to a component. This addendum authorizes the additional component files and the focused root wiring needed to reach that boundary; it does not authorize behavior or serialization changes.
|
||||
|
||||
### 8. Run lifecycle and authored snapshot (approved continuation)
|
||||
|
||||
`StageRunSession`, `scripts/editors/stage/stage_run_session.gd` (`RefCounted`), owns the mutable run-state fields, paused rigid-body snapshots, authored transform/role snapshots, deferred restore count, prop-scale trace history, paused-edit autosave countdown, and editable rigid-body transform targets. It receives the current selectable world nodes and `StageRuleEngine` through typed method arguments; it does not retain a stage or world reference. The root keeps mode transition ordering, timestamp/run-control presentation, rule-edge baseline coordination, contact reconciliation, signals, dirty marking, navigation work, and final scene reset ordering. Existing underscored state fields and authored-state methods stay as forwarding facades for current callers. The component may apply the run lifecycle operations directly to the supplied nodes, while the root remains responsible for cross-domain effects and the final transition decision.
|
||||
|
||||
This continuation narrows the original composition rule that listed authored object state as root-owned: the authored snapshot data now has one owner in `StageRunSession`, while `SandboxStage` remains its compatibility facade and the owner of the mode/world transaction. No scene fields, run timing, input order, or simulation semantics change.
|
||||
|
||||
### 9. Asset selector and thumbnail queue (approved continuation)
|
||||
|
||||
`StageAssetBrowser`, `scripts/editors/stage/stage_asset_browser.gd` (`Node`), owns stickman/prop library scans, selector open/refresh coordination, browse entry validation and dialog presentation, selector generation state, thumbnail cache/render helpers, and the asynchronous thumbnail queue. It receives the existing UI layer, fonts, and theme through `build_ui(...)`; it has no `SandboxStage` reference. It emits typed asset-selection, load-error, cancellation, and refresh requests. The root remains responsible for choosing the placement asset through `StageSpawner`, changing placement mode, and applying the refresh fallback selection. Existing underscored selector/library/cache fields and thumbnail queue methods remain forwarding facades while callers are migrated.
|
||||
|
||||
### 10. Speech draft persistence split (approved continuation)
|
||||
|
||||
`StageSpeechDraftStore`, `scripts/editors/stage/stage_speech_draft_store.gd` (`RefCounted`), owns the durable recovery draft lifecycle that previously enlarged `StageSpeechSession`: debounce state, atomic `.tmp`/`.bak` replacement, payload conversion, recovery availability checks, recovered bubble-text preparation, scene path origin, and actor/queue identity validation. It receives only `World` and the active composer in `configure(...)`, and does not retain `SandboxStage`. `StageSpeechSession` keeps typed forwarding methods and owns live composer, preview, pointer, and toolbar state. The root computes the live scene fingerprint, applies recovered editor/session state, and keeps save-gate and final action-commit decisions in `SandboxStage`.
|
||||
|
||||
### 11. Modal construction and presentation
|
||||
|
||||
`StageModalViews`, `scripts/editors/stage/stage_modal_views.gd` (`RefCounted`), owns creation and shared sizing/theme application for the stage's modal dialogs, authoring popups, and the overlapping-object picker. `SandboxStage` supplies the existing layer/theme/font inputs, keeps its dialog/control references as compatibility facades, and handles the selected object after the view emits it. The component does not hold a `SandboxStage` reference and does not decide save/load, mode, or authored-state actions.
|
||||
|
||||
### 12. Theme value loading
|
||||
|
||||
`StageThemeController`, `scripts/editors/stage/stage_theme_controller.gd` (`RefCounted`), owns theme file parsing, font resolution, color/font-size configuration, and theme defaults. Root theme fields remain forwarding properties for current callers. `SandboxStage` remains responsible for applying the resolved values to live stage visuals and controls.
|
||||
|
||||
### 13. Target capture and document workflow details
|
||||
|
||||
`StageTargetCaptureSession`, `scripts/editors/stage/stage_target_capture_session.gd` (`RefCounted`), owns capture kind/callback state and throw/set-down preview state and resolution helpers. `SandboxStage` retains stage input priority, cursor/status presentation, and final callback dispatch; legacy capture fields and method names remain forwarding facades.
|
||||
|
||||
`StageDocumentController` also owns recent-menu population/selection bookkeeping, scene-dialog signal wiring for open/save/rename/unsaved requests, and scene-save queue validation. It emits typed workflow requests; the root performs scene apply, rename dirty marking, pending-file-action decisions, confirmation execution, recent settings persistence, and the speech save gate before normal writes. Queue validation observes the supplied world and preserves the existing save error message and order semantics.
|
||||
|
||||
### 14. Authoring callback ownership refinement
|
||||
|
||||
`StageRuleAuthoringController` handles draft-only callbacks for rule target results, action parameters, and RuleEditor targets. `SandboxStage` still performs world hit-tests, starts/stops capture, and owns all persistent rule array changes, final commits, save-gate decisions, and dirty marking. Existing underscored root callbacks remain forwarding facades.
|
||||
|
||||
`StageActionQueueController` connects QueuePanel and ActionEditor UI signals internally, builds queue delete/clear confirmation requests, and resolves action-editor presentation state and target-capture requests. The root presents confirmation through the shared dialog and performs each confirmed queue write. For target capture, the root retains event priority and capture ownership; the controller supplies typed kind/hint/callback requests and receives the final target to update the editor.
|
||||
|
||||
`StageSpeechSession` connects the composer, preview, picker, placement/reset, and toolbar signals internally and emits its existing toast requests. The root keeps stage input routing and the final speech commit/save-gate boundary. Redundant private root forwarding callbacks with no project or test callsites may be removed once direct component wiring is verified; keep the root camera bridge, speech-open/save-gate access, cursor integration, final commit/cancel handlers, and any test-facing facades.
|
||||
|
||||
### 15. Remove superseded component callback wrappers
|
||||
|
||||
After the internal signal connections are in place, remove private root callbacks that only forward speech preview/picker/toolbar/placement signals, prop-card viewport/reopen signals, or ActionEditor target callbacks into their owning components. `StageSpeechSession` owns its UI signal routing; `StagePropSettingsView` owns reopen and viewport layout; and `StageActionQueueController` owns ActionEditor target and speech request handling. `SandboxStage` retains generic capture initiation/result handling, camera input routing, live speech cursor and save-gate checks, final speech commit/cancel decisions, prop role writes, and test-facing queue/rule facades. Remove only handlers with no connection or caller after checking project and test sources.
|
||||
|
||||
### 16. Move remaining view and recovery preparation
|
||||
|
||||
`StageModalViews` now builds the overlapping-object picker and emits the selected `Node2D`; the root validates that it still belongs to `World` before changing selection. `StageAssetBrowser` owns selector scanning/open/refresh setup and browse-file entry validation, while root placement-asset choice and fallback selection remain stage decisions. `StageSpeechDraftStore` computes whether a recovered draft is valid for the supplied scene identity and prepares empty recovered bubble text from a saved queue action. The root still computes the current scene fingerprint, applies recovered editor state, and decides when a matching draft is cleared.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- Stage opens through `scenes/stage/sandbox_stage.tscn`, and CLI scene playback still loads/plays a `.scene` with the same errors for missing paths.
|
||||
- EDIT placement, terrain click/drag, selection, prop settings, DIRECT queues/rules/captures, PLAY/pause/resume/reset, and speech composition behave as before. Input and cancellation priorities are unchanged.
|
||||
- Saving and loading an existing scene yields the same schema, canonical paths, authored transforms, object order, placeholders, action queues, rules, metadata, and recovery behavior. No save migration is introduced.
|
||||
- Each extracted component has one documented owner for its mutable state. The root does not keep a second mutable copy. Component-to-root communication uses typed APIs/signals, with no parent traversal or circular dependency.
|
||||
- Existing stage-facing methods and fields used by current callers continue to work through facades during this refactor. Godot parses every changed script after each slice. The developer should perform focused manual stage checks for the slice before moving on; the final in-editor responsiveness must be judged in the Godot IDE, since splitting source files alone does not guarantee a specific performance gain.
|
||||
|
||||
## Handoff notes
|
||||
|
||||
Slices 1–16 have been delivered. The root retains world input priority, hit-testing and selection decisions, authored rule/queue writes, scene recovery application, and save/commit decisions to preserve ordering and existing stage-facing APIs. The original size target has not been reached; a further pass should first agree on whether any of those coordinator boundaries or compatibility facades may move. This specification authorizes architectural refactoring only; defer visual redesign, new features, rule semantics changes, and serialization changes.
|
||||
Reference in New Issue
Block a user