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

155 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenSpec Change: enterprise-gaming-controller
- **Change ID**: enterprise-gaming-controller
- **Package**: `@suaveplan/controller`
- **Category**: gaming/engine
- **Target path**: `gaming/engine/controller`
- **Status**: PROPOSED
- **Date**: 2026-04-24
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/controller.md`
---
## Summary
Deliver `@suaveplan/controller` on the genesis branch from scratch at enterprise quality. The package provides controller abstractions — a unified input layer that normalises keyboard, mouse, gamepad (Web Gamepad API), touch, and virtual on-screen controls into a single `ActionMap`. Actions are named bindings mapped to digital (pressed/released) and analog (axis) values. A `ControllerManager` polls inputs each tick, resolves conflicts, applies deadzone and sensitivity curves, and fires `@suaveplan/events` action events. Genesis adds Zod binding schemas, structured errors, OTel input-latency histogram, 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:^`) | `ControllerError`; `CONTROLLER.*` codes |
| `@suaveplan/types` (`workspace:^`) | `Clock` |
| `@suaveplan/events` (`workspace:^`) | Action-pressed/released events |
| `zod` (`catalog:forms`) | Binding config schemas |
| `@opentelemetry/api` (`catalog:observability`) | Input-latency histogram |
---
## Public API surface
```ts
function createControllerManager(options?: ControllerManagerOptions): ControllerManager
interface ControllerManagerOptions {
deadzone?: number // analog deadzone 0–1, default 0.1
bindings?: ActionBinding[]
clock?: Clock
}
interface ControllerManager {
registerBinding(binding: ActionBinding): void
removeBinding(action: string): void
isPressed(action: string): boolean
getAxis(action: string): number // -1 to 1
poll(dt?: number): void // called each game tick
destroy(): void
}
type InputSource = 'keyboard' | 'mouse' | 'gamepad' | 'touch' | 'virtual'
interface ActionBinding {
action: string
source: InputSource
key?: string // keyboard: e.g. 'KeyW', 'Space'
button?: number // gamepad button index
axis?: number // gamepad axis index
mouseButton?: number // 0=left, 1=middle, 2=right
touchId?: number
invert?: boolean
sensitivity?: number
}
// Keyboard/mouse adapter (for environments with DOM)
function createKeyboardAdapter(): InputAdapter
function createGamepadAdapter(): InputAdapter
function createVirtualAdapter(): InputAdapter & { setAxis(action: string, value: number): void }
interface InputAdapter {
readonly source: InputSource
isPressed(key: string | number): boolean
getAxis(index: number): number
attach(): void
detach(): void
}
```
### Error codes
```ts
type ControllerErrorCode =
| 'CONTROLLER_ACTION_NOT_FOUND'
| 'CONTROLLER_DUPLICATE_BINDING'
| 'CONTROLLER_INVALID_AXIS'
| 'CONTROLLER_ADAPTER_ERROR'
```
---
## New additions for genesis
1. **Multi-source conflict resolution** — when multiple sources bind the same action, the last non-zero value wins.
2. **Sensitivity curves** — linear, quadratic, and cubic response curves for analog axes.
3. **Virtual adapter** — headless adapter for touch/on-screen controls; state driven by caller (used by `@suaveplan/react-controller`).
4. **OTel** — `controller.poll_duration_ms` histogram; `controller.active_bindings` gauge.
---
## File layout
```text
gaming/engine/controller/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
constants/index.ts
types/common.ts
types/common.md
core/
controller-manager/
controller-manager.ts
controller-manager.md
controller-manager.types.ts
controller-manager.test.ts
index.ts
adapters/
keyboard-adapter/
keyboard-adapter.ts
keyboard-adapter.md
keyboard-adapter.test.ts
index.ts
gamepad-adapter/
gamepad-adapter.ts
gamepad-adapter.md
gamepad-adapter.test.ts
index.ts
virtual-adapter/
virtual-adapter.ts
virtual-adapter.md
virtual-adapter.test.ts
index.ts
utils/
sensitivity.ts
sensitivity.md
sensitivity.test.ts
tests/
integration.test.ts
```
---
## Impact
**Downstream**: `@suaveplan/react-controller` wraps virtual adapter in React hooks; `@suaveplan/r3f-controller` drives Three.js camera/character from action map. Prerequisites: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`.