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

172 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```ts
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
```ts
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
```text
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`.