Files
2026-05-27 23:29:53 +01:00

4.0 KiB

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

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

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

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.