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`.
|
||||
46
openspec/changes/enterprise-gaming-hitbox/tasks.md
Normal file
46
openspec/changes/enterprise-gaming-hitbox/tasks.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Tasks: enterprise-gaming-hitbox
|
||||
|
||||
## 0. Pre-flight (non-negotiable)
|
||||
|
||||
- [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each)
|
||||
- [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
|
||||
- [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
|
||||
|
||||
## Phase 1 — Scaffold
|
||||
|
||||
- [ ] Create `gaming/combat/hitbox/` (`@suaveplan/hitbox`, `0.1.0`, `sideEffects: false`)
|
||||
- [ ] `tsconfig.json`, `vitest.config.ts`
|
||||
|
||||
## Phase 2 — Error codes & constants
|
||||
|
||||
- [ ] `src/error-codes.ts` + `src/constants/index.ts` — default zone multipliers
|
||||
|
||||
## Phase 3 — Types
|
||||
|
||||
- [ ] `src/types/common.ts` + `common.md`
|
||||
|
||||
## Phase 4 — Intersection math
|
||||
|
||||
- [ ] `src/utils/intersection.ts` — ray-AABB, ray-sphere, ray-capsule, sphere-AABB, AABB-AABB
|
||||
- [ ] Tests + docs
|
||||
|
||||
## Phase 5 — Hitbox rig
|
||||
|
||||
- [ ] `src/core/hitbox-rig/hitbox-rig.ts` — bone update, descriptor validation, volume list
|
||||
- [ ] Tests + docs
|
||||
|
||||
## Phase 6 — Query
|
||||
|
||||
- [ ] `src/core/query/query.ts` — `queryRay`, `querySphere`, `queryAABB` with spatial-hash broad-phase, result sorting
|
||||
- [ ] OTel instrumentation
|
||||
- [ ] Tests + docs
|
||||
|
||||
## Phase 7 — Property tests
|
||||
|
||||
- [ ] `tests/property.test.ts` — ray-sphere hit distance bounds, AABB containment
|
||||
|
||||
## Phase 8 — Pre-publish gate
|
||||
|
||||
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/hitbox` green
|
||||
- [ ] 100% coverage
|
||||
- [ ] Publish: `bun scripts/publish.ts --package @suaveplan/hitbox`
|
||||
Reference in New Issue
Block a user