perf(game): three.js graphics memory & hot-path optimizations (plan phases 1–3, 5.1) - #4855
Open
ponderingdemocritus wants to merge 1 commit into
Open
perf(game): three.js graphics memory & hot-path optimizations (plan phases 1–3, 5.1)#4855ponderingdemocritus wants to merge 1 commit into
ponderingdemocritus wants to merge 1 commit into
Conversation
…raphics plan phase 3) Remove the per-frame allocations that grow with army/structure count on the worldmap hot path. Each change lands with unit tests or is a behaviour-preserving refactor covered by existing tests. - 3.1 ArmyModel resolved a moving army's hex biome via BigInt/simplex-noise twice per frame, though biome is immutable per hex. Memoize via a new bounded per-hex cache (utils/bounded-hex-cache.ts, tested) with a stable resolver field so the lookups allocate no closures. - 3.2 The attachment-transform sync allocated a 12-field input object + 5 delegate closures for every visible army each frame whenever any cosmetic attachment was active, even though the callee early-returns for non-attachment entities. Hoist the membership check to both call sites so it scales with attachment count, not army count (behaviour-preserving — the callee's guard is identical). - 3.3 The compact label built the entire entity-label view model (incl. detailRows) per moving army per frame just to read the title. Export resolveArmyTitle/ resolveStructureTitle and call them directly; output is unchanged. - 3.4 getStructureByHexCoords scanned every structure with an Array.from+find per group on each pointermove. Resolve from the chunkToStructures spatial bucket (the same index the visible-structure pass trusts) via a new tested exact-hex lookup. - 3.6 Frame-loop micro-churn: renderer-diagnostics skips the per-frame window snapshot when the scene name is unchanged (tested); the 1Hz stamina recompute is gated behind the existing armies-tick policy (battle timers keep the 1s cadence); the centralized visibility manager mutates its cache record in place instead of allocating a fresh one on every miss. Deferred to a follow-up (needs a new ECS spatial index + runtime QA): 3.5 (the global TileOpt hydration scan / per-entity Position allocation). Note: vitest/tsc not run here (node killed in worktree shell); red->green verified by construction, CI runs the suite. Wants runtime QA: structure hover resolves via the spatial index, stamina labels update on tick advance, no visibility regressions.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
Contributor
|
Failed to generate code suggestions for PR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Memory and hot-path performance work for the Three.js game client (
client/apps/game/src/three), aimed at low-spec hardware. The changes come out of a deep multi-agent review of the graphics layer (328 files / ~72k lines); the full prioritized plan lives inGRAPHICS_OPTIMIZATION_PLAN.md(added in the Phase 1 commit).This PR bundles four phases of that plan. Commits are scoped one-per-phase, so it reviews cleanly commit-by-commit.
What's in here (by commit)
9582acc— Phase 1: scope worldmap terrain cache invalidationStop the cache-invalidation storms that defeat the terrain cache during exploration/panning.
b667108— Phase 2.1–2.3: GPU leaks + morph-texture crashsetMorphAtindexed past a fixedFloat32Arrayonce >64 animated army slots existed and threw aRangeErroron the frame path.49422835— Phase 2.5: manager destroy hygieneChestManager/ArmyModel/InstancedModeldispose paths now free instanced GPU buffers + morph textures (viaInstancedMesh.dispose(), which leaves shared geometry/materials intact), with anisDestroyedguard on the async chest load; removed a deadGrouphexception leaked on every grid rebuild.586d378— Phase 5.1: share biome GLTFs across scenesThe ~23 biome GLBs were parsed and GPU-resident twice (worldmap + hexception). They're now parsed once via a module cache and shared; only per-scene instance buffers + morph textures differ. Includes an idempotent biome draw-order fix so the shared material resolves the same
renderOrderin both scenes.26b97886— Phase 3: hot-path allocation diet (scales with entity count)Array.fromper pointermove.How it was built
Deferred (intentionally, to focused follow-ups)
packages/core/world-update-listener.tsmust return its unsubscribers).Reviewer notes / test status
vitest+tsc. These were authored in a sandboxed worktree where node is killed, so the red→green cycle was verified by construction, not executed locally. Nothing else gates correctness of the new tests.RangeError); watchMatrixPool/attribute-pool stats during fast pans (dropped chunks return their attributes).🤖 Generated with Claude Code