PURPOSE
Left-side library pane for the Weapon Workbench screen. Renders a searchable two-column grid of seed forge components, lets the user select one (driving the rest of the workbench UI), and exposes a ”+ New” entry point that opens the new-component modal.
OWNS
- Local React state
modalOpen(controlsNewComponentModalvisibility). - Layout of the library pane: header row (label + ”+ New” button), search input, scrollable card grid, empty-state placeholder, and the mounted
NewComponentModal. - Per-card visual treatment, including thumbnail placeholder text derived from
c.kind/c.baked.shaderand selected-state styling. - Client-side filter logic over
SEED_COMPONENTSmatching the lowercasedlibrarySearchquery against componentidandname.
READS FROM
useWorkbenchStore(./state/workbench-store):selectedComponentId,librarySearch.SEED_COMPONENTSfrom./fixturesas the source list of components.
PUSHES TO
useWorkbenchStoreactions:selectComponent(id)on card click and after a new component is created;setLibrarySearch(value)on every search input change.NewComponentModalviaopen,onClose, andonCreatedprops; ononCreated(id)it closes the modal and selects the newly created component.
DOES NOT
- Does not fetch, persist, or mutate any component data (only the seed fixture list is rendered; creation is handled inside
NewComponentModal). - Does not render component details, baked output, GLSL editor, or any preview — those live in sibling workbench panes.
- Does not manage workbench-wide layout, routing, or modal stacking beyond its own new-component modal.
- Does not debounce or paginate search; the entire fixture list is filtered on every keystroke.
- Does not handle keyboard navigation, drag-and-drop, or context menus on cards.
Signals
data-testid="new-component-btn"on the ”+ New” button.data-testid="library-card-${c.id}"on each component card button.- Empty-state message differs depending on whether
librarySearchis set (“No components match your search.”) or not (“No components yet. Click + New to create one.”).
Entry points
- Default export-equivalent named export
ForgeLibraryPane, used by the weapon-workbench screen as the left pane.
Pattern notes
- Functional component using
useStatefor local modal state and selector-style subscriptions touseWorkbenchStore(one selector per field) — minimizes re-renders to changes in those slices. - Search filter is case-insensitive via
toLowerCase()on both query and candidate fields, withString(... ?? '')guards so missingid/namedo not throw. - Components are typed loosely as
anyat the iteration boundary, accommodating heterogeneous shapes inSEED_COMPONENTS(e.g.kind === 'live_shader'vs baked components withbaked.shader). - All styling is inline; the file uses two custom font families (
Cal Sansfor the LIBRARY label,Space Groteskfor controls) and a dark palette anchored on#0d0d18background with#44ffccaccent for selection and the primary action. - Selection state is derived (
c.id === selectedComponentId) rather than stored locally, keeping the store as the single source of truth. NewComponentModalis always mounted and gated by theopenprop, rather than conditionally rendered.