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

4.4 KiB
Raw Permalink Blame History

OpenSpec Change: enterprise-gaming-destructibles

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

Summary

Deliver @suaveplan/destructibles on the genesis branch from scratch at enterprise quality. The package provides a destructible environment system with fracture patterns, debris management, and loot spawning. A DestructibleObject holds health state and a FracturePattern — a list of named fragment descriptors with relative positions, masses, and spawn probabilities; when health reaches zero, fracture() computes which fragments to spawn and what loot to drop. A DebrisManager tracks active debris with lifetime timers. Genesis adds Zod schemas, structured errors, OTel destruction 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:^) DestructiblesError; DESTRUCT.* codes
@suaveplan/types (workspace:^) Clock, IdGenerator
@suaveplan/events (workspace:^) destructible:fracture, destructible:debris:expired events
@suaveplan/combat (workspace:^) DamageEvent consumed to damage destructibles
zod (catalog:forms) FracturePattern, LootTable schemas
@opentelemetry/api (catalog:observability) Fracture event counter

Public API surface

interface FragmentDescriptor {
  id: string
  relativePosition: Vec3
  mass: number
  spawnProbability: number    // 0–1
  impulse?: Vec3
}

interface FracturePattern {
  fragments: FragmentDescriptor[]
  debrisLifetime?: number     // seconds; undefined = permanent
}

interface LootEntry {
  itemId: string
  probability: number
  quantity: [min: number, max: number]
}

interface LootTable {
  entries: LootEntry[]
  rollCount: [min: number, max: number]
}

function createDestructibleObject(options: DestructibleOptions): DestructibleObject

interface DestructibleOptions {
  id: string
  maxHealth: number
  fracturePattern: FracturePattern
  lootTable?: LootTable
  clock?: Clock
}

interface DestructibleObject {
  readonly id: string
  readonly health: number
  readonly isDestroyed: boolean
  applyDamage(event: DamageEvent): void
  fracture(rng: Rng): FractureResult
  repair(amount?: number): void
}

interface FractureResult {
  fragments: SpawnedFragment[]
  loot: DroppedItem[]
}

interface SpawnedFragment {
  id: string
  position: Vec3
  impulse: Vec3
  expiresAt?: number
}

interface DroppedItem {
  itemId: string
  quantity: number
  position: Vec3
}

// Debris manager
function createDebrisManager(options?: DebrisManagerOptions): DebrisManager

interface DebrisManager {
  add(fragment: SpawnedFragment): void
  tick(dt: number): ExpiredFragment[]
  getActive(): SpawnedFragment[]
  clear(): void
}

Error codes

type DestructErrorCode =
  | 'DESTRUCT_OBJECT_NOT_FOUND'
  | 'DESTRUCT_ALREADY_DESTROYED'
  | 'DESTRUCT_INVALID_PATTERN'
  | 'DESTRUCT_LOOT_FAILED'

New additions for genesis

  1. RNG-driven loot rolls — injectable Rng from @suaveplan/types for deterministic loot in tests.
  2. Debris lifetime timer — DebrisManager.tick() returns expired fragments for physics engine cleanup.
  3. OTel — destructible.fractures_total counter; destructible.loot_drops_total counter.

File layout

gaming/combat/destructibles/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    error-codes.ts
    constants/index.ts
    types/common.ts
    types/common.md
    core/
      destructible-object/
        destructible-object.ts
        destructible-object.md
        destructible-object.types.ts
        destructible-object.test.ts
        index.ts
      debris-manager/
        debris-manager.ts
        debris-manager.md
        debris-manager.types.ts
        debris-manager.test.ts
        index.ts
    utils/
      loot-roller.ts
      loot-roller.md
      loot-roller.test.ts
  tests/
    integration.test.ts

Impact

Downstream: @suaveplan/r3f-combat spawns visual fragments from FractureResult. Prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/combat.