Blacksite/.cursor/plans/material_library_and_targeted_drop_2026-07-12.plan.md

4.9 KiB

Material Library And Targeted Viewport Drop

Working implementation plan for Gitea issues #16 and #18. The shared Material/Material Instance and stable renderer-slot foundation from #51 is already present; this slice completes the production-facing catalog and drag/drop workflow.

Status

Source audit complete. Implementation starts on a clean branch after collaborative-safety #49 is published, because both slices touch the Asset Browser and should remain independently reviewable.

Current Gaps

  • Material assets are edited inside generic Asset Browser Details; no dedicated Material Library or scene-usage view exists.
  • Viewport material/texture drops act on the existing selection instead of the surface under the pointer.
  • Multi-slot renderers silently assign all slots; the hydrated draw hit already carries HydratedRendererMaterialBinding, but the drop path does not use it.
  • Primitive and brush-face targeting is not explicit, and unsupported authored actors can receive a generic MaterialDesc instead of an actionable rejection.
  • Drag UI describes an eventual action but does not preview the actual affected surface or restore a preview on cancel/target change.

Material Library

  1. Add a dockable Material Library panel, opened from Window and placed in the existing bottom dock without adding another permanent toolbar.
  2. Present project Materials and Material Instances with search, Material/Instance filter, thumbnail grid/list modes, base/dependency health, and source-control status.
  3. Add a scene-usage section that counts renderer-slot, primitive, and brush-face references and can select/locate users. Do not revive ambiguous hidden scene-local material clones.
  4. Reuse the existing guarded Material/Instance drafts for Apply, Revert, Create Instance, and texture-parameter editing. Shared-file edits remain explicit; scene assignment changes use history.
  5. Material and Instance cells are first-class drag sources and preserve the current pointer-following visual identity.

Targeted Drop Contract

Introduce a frame-updated ViewportAssetDropTarget resolved by the existing mesh-picking path:

  • A hydrated static/skinned draw maps through HydratedRendererMaterialBinding to the authored actor and exact stable slot ID.
  • A primitive maps to its authored actor-level MaterialDesc.
  • A brush performs authored face intersection and identifies the stable face ID.
  • An authored but unsupported target remains a visible invalid target with a specific reason.
  • Empty space remains placement-only for placeable assets and invalid for Material/Texture payloads.

Payload matrix:

Payload Renderer slot Primitive Brush face
Material / Material Instance Assign exact hit slot; one-slot actors may assign directly Replace actor material reference/values Replace the hit face material reference
Texture Reject with guidance to create/edit a Material Instance Set base-color texture Set hit-face base-color texture/material binding

An explicit Apply All Slots command remains available from the renderer inspector/library usage menu; a viewport hit never silently broadens from one slot to all slots.

Preview, Commit, And Cancel

  1. Start a persistent drop-preview session when a supported Material/Texture payload enters the viewport. Snapshot only the target's affected authored state.
  2. Apply a transient visual preview without pushing history or marking the scene dirty.
  3. When the pointer changes target, restore the previous snapshot before previewing the new target.
  4. On release, restore the transient state first, then commit exactly one typed history/operator transaction to the identified slot, primitive, or face.
  5. On Escape, drag cancellation, leaving the viewport, invalid target, or missing source, restore the exact snapshot and remove every preview/helper marker.
  6. The drag card and target outline name the payload, actor, slot/face, action, and invalid reason.

Verification

  • Unit-test ray-hit to authored target/slot mapping, primitive/face targeting, and invalid reasons.
  • Use OperatorInvariantHarness for preview target changes, release commit, Escape/outside cancel, dirty-state preservation, helper cleanup, and one-step undo/redo.
  • Cover static one/multi-slot, skinned multi-slot, primitive, brush face, Texture rejection on a renderer slot, missing material, and linked/locked prefab boundaries.
  • Verify Material Library filtering, scene-usage counts, dependency diagnostics, and drag sources in headless egui tests.
  • Run full source/headless checks. Packaged testing remains deferred until the project owner requests it again; live visual acceptance is still required before closing #16/#18.