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

5.2 KiB

OpenSpec Change: enterprise-gaming-weapons

  • Change ID: enterprise-gaming-weapons
  • Package: @suaveplan/weapons
  • Category: gaming/combat
  • Target path: gaming/combat/weapons
  • Status: PROPOSED
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/weapons.md

Summary

Deliver @suaveplan/weapons on the genesis branch from scratch at enterprise quality. The package provides a weapon system with projectile ballistics, melee attacks, recoil patterns, ammo management, and attachment slots. A WeaponRegistry holds typed WeaponDefinition descriptors; WeaponInstance tracks runtime state (current ammo, reload timer, heat); ProjectileSimulator advances projectile positions each tick applying drag and gravity. All outputs are damage events consumable by @suaveplan/combat. Genesis adds Zod schemas for weapon definitions, structured errors, OTel shot counters, 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:^) WeaponError; WEAPON.* codes
@suaveplan/types (workspace:^) Clock, IdGenerator
@suaveplan/events (workspace:^) weapon:fire, weapon:reload, weapon:empty events
@suaveplan/combat (workspace:^) DamageEvent type consumed by fire logic
zod (catalog:forms) WeaponDefinition, AmmoConfig schemas
@opentelemetry/api (catalog:observability) Shots-fired counter, reload timer histogram

Public API surface

type WeaponClass = 'pistol' | 'rifle' | 'shotgun' | 'sniper' | 'smg' | 'melee' | 'explosive'

interface WeaponDefinition {
  id: string
  name: string
  class: WeaponClass
  damage: number
  damageType: DamageType
  fireRate: number          // rounds per second
  magazineSize: number
  reloadTime: number        // seconds
  projectileSpeed?: number  // m/s; undefined = instant hitscan
  spread: number            // degrees
  recoilPattern?: Vec2[]    // sequence of screen-space offsets
  attachmentSlots?: string[]
  isMelee?: boolean
  meleeRange?: number       // meters
}

function createWeaponRegistry(): WeaponRegistry
interface WeaponRegistry {
  register(def: WeaponDefinition): void
  get(id: string): WeaponDefinition | undefined
  list(): WeaponDefinition[]
}

function createWeaponInstance(def: WeaponDefinition, options?: WeaponInstanceOptions): WeaponInstance

interface WeaponInstance {
  readonly definition: WeaponDefinition
  readonly ammo: number
  readonly isReloading: boolean
  readonly nextFireTime: number
  fire(origin: Vec3, direction: Vec3, shooterId: string): FireResult | null
  reload(): void
  tick(dt: number): void
  addAttachment(slot: string, attachment: Attachment): void
  removeAttachment(slot: string): void
}

interface FireResult {
  projectileId?: string       // present for ballistic projectiles
  damageEvent?: DamageEvent   // present for hitscan
  muzzlePosition: Vec3
  direction: Vec3
}

// Projectile simulator (ballistic weapons)
function createProjectileSimulator(options?: ProjectileSimulatorOptions): ProjectileSimulator

interface ProjectileSimulator {
  spawn(id: string, origin: Vec3, velocity: Vec3, def: WeaponDefinition): void
  tick(dt: number): ProjectileUpdate[]
  destroy(id: string): void
}

interface ProjectileUpdate {
  id: string
  position: Vec3
  velocity: Vec3
  traveledMeters: number
  expired: boolean
}

interface Attachment {
  id: string
  slot: string
  damageMultiplier?: number
  fireRateMultiplier?: number
  spreadModifier?: number
  displayName: string
}

Error codes

type WeaponErrorCode =
  | 'WEAPON_NOT_FOUND'
  | 'WEAPON_EMPTY'
  | 'WEAPON_RELOADING'
  | 'WEAPON_FIRE_RATE_EXCEEDED'
  | 'WEAPON_INVALID_ATTACHMENT'

New additions for genesis

  1. Ballistic drop — projectile velocity decreases by gravity * dt; configurable drag coefficient.
  2. Recoil pattern playback — recoilPattern cycles through offsets each shot, resetting after trigger release.
  3. Attachment modifiers — multiplicative stacking for damage, fire rate, spread; additive for reload time.
  4. OTel — weapon.shots_fired_total counter (by weapon class); weapon.reload_duration_ms histogram.

File layout

gaming/combat/weapons/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    error-codes.ts
    constants/index.ts
    types/common.ts
    types/common.md
    core/
      weapon-registry/
        weapon-registry.ts
        weapon-registry.md
        weapon-registry.types.ts
        weapon-registry.test.ts
        index.ts
      weapon-instance/
        weapon-instance.ts
        weapon-instance.md
        weapon-instance.types.ts
        weapon-instance.test.ts
        index.ts
      projectile-simulator/
        projectile-simulator.ts
        projectile-simulator.md
        projectile-simulator.types.ts
        projectile-simulator.test.ts
        index.ts
  tests/
    integration.test.ts

Impact

Downstream: @suaveplan/r3f-combat renders muzzle flash and projectile trails from fire events. Prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/combat.