Files
suaveplan/openspec/changes/enterprise-gaming-character-vehicle-picker/proposal.md
2026-05-27 23:29:53 +01:00

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

  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

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.