# OpenSpec Change: enterprise-gaming-character-vehicle-picker - **Change ID**: enterprise-gaming-character-vehicle-picker - **Package**: `@suaveplan/character-vehicle-picker` - **Category**: gaming/rigs - **Target path**: `gaming/rigs/character-vehicle-picker` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/character-vehicle-picker.md` --- ## Summary Deliver `@suaveplan/character-vehicle-picker` on the genesis branch from scratch at enterprise quality. The package provides character/vehicle picker schemas, catalogs, and state management with BitPacker compression. A `CharacterCatalog` and `VehicleCatalog` hold typed descriptors; a `PickerState` tracks the active character/vehicle selection with undo/redo history; `BitPacker` from `@suaveplan/game-state-schemas` compresses selection state for network transmission. Genesis adds Zod schemas for all catalog entries, structured errors, OTel picker-event counter, and 100% coverage. --- ## Current-state audit (genesis) Package does not exist on genesis yet — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `PickerError`; `PICKER.*` codes | | `@suaveplan/types` (`workspace:^`) | Shared primitives | | `@suaveplan/events` (`workspace:^`) | `picker:select`, `picker:confirm` events | | `@suaveplan/game-state-schemas` (`workspace:^`) | `BitPacker` for selection compression | | `zod` (`catalog:forms`) | Catalog entry schemas | | `@opentelemetry/api` (`catalog:observability`) | Selection event counter | --- ## Public API surface ```ts // Catalog entry types interface CharacterEntry { id: string displayName: string thumbnailUrl?: string tags: string[] unlocked: boolean customization?: CharacterCustomization } interface VehicleEntry { id: string displayName: string type: 'car' | 'bike' | 'boat' | 'aircraft' | 'custom' thumbnailUrl?: string tags: string[] unlocked: boolean customization?: VehicleCustomization } // Catalogs function createCharacterCatalog(entries: CharacterEntry[]): CharacterCatalog function createVehicleCatalog(entries: VehicleEntry[]): VehicleCatalog interface CharacterCatalog { getById(id: string): CharacterEntry | undefined list(filter?: CatalogFilter): CharacterEntry[] unlock(id: string): void lock(id: string): void } interface VehicleCatalog { getById(id: string): VehicleEntry | undefined list(filter?: CatalogFilter): VehicleEntry[] unlock(id: string): void lock(id: string): void } interface CatalogFilter { tags?: string[] unlockedOnly?: boolean type?: string } // Picker state manager function createPickerState(options: PickerStateOptions): PickerState interface PickerStateOptions { characterCatalog: CharacterCatalog vehicleCatalog: VehicleCatalog maxHistory?: number } interface PickerState { selectCharacter(id: string): void selectVehicle(id: string): void confirm(): PickerSelection undo(): void redo(): void readonly current: PickerSelection readonly canUndo: boolean readonly canRedo: boolean } interface PickerSelection { characterId: string | null vehicleId: string | null confirmedAt?: number } // Compressed state function encodePickerSelection(selection: PickerSelection, schema: StateSchema): Uint8Array function decodePickerSelection(buffer: Uint8Array, schema: StateSchema): PickerSelection ``` ### Error codes ```ts type PickerErrorCode = | 'PICKER_ENTRY_NOT_FOUND' | 'PICKER_ENTRY_LOCKED' | 'PICKER_CATALOG_EMPTY' | 'PICKER_NO_SELECTION' ``` --- ## New additions for genesis 1. **Undo/redo history** — configurable history depth with pointer-based redo. 2. **Locked-entry guard** — selecting a locked entry throws `PICKER_ENTRY_LOCKED`. 3. **Compressed wire format** — `encodePickerSelection` uses `game-state-schemas` BitPacker for minimal payload. --- ## File layout ```text gaming/rigs/character-vehicle-picker/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/index.ts types/common.ts types/common.md core/ character-catalog/ character-catalog.ts character-catalog.md character-catalog.types.ts character-catalog.test.ts index.ts vehicle-catalog/ vehicle-catalog.ts vehicle-catalog.md vehicle-catalog.types.ts vehicle-catalog.test.ts index.ts picker-state/ picker-state.ts picker-state.md picker-state.types.ts picker-state.test.ts index.ts utils/ encoding.ts encoding.md encoding.test.ts tests/ integration.test.ts ``` --- ## Impact **Downstream**: `@suaveplan/r3f-character-vehicle-picker` wraps picker state in 3D preview UI. Prerequisites: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`, `@suaveplan/game-state-schemas`.