4.9 KiB
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
// 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<PickerSelection>): Uint8Array
function decodePickerSelection(buffer: Uint8Array, schema: StateSchema<PickerSelection>): PickerSelection
Error codes
type PickerErrorCode =
| 'PICKER_ENTRY_NOT_FOUND'
| 'PICKER_ENTRY_LOCKED'
| 'PICKER_CATALOG_EMPTY'
| 'PICKER_NO_SELECTION'
New additions for genesis
- Undo/redo history — configurable history depth with pointer-based redo.
- Locked-entry guard — selecting a locked entry throws
PICKER_ENTRY_LOCKED. - Compressed wire format —
encodePickerSelectionusesgame-state-schemasBitPacker for minimal payload.
File layout
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.