Initial Commit
This commit is contained in:
153
openspec/changes/enterprise-gaming-hitbox/proposal.md
Normal file
153
openspec/changes/enterprise-gaming-hitbox/proposal.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# OpenSpec Change: enterprise-gaming-hitbox
|
||||
|
||||
- **Change ID**: enterprise-gaming-hitbox
|
||||
- **Package**: `@suaveplan/hitbox`
|
||||
- **Category**: gaming/combat
|
||||
- **Target path**: `gaming/combat/hitbox`
|
||||
- **Status**: PROPOSED
|
||||
- **Date**: 2026-04-24
|
||||
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/hitbox.md`
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Deliver `@suaveplan/hitbox` on the genesis branch from scratch at enterprise quality. The package provides hierarchical hit detection with per-bone AABB/sphere hitboxes, raycasting, and swept-shape tests. A `HitboxRig` attaches typed hitbox volumes to named bone slots; `HitboxQuery` tests ray-vs-AABB and ray-vs-sphere intersections using separating-axis test and returns hit results sorted by distance with zone metadata (head/torso/limb). Genesis adds Zod hitbox descriptor schemas, structured errors, OTel intersection-test counter, and 100% coverage with property tests for ray-sphere/AABB correctness.
|
||||
|
||||
---
|
||||
|
||||
## Current-state audit (genesis)
|
||||
|
||||
Package does not exist on genesis yet — fresh build.
|
||||
|
||||
---
|
||||
|
||||
## Available workspace deps on genesis
|
||||
|
||||
| Package | Role |
|
||||
|---|---|
|
||||
| `@suaveplan/error` (`workspace:^`) | `HitboxError`; `HITBOX.*` codes |
|
||||
| `@suaveplan/types` (`workspace:^`) | Shared primitives |
|
||||
| `@suaveplan/spatial-hash` (`workspace:^`) | Broad-phase culling before per-hitbox tests |
|
||||
| `zod` (`catalog:forms`) | Hitbox descriptor schemas |
|
||||
| `@opentelemetry/api` (`catalog:observability`) | Intersection test counter |
|
||||
|
||||
---
|
||||
|
||||
## Public API surface
|
||||
|
||||
```ts
|
||||
type HitboxShape = 'aabb' | 'sphere' | 'capsule'
|
||||
type HitboxZone = 'head' | 'neck' | 'torso' | 'upper_arm' | 'forearm' | 'hand' | 'thigh' | 'shin' | 'foot'
|
||||
|
||||
interface HitboxDescriptor {
|
||||
boneName: string
|
||||
shape: HitboxShape
|
||||
zone: HitboxZone
|
||||
damageMultiplier?: number // 1.0 = normal, 2.0 = headshot
|
||||
// AABB
|
||||
halfExtents?: Vec3
|
||||
// Sphere
|
||||
radius?: number
|
||||
// Capsule
|
||||
halfHeight?: number
|
||||
capsuleRadius?: number
|
||||
offset?: Vec3
|
||||
}
|
||||
|
||||
function createHitboxRig(descriptors: HitboxDescriptor[]): HitboxRig
|
||||
|
||||
interface HitboxRig {
|
||||
updateBone(boneName: string, worldPosition: Vec3, worldRotation: Quat): void
|
||||
getHitboxes(): HitboxVolume[]
|
||||
}
|
||||
|
||||
interface HitboxVolume {
|
||||
readonly descriptor: HitboxDescriptor
|
||||
readonly worldPosition: Vec3
|
||||
readonly worldRotation: Quat
|
||||
}
|
||||
|
||||
// Ray query
|
||||
interface Ray {
|
||||
origin: Vec3
|
||||
direction: Vec3
|
||||
maxDistance?: number
|
||||
}
|
||||
|
||||
function queryRay(ray: Ray, rigs: HitboxRig[]): HitResult[]
|
||||
|
||||
interface HitResult {
|
||||
entityId?: string
|
||||
distance: number
|
||||
hitPoint: Vec3
|
||||
zone: HitboxZone
|
||||
damageMultiplier: number
|
||||
normal: Vec3
|
||||
}
|
||||
|
||||
// Sweep query
|
||||
function querySphere(center: Vec3, radius: number, rigs: HitboxRig[]): HitResult[]
|
||||
function queryAABB(min: Vec3, max: Vec3, rigs: HitboxRig[]): HitResult[]
|
||||
```
|
||||
|
||||
### Error codes
|
||||
|
||||
```ts
|
||||
type HitboxErrorCode =
|
||||
| 'HITBOX_BONE_NOT_FOUND'
|
||||
| 'HITBOX_INVALID_SHAPE'
|
||||
| 'HITBOX_RIG_EMPTY'
|
||||
| 'HITBOX_QUERY_FAILED'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## New additions for genesis
|
||||
|
||||
1. **Separating-axis AABB test** — correct oriented AABB test using world rotation.
|
||||
2. **Damage multiplier per zone** — `head` defaults to 2.0; others configurable.
|
||||
3. **Spatial hash broad-phase** — `@suaveplan/spatial-hash` culls rigs before per-hitbox tests.
|
||||
4. **OTel** — `hitbox.ray_tests_total` counter; `hitbox.query_duration_ms` histogram.
|
||||
|
||||
---
|
||||
|
||||
## File layout
|
||||
|
||||
```text
|
||||
gaming/combat/hitbox/
|
||||
package.json
|
||||
tsconfig.json
|
||||
vitest.config.ts
|
||||
src/
|
||||
index.ts
|
||||
error-codes.ts
|
||||
constants/index.ts
|
||||
types/common.ts
|
||||
types/common.md
|
||||
core/
|
||||
hitbox-rig/
|
||||
hitbox-rig.ts
|
||||
hitbox-rig.md
|
||||
hitbox-rig.types.ts
|
||||
hitbox-rig.test.ts
|
||||
index.ts
|
||||
query/
|
||||
query.ts
|
||||
query.md
|
||||
query.types.ts
|
||||
query.test.ts
|
||||
index.ts
|
||||
utils/
|
||||
intersection.ts
|
||||
intersection.md
|
||||
intersection.test.ts
|
||||
tests/
|
||||
property.test.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Impact
|
||||
|
||||
**Downstream**: `@suaveplan/weapons` uses `queryRay` for hitscan; `@suaveplan/r3f-combat` renders hitbox debug overlays. Prerequisites: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/spatial-hash`.
|
||||
Reference in New Issue
Block a user