First slice of Phase 4 work pulled in: an inspector that reads any
registered node's `parametrics` descriptor and renders the right-side
panel automatically. Verifies the parametric descriptor design end-to-end
on shelf and proves the loop (descriptor → UI → store update → render).
ParametricInspector component:
- Reads `nodeRegistry.get(node.type)?.parametrics`.
- Renders one `<PanelSection>` per group, one control per field.
- Field kinds supported in v1:
* `number` → SliderControl with min/max/step/unit from descriptor
* `enum` → dark-themed <select> with prettified labels
* `color` → native color picker + hex input pair
* `vec3` → 3× SliderControl (X / Y / Z)
- Honors `field.visibleIf(node)` to gate conditional fields.
- Generic Actions footer with Move / Delete, gated on
`capabilities.movable` / `capabilities.deletable !== false`.
- Title from `presentation.label`, defaults to `node.type`.
Wired as the `default:` arm of panel-manager.tsx's switch — registered
kinds without a hardcoded case (shelf, future kinds) get the auto-derived
panel. Spawn keeps its hand-written panel (the legacy switch catches
it first); we'll switch to registry-first dispatch when Phase 4 finishes
and the hand-written panels can be deleted.
What you can verify after this:
- Click a shelf → right panel shows Dimensions (width/depth/thickness/
height sliders with units + bounds from the schema) + Style (bracket
style select + color picker) + Actions (Move / Delete).
- Drag a slider → mesh updates live (store update → renderer re-renders).
- Try to set width > 3.0 — schema rejects, no update fires (the
parametric bounds are enforced by Zod, same source of truth as MCP
bound generation in Phase 4's MCP work).
Not in scope for this commit:
- `parametrics.customPanel?` escape hatch.
- `material` / `ref` field kinds.
- `invariants` validation feedback in the UI.
- Migration of legacy panels (spawn/column/etc.) to the auto-generated
path — those keep working unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>