Initial Commit
This commit is contained in:
134
openspec/changes/enterprise-gaming-spatial-hash/proposal.md
Normal file
134
openspec/changes/enterprise-gaming-spatial-hash/proposal.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# OpenSpec Change: enterprise-gaming-spatial-hash
|
||||
|
||||
- **Change ID**: enterprise-gaming-spatial-hash
|
||||
- **Package**: `@suaveplan/spatial-hash`
|
||||
- **Category**: gaming/engine
|
||||
- **Target path**: `gaming/engine/spatial-hash`
|
||||
- **Status**: PROPOSED
|
||||
- **Date**: 2026-04-24
|
||||
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/spatial-hash.md`
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Deliver `@suaveplan/spatial-hash` on the genesis branch from scratch at enterprise quality. The package provides spatial hashing for O(1) broad-phase 2D/3D proximity queries — used by physics, AI, and rendering culling systems. A uniform grid divides world space into cells; each cell maps to a hash bucket holding entity IDs. Insertion, removal, and range queries run in O(1) amortised time assuming uniform entity distribution. Genesis adds typed 2D and 3D variants, Zod option schemas, OTel instrumentation, structured errors, and property-based tests verifying query completeness.
|
||||
|
||||
---
|
||||
|
||||
## Current-state audit (genesis)
|
||||
|
||||
Package does not exist on genesis yet — fresh build.
|
||||
|
||||
---
|
||||
|
||||
## Available workspace deps on genesis
|
||||
|
||||
| Package | Role |
|
||||
|---|---|
|
||||
| `@suaveplan/error` (`workspace:^`) | `SpatialHashError`; `SPATIAL_HASH.*` codes |
|
||||
| `@suaveplan/types` (`workspace:^`) | `IdGenerator` |
|
||||
| `zod` (`catalog:forms`) | Option schemas |
|
||||
| `@opentelemetry/api` (`catalog:observability`) | Query time histogram, cell-count gauge |
|
||||
|
||||
---
|
||||
|
||||
## Public API surface
|
||||
|
||||
```ts
|
||||
// 2D
|
||||
function createSpatialHash2D(options: SpatialHash2DOptions): SpatialHash2D
|
||||
|
||||
interface SpatialHash2DOptions {
|
||||
cellSize: number
|
||||
initialCapacity?: number
|
||||
}
|
||||
|
||||
interface SpatialHash2D {
|
||||
insert(id: number, x: number, y: number): void
|
||||
remove(id: number): void
|
||||
move(id: number, x: number, y: number): void
|
||||
queryRadius(x: number, y: number, radius: number): number[]
|
||||
queryAABB(minX: number, minY: number, maxX: number, maxY: number): number[]
|
||||
clear(): void
|
||||
readonly size: number
|
||||
}
|
||||
|
||||
// 3D
|
||||
function createSpatialHash3D(options: SpatialHash3DOptions): SpatialHash3D
|
||||
|
||||
interface SpatialHash3DOptions {
|
||||
cellSize: number
|
||||
initialCapacity?: number
|
||||
}
|
||||
|
||||
interface SpatialHash3D {
|
||||
insert(id: number, x: number, y: number, z: number): void
|
||||
remove(id: number): void
|
||||
move(id: number, x: number, y: number, z: number): void
|
||||
queryRadius(x: number, y: number, z: number, radius: number): number[]
|
||||
queryAABB(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number): number[]
|
||||
clear(): void
|
||||
readonly size: number
|
||||
}
|
||||
```
|
||||
|
||||
### Error codes
|
||||
|
||||
```ts
|
||||
type SpatialHashErrorCode =
|
||||
| 'SPATIAL_HASH_ENTITY_NOT_FOUND'
|
||||
| 'SPATIAL_HASH_INVALID_CELL_SIZE'
|
||||
| 'SPATIAL_HASH_QUERY_OUT_OF_BOUNDS'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## New additions for genesis
|
||||
|
||||
1. **Typed 2D and 3D implementations** — separate factories; 3D uses cantor-triple hash for cell keys.
|
||||
2. **Float32Array-backed position cache** — tracks entity positions to support O(1) `move()` without caller re-inserting.
|
||||
3. **OTel** — `spatial_hash.query_duration_ms` histogram, `spatial_hash.entity_count` gauge.
|
||||
4. **Property-based tests** — fast-check: `queryRadius` completeness (every inserted entity within radius is returned), no false negatives.
|
||||
|
||||
---
|
||||
|
||||
## File layout
|
||||
|
||||
```text
|
||||
gaming/engine/spatial-hash/
|
||||
package.json
|
||||
tsconfig.json
|
||||
vitest.config.ts
|
||||
src/
|
||||
index.ts
|
||||
error-codes.ts
|
||||
constants/index.ts
|
||||
types/common.ts
|
||||
types/common.md
|
||||
core/
|
||||
spatial-hash-2d/
|
||||
spatial-hash-2d.ts
|
||||
spatial-hash-2d.md
|
||||
spatial-hash-2d.types.ts
|
||||
spatial-hash-2d.test.ts
|
||||
index.ts
|
||||
spatial-hash-3d/
|
||||
spatial-hash-3d.ts
|
||||
spatial-hash-3d.md
|
||||
spatial-hash-3d.types.ts
|
||||
spatial-hash-3d.test.ts
|
||||
index.ts
|
||||
utils/
|
||||
hash.ts
|
||||
hash.md
|
||||
hash.test.ts
|
||||
tests/
|
||||
property.test.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Impact
|
||||
|
||||
**Downstream**: `@suaveplan/hitbox`, `@suaveplan/r3f-pathfinding`, AI packages use spatial hash for broad-phase. Prerequisites: `@suaveplan/error`, `@suaveplan/types`.
|
||||
48
openspec/changes/enterprise-gaming-spatial-hash/tasks.md
Normal file
48
openspec/changes/enterprise-gaming-spatial-hash/tasks.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Tasks: enterprise-gaming-spatial-hash
|
||||
|
||||
## 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/engine/spatial-hash/` (`@suaveplan/spatial-hash`, `0.1.0`, `sideEffects: false`)
|
||||
- [ ] `tsconfig.json`, `vitest.config.ts`
|
||||
|
||||
## Phase 2 — Error codes & constants
|
||||
|
||||
- [ ] `src/error-codes.ts` — `SpatialHashError`, `SPATIAL_HASH.*` codes
|
||||
- [ ] `src/constants/index.ts` — `DEFAULT_INITIAL_CAPACITY`
|
||||
|
||||
## Phase 3 — Types
|
||||
|
||||
- [ ] `src/types/common.ts` + `common.md`
|
||||
|
||||
## Phase 4 — Hash utilities
|
||||
|
||||
- [ ] `src/utils/hash.ts` — `hashCell2D(cx, cy)`, `hashCell3D(cx, cy, cz)` using integer cantor/XOR hash
|
||||
- [ ] Tests + docs
|
||||
|
||||
## Phase 5 — 2D spatial hash
|
||||
|
||||
- [ ] `src/core/spatial-hash-2d/spatial-hash-2d.ts` — insert/remove/move/queryRadius/queryAABB
|
||||
- [ ] Float32Array position cache
|
||||
- [ ] OTel histogram + gauge
|
||||
- [ ] Tests + docs
|
||||
|
||||
## Phase 6 — 3D spatial hash
|
||||
|
||||
- [ ] `src/core/spatial-hash-3d/spatial-hash-3d.ts` — same surface, 3D coordinates
|
||||
- [ ] Tests + docs
|
||||
|
||||
## Phase 7 — Property tests
|
||||
|
||||
- [ ] `tests/property.test.ts` — fast-check: query completeness, no false negatives, size invariants
|
||||
|
||||
## Phase 8 — Pre-publish gate
|
||||
|
||||
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/spatial-hash` green
|
||||
- [ ] 100% coverage
|
||||
- [ ] Publish: `bun scripts/publish.ts --package @suaveplan/spatial-hash`
|
||||
Reference in New Issue
Block a user