# Architectural Plan: Dynamic `.prop` Loading & Sandbox Integration This document outlines the architectural plan to transition `PropLibrary` from a static registry into a dynamic filesystem-backed library (matching `StickmanLibrary`) and integrate user-created `.prop` files into the Sandbox Stage. --- ## 1. System Architecture Overview The system bridges custom prop files produced by the Prop Editor into the sandbox physics simulation through four primary layers: 1. **Library & File Scanning (`PropLibrary`):** Scans `res://props/` for `*.prop` files, deserializes them via `PropFile`, flattens multi-shape hierarchies into collision payloads, and merges them with built-in templates. 2. **Thumbnail Pipeline (`ThumbnailCache` & `PropThumbnail`):** Computes cache keys using file modification timestamps (`mtime`), renders visual previews offscreen, and streams textures to the selector grid. 3. **UI Integration (`AssetSelector` & `SandboxStage`):** Presents custom props alongside built-in presets in a unified grid, offering folder scanning, ad-hoc file browsing, and palette live-refresh. 4. **World Spawning & Physics Lifecycle (`StageSpawner` & `PropBlock`):** Instantiates `RigidBody2D` nodes configured with custom collision geometry and material physical properties (mass, friction, bounce), tracking authored positions across sandbox mode transitions. --- ## 2. Component Specifications ### A. Library Layer (`res://scripts/prop_library.gd`) - **Dual-Source Registry:** Maintain built-in templates (Crate, Ball, Plank, Triangle) as default presets while scanning `res://props/*.prop` on demand. - **Entry Model Schema:** Standardize entry dictionaries returned to the UI: - **Identifier (`id`):** Resource path (`res://props/chair.prop`) for custom files, or string key (`crate`) for templates. - **Display Name (`name`):** Extracted from `.prop` metadata, with fallback to capitalized file basename. - **Material Preset & Label:** Physical properties index (Wood, Metal, Rubber, Cardboard) and human-readable label. - **Payload (`payload`):** Flattened shape and collision dictionary generated via `PropFile.flatten_to_payload()`. - **Provenance Flags:** Boolean flag indicating whether the entry is custom and string path reference for scene serialization. - **Error Handling:** Skip invalid or corrupted `.prop` files gracefully while outputting descriptive warnings. ### B. Thumbnail Pipeline (`ThumbnailCache` & `PropThumbnail`) - **Dynamic Keying Strategy:** - Built-in prop templates compute keys using internal version constants. - Custom `.prop` files compute keys combining file basename and filesystem modification timestamp (`FileAccess.get_modified_time`). - **Renderer Extension (`PropThumbnail`):** Extend offscreen rendering to support composite shapes and custom vector styling (fill color, outline width, polygons, circles) rather than single primitive shapes. - **Stale Cache Cleanup:** Automatically purge superseded PNG thumbnails when custom `.prop` files are edited or deleted. ### C. World Spawning Pipeline (`StageSpawner`) - **Payload Forwarding:** Pass the entry payload directly to `PropUtils.spawn_prop()`, which generates the corresponding `PropBlock` node with `CollisionPolygon2D` or `CollisionShape2D` nodes. - **Provenance Tagging:** Store `spawn_id` and source path metadata on spawned instances to support scene serialization and reloading. - **Authored Pose Capture:** Save placement positions to instance metadata (`_authored_position`, `_authored_rotation`) during **Edit** mode. ### D. UI & Sandbox Integration (`AssetSelector` & `SandboxStage`) - **Grid Population:** Trigger `PropLibrary.scan()` when opening the prop selector, populating grid cells with thumbnails and display names. - **Browse & Refresh Integration:** Connect the "Browse…" button to a file dialog for arbitrary `*.prop` selection, and the "Refresh" button to re-scan `res://props/`. - **Lazy Thumbnail Processing:** Process offscreen thumbnail generation non-blockingly during stage frame processing to keep UI interactions responsive. --- ## 3. Physics & Sandbox Lifecycle Integration Custom `.prop` instances must follow the existing 3-mode sandbox state machine: | Stage Mode | Prop Physics State | Interaction Capabilities | Reset Behavior | | ---------- | -------------------------------------------------- | ------------------------ | -------------- | | **Edit** | RigidBody frozen (`freeze = true`, kinematic mode) | | Move, rotate, scale, or delete via selection gizmos | N/A (Authored state recorded on movement) | | **Direct** | RigidBody frozen (`freeze = true`, kinematic mode) | Gizmos active for rule/trigger assignment; spawner palette hidden | N/A | | **Play** | RigidBody unfrozen (`freeze = false`) | Full physical simulation, collisions with terrain/stickmen/props | Mode exit restores initial authored position/rotation and zeroes linear/angular velocity | --- ## 4. Implementation Roadmap ``` [ Phase 1: Library & Data Layer ] └─ Extend PropLibrary (res://props/*.prop scanning + PropFile parsing) └─ Define unified Prop Entry Dictionary schema [ Phase 2: Thumbnail Pipeline ] └─ Update PropThumbnail to render multi-shape custom payloads └─ Implement modification timestamp cache invalidation in ThumbnailCache [ Phase 3: Spawning & UI Integration ] └─ Update StageSpawner to tag custom prop provenance └─ Wire AssetSelector grid refresh and file dialog browsing [ Phase 4: Stage Lifecycle & Verification ] └─ Verify Edit -> Play -> Edit position resets for custom props └─ Validate scene saving/loading persistence ``` ### Milestone Checklist for Architect Agent 1. **Directory Scanning:** `PropLibrary` reads `res://props/` and extracts payloads via `PropFile`. 2. **Visual Previews:** `PropThumbnail` renders multi-polygon custom vector props to textures. 3. **Palette Display:** `AssetSelector` displays merged built-in templates and `.prop` files. 4. **Physics Interaction:** Custom props unfreeze during **Play** mode, participating in physics simulation and collision events. 5. **State Reset:** Props return to their original authored transforms when switching from **Play** back to **Edit** mode.