Skip to content

perf: spatial hash grid, sqrt elimination, GC-free hot path#1

Open
OldCrow wants to merge 3 commits intotjards:masterfrom
OldCrow:master
Open

perf: spatial hash grid, sqrt elimination, GC-free hot path#1
OldCrow wants to merge 3 commits intotjards:masterfrom
OldCrow:master

Conversation

@OldCrow
Copy link
Copy Markdown

@OldCrow OldCrow commented Apr 14, 2026

Summary

Reduces per-frame complexity from O(n²) to O(n) for bounded-density interactions, extending usable agent count from ~200 to 2000+ at 60fps.

Changes

  • Spatial hash grid (spatial-grid.js): O(1) neighbor queries replace O(n) full scans in herd and shepherd update loops
  • Squared distance comparisons: range checks avoid Math.sqrt, only computed when normalizing direction vectors
  • GC pressure eliminated: pre-allocated limitMagnitudeInto output, removed per-frame precomputeOtherShepherds() array allocation and [...herd.members] spread
  • FPS counter overlay: dark background badge for benchmarking on any canvas color
  • .gitignore and OPTIMIZATION.md: documentation covering methodology, design decisions, measured results, and future work

Bug Fix

Shepherd closest-herd-member search uses full list scan (not spatial grid) to correctly handle wrap-around boundaries.

Measured Results (144Hz monitor)

Agents FPS Notes
25 144 Default, vsync-capped
1100 144 Still vsync-capped
2100 ~100 First measurable drop, est. ~7× over original

No external dependencies. All vanilla JavaScript.

Co-Authored-By: Oz oz-agent@warp.dev

OldCrow and others added 2 commits April 13, 2026 23:58
Reduces per-frame complexity from O(n^2) to O(n) for bounded-density
interactions, extending usable agent count from ~200 to 2000+.

Performance:
- Spatial hash grid (spatial-grid.js): O(1) neighbor queries replace
  O(n) full scans in herd and shepherd update loops
- Squared distance comparisons: range checks avoid sqrt, only computed
  when normalizing direction vectors
- GC pressure eliminated: pre-allocated limitMagnitude output, removed
  per-frame array spreads and precomputeOtherShepherds allocation

Bug fixes:
- Shepherd closest-herd-member search uses full list (not grid) to
  handle wrap-around boundaries correctly

Additions:
- .gitignore
- OPTIMIZATION.md: problem statement, methodology, per-file changes,
  design decisions (spatial hash vs KD-tree, GC avoidance, batched
  rendering), measured results, future work
- FPS counter overlay (dark background for visibility on light canvas)

Measured results (144Hz monitor):
- 144 FPS sustained to 1100 agents (vsync-capped)
- ~100 FPS at 2100 agents (est. ~7x over original O(n^2))

No external dependencies. All vanilla JavaScript.

Co-Authored-By: Oz <oz-agent@warp.dev>
Cantor pairing is only bijective for non-negative integers. query()
could produce negative cell coordinates for agents near the top/left
canvas edges, causing hash collisions with positive cells. This returned
duplicate agents in results, multi-counting their forces.

Clamp minCx/minCy to 0 since agents always wrap to non-negative
positions—negative cells are guaranteed empty.

Co-Authored-By: Oz <oz-agent@warp.dev>
@OldCrow
Copy link
Copy Markdown
Author

OldCrow commented Apr 15, 2026

Pushed a bugfix in 5637394: the spatial grid's Cantor pairing hash is only bijective for non-negative integers, but query() could produce negative cell coordinates for agents near the top/left canvas edges. Those negative coords collided with positive cell keys, returning duplicate agents and multi-counting their forces.

Fix: clamp minCx/minCy to 0 in query(). Negative cells are guaranteed empty since agent positions always wrap to non-negative values.

Co-Authored-By: Oz <oz-agent@warp.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant