# OpenSpec Change: enterprise-gaming-react-game-settings - **Change ID**: enterprise-gaming-react-game-settings - **Package**: `@suaveplan/react-game-settings` - **Category**: gaming/react - **Target path**: `gaming/react/react-game-settings` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/react-game-settings.md` --- ## Summary Deliver `@suaveplan/react-game-settings` on the genesis branch from scratch at enterprise quality. The package is a headless React layer for player-configurable game settings. A `SettingsManager` holds typed settings categories (graphics, audio, controls, gameplay) with default values, dirty tracking, and localStorage persistence; `useGameSettings()` provides `useSyncExternalStore` access; typed components expose sliders, toggles, dropdowns, and keybind rows. Genesis adds Zod settings schemas, structured errors, and Storybook stories for all components. --- ## Current-state audit (genesis) Package does not exist on genesis yet — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `SettingsError` | | `@suaveplan/controller` (`workspace:^`) | Keybind capture for controls settings | | `react` (`catalog:react`) | React 18 | | `zod` (`catalog:forms`) | Settings schema validation | --- ## Public API surface ```ts interface GameSettings { graphics: GraphicsSettings audio: AudioSettings controls: ControlsSettings gameplay: GameplaySettings } function createSettingsManager(defaults: GameSettings, options?: SettingsManagerOptions): SettingsManager interface SettingsManager { getSnapshot(): GameSettings subscribe(cb: () => void): () => void update(category: K, values: Partial): void reset(category?: keyof GameSettings): void save(): void load(): void readonly isDirty: boolean } function useGameSettings(): GameSettings & { update: SettingsManager['update']; isDirty: boolean } // Components function SettingsPanel(props: SettingsPanelProps): JSX.Element function SettingsSlider(props: SettingsSliderProps): JSX.Element function SettingsToggle(props: SettingsToggleProps): JSX.Element function SettingsDropdown(props: SettingsDropdownProps): JSX.Element function KeybindRow(props: KeybindRowProps): JSX.Element ``` --- ## File layout ```text gaming/react/react-game-settings/ package.json tsconfig.json vitest.config.ts src/ index.ts types/common.ts types/common.md state/ settings-manager.ts settings-manager.md settings-manager.test.ts hooks/ use-game-settings.ts use-game-settings.md use-game-settings.test.ts components/ settings-panel/ settings-panel.tsx + md + test + stories + index settings-slider/ settings-slider.tsx + md + test + stories + index settings-toggle/ settings-toggle.tsx + md + test + stories + index settings-dropdown/ settings-dropdown.tsx + md + test + stories + index keybind-row/ keybind-row.tsx + md + test + stories + index ``` --- ## Impact **Downstream**: game apps use settings panel in pause menu. Prerequisites: `@suaveplan/error`, `@suaveplan/controller`, react, zod.