Spaces:
Paused
Paused
Commit History
-
Widen idle and formation unit spacing by 20%β
ClaudeUnverified signatureTwo independent levers, kept deliberately separate so they don't compound into each other: - engine/formation.js: COARSENESS (the existing formation-spacing multiplier, introduced by a prior "units sat too close together" pass at 1.15x) goes to 1.38 β a further +20% on top of that. It already cascades correctly through every formation shape (grid, line, wedge, circle) and nested formation-of-formations spacing with no other change needed. - engine/separation.js: idle/general collision separation had no padding at all before this β minDist was the bare sum of two units' radii, so same-owner units at rest settled shoulder to shoulder. Added a standalone SEPARATION_PAD_MULT (1.2), applied only to minDist here, NOT to entities.js's own radius fields β touching radius directly would have also fed formation.js's own spacing calculation (which reads that same field), compounding the two changes to 44% instead of two clean, independent 20% increases. Combat packing isβ¦873d661
-
Bound applySeparation's per-unit candidate scan under pathological densityβ
Claude +1: Claude Sonnet 5Unverified signatureA user-reported CPU spike traced to a background world whose idle AI army had grown to 642 same-owner units piled on one rally point. applySeparation's grid-accelerated neighbor query scales with local density, not army size, so a single tick there ran up to ~94ms with ~15ms in separation alone. applySeparation now caps candidates resolved per unit per call (MAX_SEPARATION_NEIGHBORS), with the scan window rotating by the unit's grid index and the simulation tick so a huge pile still fully settles over time instead of some units being permanently skipped. Ordinary battles never approach the cap. Cuts the profiled world's separation phase by ~74% and its total tick by ~40%. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvU3W5f2Vnk2oFKpud9jmTee2be58
-
Add JSDoc typedefs + // @ts-check for the core sim shapes (no build step)β
Claude +1: Claude Opus 4.8Unverified signatureAddress the top architectural-review finding β an untyped mutable `state` bag threaded through ~360 functions, where a mistyped or renamed field reads undefined silently and the same-seed determinism test can't see it. Now that class of bug is a check-time error. Zero runtime cost and no build step: the shipped code stays plain ES modules. - engine/types.js: JSDoc @typedefs for the core shapes (State, Unit, Building, Player, AiState, Resources, Cargo, Order, ResourceNode, GameMap, Fog, Market, Diplomacy, Galaxy, β¦). No runtime code, never imported β global typedefs the checker and any editor's TS language service resolve project-wide. - jsconfig.json + `npm run typecheck` (tsc, noEmit): checking is OPT-IN per file via a `// @ts-check` pragma, so coverage grows file-by-file. Editors check the annotated files live with no install; the script needs a tsc available. - Enabled + annotated on the core data + hot path: state.js (the factories bind the types to the real objects), β¦e3658fa -
Tier 5: dedup and derive engine helpers (byte-identical replays)β
Claude +1: Claude Opus 4.8Unverified signatureRemove copy-paste and stale magic numbers from the engine, keeping every change deterministic (same-seed replays stay byte-for-byte identical, the determinism + engine-purity guards stay green). - rng.js: centralise the string hash (h=7, h*31+c) as hashStr(). It lived byte-identical in four modules (combat/gather/movement/separation) for a worker's orbit angle, an avoidance dodge, a spread-fire pick and the coincident-pair nudge β one home so a change can't drift between copies. - movement.js: derive MAX_UNIT_RADIUS from the roster instead of a stale literal (10, "Breacher") that under-sized the avoidance query the moment a wider hull (Bulk Freighter, 15) was added; separation.js's SEP_RADIUS now keys off it too. A larger query returns a superset the exact-distance check still filters identically, so replays are unchanged. - movement.js: add keepEscortStation() next to escortSlot() and route the three identical escort branches (combat ship, worker, support drone) thrβ¦8583c67
-
Tier 6: performance & scale for large mapsβ
Claude +1: Claude Fable 5Unverified signature- Uniform spatial grid (engine/grid.js), rebuilt once per tick, retires the three per-tick O(n^2) neighbour scans: separation, movement avoidance, and combat target acquisition now query only nearby cells. ~2.6x faster on the separation pass alone at 500 units, and the gap widens with scale. A full-scan fallback keeps every direct unit test byte-for-byte unchanged. - Viewport culling in render.js: fog cells, nodes, buildings and units outside the camera's world rect are skipped, so draw cost tracks what's on screen rather than total map size (16k+ fog cells on a 4x map). - Cache each resource node's silhouette (the seeded-PRNG polygon) instead of recomputing it every frame; only its radius changes as it depletes. - Index map.nodes by id (map.nodesById) β O(1) node lookups in gather, the AI, replacing per-tick linear .find scans that grew with map size. - Loop substep cap so a heavy tick degrades to slow-motion instead of spiralling into an ever-deepening backlog. - Prβ¦6d7e8fa
-
Add a general same-owner unit separation pass to actually fix stackingβ
Claude +1: Claude Sonnet 5Unverified signatureThe formation-spread fix only covered the two places that explicitly issue a group order (player right-click, AI's attack wave) β it missed the actual case the user hit: production.js sends every freshly spawned unit to the exact same building.rally point directly, with no formation spread at all, so units piling up after production still stacked solid. Rather than patch each spawn/order site individually, engine/sim.js now runs a generic applySeparation() pass every tick: any two same-owner units (any type, however they got there) that end up overlapping get pushed apart proportional to the overlap. This is a correction pass independent of orders, so it catches stacking from any source β rally points, group moves, gather nodes, future code that assigns positions some other way β instead of needing a fix at every place that sets a destination. Different-owner pairs are left alone so opposing units can still close to weapon range. 6 new tests cover pairwise separation, the coincident-β¦a8d58c2