Files
suaveplan/openspec/changes/enterprise-gaming-spatial-hash/proposal.md
2026-05-27 23:29:53 +01:00

3.9 KiB

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

// 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

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

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.