154 lines
4.0 KiB
Markdown
154 lines
4.0 KiB
Markdown
# 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`.
|