[BUG] Client tab locks up on production after long sessions (full terrain rebuild every tick) #13

Closed
opened 2026-10-18 07:21:40 +02:00 by agent-claude · 1 comment
Collaborator

Symptom

On production the game tab locks up after a while (reported at colony tick ~9,000 and ~294,000). Refreshing doesn't recover it; only a fresh tab does.

Root cause (client render path)

  • ColonySim.stepTick() marks every growing crop tile dirty every tick, so once any growing zone is planted, every 10 Hz S2C_COLONY_DELTA has non-empty changedTiles.
  • On each such delta the client's ColonyPixiRenderer.onTickDeltaApplied() destroys and recreates all 10,000 terrain sprites, all crop sprites, and every item stack (with a new Text per stack) — 10×/sec.
  • renderDynamicEntities() also destroys/recreates every pawn's Container, Graphics, Sprites and Text label on every animation frame.
  • Panel DOM (innerHTML roster/inspector) is rebuilt per delta.

As the colony grows, the main thread can't keep up with 10 deltas/sec; WebSocket messages queue up and the renderer process hangs. Chrome reuses the hung renderer process on reload, so refresh doesn't help but a new tab does.

Fix

  • Persistent per-tile terrain/crop sprites updated only for changed tiles.
  • Coalesce delta-driven redraws and DOM panel updates to once per animation frame.
  • Reuse pawn display nodes and labels instead of recreating each frame.
## Symptom On production the game tab locks up after a while (reported at colony tick ~9,000 and ~294,000). Refreshing doesn't recover it; only a fresh tab does. ## Root cause (client render path) - `ColonySim.stepTick()` marks every growing crop tile dirty **every tick**, so once any growing zone is planted, every 10 Hz `S2C_COLONY_DELTA` has non-empty `changedTiles`. - On each such delta the client's `ColonyPixiRenderer.onTickDeltaApplied()` destroys and recreates all **10,000 terrain sprites**, all crop sprites, and every item stack (with a new `Text` per stack) — 10×/sec. - `renderDynamicEntities()` also destroys/recreates every pawn's Container, Graphics, Sprites and `Text` label on **every animation frame**. - Panel DOM (`innerHTML` roster/inspector) is rebuilt per delta. As the colony grows, the main thread can't keep up with 10 deltas/sec; WebSocket messages queue up and the renderer process hangs. Chrome reuses the hung renderer process on reload, so refresh doesn't help but a new tab does. ## Fix - Persistent per-tile terrain/crop sprites updated only for changed tiles. - Coalesce delta-driven redraws and DOM panel updates to once per animation frame. - Reuse pawn display nodes and labels instead of recreating each frame.
Author
Collaborator

Handoff (agent-claude) — PR #14

Completed

  • client/src/colony-renderer.ts: incremental per-tile terrain/crop sprites, frame-coalesced dirty flushing, pooled pawn + item-stack views.
  • client/src/main.ts: HUD/inspector DOM refresh coalesced via rAF; passes TickDelta to the renderer.
  • Reproduced locally: before = heap 1.1 GB within ~14 s and 52% main-thread blocking; after = heap flat ~24 MB, no steady-state blocking. Tests + typecheck green.

Remains

  • Peer review (Gemini) + @johnw merge approval, then npm run deploy.
  • Follow-up: growing tiles are still sent in every delta (bandwidth/JSON.parse cost scales with farm size).

Gotchas

  • No sim-core/server/wire changes, so determinism and replay are unaffected.
  • ColonyPixiRenderer.onTickDeltaApplied(delta) signature changed (was two booleans).
**Handoff (agent-claude)** — PR #14 **Completed** - `client/src/colony-renderer.ts`: incremental per-tile terrain/crop sprites, frame-coalesced dirty flushing, pooled pawn + item-stack views. - `client/src/main.ts`: HUD/inspector DOM refresh coalesced via rAF; passes `TickDelta` to the renderer. - Reproduced locally: before = heap 1.1 GB within ~14 s and 52% main-thread blocking; after = heap flat ~24 MB, no steady-state blocking. Tests + typecheck green. **Remains** - Peer review (Gemini) + @johnw merge approval, then `npm run deploy`. - Follow-up: growing tiles are still sent in every delta (bandwidth/JSON.parse cost scales with farm size). **Gotchas** - No sim-core/server/wire changes, so determinism and replay are unaffected. - `ColonyPixiRenderer.onTickDeltaApplied(delta)` signature changed (was two booleans).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
game-dev/RicosWorld#13
No description provided.