Skip to content

Commit ae3a35f

Browse files
committed
Restore utility helpers, DOM helpers, and update docs
Recover src/shared/util.ts (16 functional collection helpers), src/client/dom.ts (declarative DOM helpers), and their tests from git history after accidental deletion during folder reorganization. Update CODING_STANDARDS.md with functional style guidance and DOM helper recommendations. Add utility adoption as top P2 priority in BACKLOG.md. Align doc cross-references with new folder structure.
1 parent 7e04c2a commit ae3a35f

File tree

10 files changed

+881
-29
lines changed

10 files changed

+881
-29
lines changed

docs/ARCHITECTURE.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Delta-V employs a full-stack TypeScript architecture built around a **shared pur
88

99
### Key Technologies
1010
- **Language**: TypeScript (strict mode) across the entire stack.
11-
- **Frontend**: HTML5 Canvas 2D API for rendering (`client/renderer.ts`), raw DOM/Events for UI and Input. No heavy frameworks (React/Vue/etc.) are used, ensuring maximum performance for the game loop.
11+
- **Frontend**: HTML5 Canvas 2D API for rendering (`client/renderer/renderer.ts`), raw DOM/Events for UI and Input. No heavy frameworks (React/Vue/etc.) are used, ensuring maximum performance for the game loop.
1212
- **Backend**: Cloudflare Workers for HTTP routing and Cloudflare Durable Objects for authoritative game state and WebSocket management.
1313
- **Build & Tools**: `esbuild` for lightning-fast client bundling, `wrangler` for local testing and deployment, and `vitest` for unit testing.
1414

@@ -21,7 +21,7 @@ The architecture is divided into three distinct layers: Shared Logic, Server, an
2121
### A. Shared Game Engine (`shared/`)
2222
This is the heart of the project. The decision to keep all game rules in a shared folder makes the system incredibly robust and completely unit-testable.
2323

24-
- **`game-engine.ts`**: A pure functional state machine. It takes the current `GameState` and player actions (e.g., astrogation orders, combat declarations) and returns a new `GameState` along with events (movements, combat results). **Crucially, it has no side effects (no DOM manipulation, no network calls, no storage access).**
24+
- **`engine/game-engine.ts`**: A pure functional state machine. It takes the current `GameState` and player actions (e.g., astrogation orders, combat declarations) and returns a new `GameState` along with events (movements, combat results). **Crucially, it has no side effects (no DOM manipulation, no network calls, no storage access).**
2525
- **`movement.ts`**: Contains the complex vector math, gravity well logic, and collision detection. Moving a ship is resolved strictly on an axial hex grid (using `hex.ts`).
2626
- **`combat.ts`**: Evaluates line-of-sight, calculates combat odds based on velocity/range modifiers, and resolves damage.
2727
- **`types.ts`**: The single source of truth for all data structures (`GameState`, `Ship`, `CombatResult`, network message payloads). This ensures the client and server never fall out of sync.
@@ -30,7 +30,7 @@ This is the heart of the project. The decision to keep all game rules in a share
3030
The backend leverages Cloudflare's edge network.
3131

3232
- **`index.ts`**: The standard Worker entry point. It creates tokenized game rooms, generates collision-checked 5-character codes, and forwards valid WebSocket requests.
33-
- **`game-do.ts` (Durable Object)**: Each game instance is backed by a single Durable Object. This ensures that all WebSocket connections for a specific game hit the same exact machine in Cloudflare's network, preventing race conditions.
33+
- **`game-do/game-do.ts` (Durable Object)**: Each game instance is backed by a single Durable Object. This ensures that all WebSocket connections for a specific game hit the same exact machine in Cloudflare's network, preventing race conditions.
3434
- Acts as the authoritative session and transport layer around `game-engine.ts`.
3535
- Handles WebSocket lifecycle (connections, reconnects, inactivity timeouts, turn timeouts).
3636
- Validates inputs before dispatch, passes them to the pure engine, stores the resulting state using the Durable Object `ctx.storage`, and broadcasts updates to connected clients.
@@ -40,10 +40,10 @@ The backend leverages Cloudflare's edge network.
4040
The frontend is responsible for rendering the pure hex-grid state into a smooth, continuous graphical experience.
4141

4242
- **`main.ts`**: The client-side controller. Manages WebSocket connections, local-AI execution, phase transitions, and orchestrates the Renderer, Input, and UI.
43-
- **`renderer.ts`**: A highly optimized Canvas 2D renderer. It separates logical hex coordinates from pixel coordinates. It features smooth camera interpolation, persistent trails, and movement/combat animations that occur *between* turn phases.
43+
- **`renderer/renderer.ts`**: A highly optimized Canvas 2D renderer. It separates logical hex coordinates from pixel coordinates. It features smooth camera interpolation, persistent trails, and movement/combat animations that occur *between* turn phases.
4444
- **`input.ts`**: Manages the complex state of user interaction (selecting burn vectors, queuing attacks, choosing targets) before finalizing and sending them to the server.
45-
- **`game-client-*.ts` / `renderer-*.ts` helper modules**: Pure client-side helpers for combat selection, input planning, minimap geometry, phase derivation, formatting, and tooltip/view-model logic. These keep the large coordinators testable without introducing a client framework.
46-
- **`ui.ts` / `audio.ts`**: Handles the HTML overlay (menus, HUD) and Web Audio API interactions.
45+
- **`game/` / `renderer/` / `ui/` subfolders**: Pure client-side helpers for combat selection, input planning, minimap geometry, phase derivation, formatting, and tooltip/view-model logic. These keep the large coordinators testable without introducing a client framework.
46+
- **`ui/ui.ts`** / **`audio.ts`**: Handles the HTML overlay (menus, HUD) and Web Audio API interactions.
4747
- **Visual Polish**: Employs a premium design system with glassmorphism tokens (backdrop-filters), tactile micro-animations (recoil, scaling glows), and pulsing orbital effects for high-end UX.
4848

4949
### D. Progressive Web App (`static/sw.js`, `static/site.webmanifest`)
@@ -71,16 +71,16 @@ Delta-V is a fully installable PWA. A lightweight hand-written service worker pr
7171
The next architectural gains are mostly about keeping the current design readable, not replacing it:
7272

7373
### A. Shared Engine
74-
- **Split `game-engine.ts` by phase when it becomes painful to navigate**: The engine remains a strong fit for pure functions and plain data. If the file continues to grow, phase-oriented modules are the natural next split.
74+
- **Engine is now decomposed by phase** (`engine/game-engine.ts`, `engine/combat.ts`, `engine/ordnance.ts`, `engine/victory.ts`, `engine/util.ts`): The engine remains a strong fit for pure functions and plain data.
7575
- **Avoid premature ECS migration**: The current rules engine has a small, stable entity set and turn-based processing. An ECS would likely make the rules harder to follow before it creates meaningful flexibility.
7676
- **Prefer a lightweight event log over full event sourcing**: Replays, reconnect catch-up, and spectator mode would benefit from an append-only turn log, but snapshots should remain the source of truth.
7777

7878
### B. Client
7979
- **Continue extracting pure helpers from `main.ts`**: Phase derivation, HUD view models, and local/remote result application should keep moving out of the main controller so browser orchestration stays thin.
80-
- **Split `renderer.ts` by render pass only when needed**: The renderer is large enough to justify future decomposition, but the right split is by visual responsibility, not by introducing a generic rendering framework.
80+
- **Renderer is now decomposed by visual responsibility** (`renderer/renderer.ts` plus `combat.ts`, `entities.ts`, `vectors.ts`, `effects.ts`, etc.): Further splits should follow the same pattern of visual responsibility.
8181
- **Add browser-side tests around input/UI/orchestration**: Shared rules are already well covered. The bigger refactor risk now sits in client coordination code.
8282

8383
### C. Server / Operations
84-
- **Keep refactoring `game-do.ts` by concern**: Session/auth handling, engine-result publishing, and timeout management should stay separate so features like spectators or replay catch-up can be added without bloating one class.
84+
- **`game-do/` is now split by concern** (`game-do.ts`, `messages.ts`, `session.ts`, `turns.ts`): Features like spectators or replay catch-up can be added without bloating one class.
8585
- **Public lobby hardening remains future work**: Longer opaque identifiers, rate limiting, and optional identity/account binding matter more than swapping validation libraries.
8686
- **Persistence beyond active rooms is still optional**: Durable Object storage is a good fit for live matches; D1 or another store only becomes necessary once match history or player progression matters.

docs/BACKLOG.md

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,117 @@ No open P0 items currently.
1111
### Continue mobile HUD/layout polish
1212
The HUD now measures its live top/bottom offsets instead of relying on fixed `rem` guesses, and the mobile top bar/action cluster have been tightened. There is still follow-up work to validate real-device behavior and finish any remaining overlap or clipping issues on very small screens.
1313

14-
**Files:** `static/style.css`, `src/client/ui.ts`, `src/client/renderer.ts`
14+
**Files:** `static/style.css`, `src/client/ui/ui.ts`, `src/client/renderer/renderer.ts`
1515

1616
## P2 — Code Quality
1717

18-
### Shrink main.ts further (1,286 lines)
19-
`main.ts` is the only coordinator still over 1,000 lines. Its methods are mostly 5-20 line glue between extracted helpers — no single block is large enough for easy extraction. Consider whether a second-level split (e.g., separating local-game orchestration from network orchestration) is worthwhile.
18+
### 20. Adopt utility helpers across the codebase
19+
`src/shared/util.ts` provides functional collection helpers (`sumBy`, `minBy`, `maxBy`, `filterMap`, `compact`, `count`, `partition`, `indexBy`, `groupBy`, `cond`, etc.) and `src/client/dom.ts` provides declarative DOM helpers (`el`, `show`/`hide`/`visible`, `byId`). These are tested and documented in CODING_STANDARDS.md but not yet widely used. Sweep the codebase to replace manual reduce/loop/filter patterns with the util helpers, and replace verbose createElement/addEventListener chains with the DOM helpers.
2020

21-
**Files:** `src/client/main.ts`
21+
**Benefit:** Reduces boilerplate, makes intent clearer, and establishes consistent patterns across the codebase.
22+
23+
**Files:** All files under `src/shared/` and `src/client/` — look for manual `reduce`, `for` loops building accumulators, `.filter().length`, `.map().filter(x => x != null)`, `document.createElement` chains, and `getElementById` with non-null assertions.
24+
25+
### 2a. Pull PlanningState out of the Renderer
26+
`PlanningState` lives on the `Renderer` but is mutated by `InputHandler`, `main.ts`, and read by renderer sub-modules. Move ownership to `GameClient`. The renderer and input handler receive it as a read reference. Mutations go through existing helpers like `createClearedCombatPlan`.
27+
28+
**Benefit:** Eliminates the tightest coupling in the codebase — three systems reaching into the same mutable bag. Enables snapshotting for debugging/undo.
29+
30+
**Files:** `src/client/main.ts`, `src/client/renderer/renderer.ts`, `src/client/input.ts`
31+
32+
**Details:** See REFACTORING.md Priority 1.
33+
34+
### 2b. Transport adapter for local vs network play
35+
9 `if (this.isLocalGame)` branches in `main.ts` duplicate logic. Define a `GameTransport` interface with `WebSocketTransport` and `LocalTransport` implementations.
36+
37+
**Benefit:** Eliminates all `isLocalGame` branching. Opens the door for replay playback and test harness transports.
38+
39+
**Files:** `src/client/main.ts`, new `src/client/game/transport.ts`
40+
41+
**Details:** See REFACTORING.md Priority 2.
42+
43+
### 2c. Command dispatch
44+
Unify ~30 action-handler methods into a single `dispatch(cmd: GameCommand)` bottleneck. The existing `KeyboardAction` discriminated union maps almost directly to `GameCommand`.
45+
46+
**Benefit:** One place for logging, guard conditions, and input routing. Keyboard, UI, and input handler all produce the same command type.
47+
48+
**Files:** `src/client/main.ts`, `src/client/game/keyboard.ts`
49+
50+
**Details:** See REFACTORING.md Priority 3.
51+
52+
### 2d. Typed UI event bus
53+
Replace `UIManager`'s ~15 nullable callback properties with a single typed `UIEvent` union and emitter. Events feed into the dispatch function from 2c.
54+
55+
**Benefit:** Makes the relationship between UI events and game actions visible and greppable.
56+
57+
**Files:** `src/client/ui/ui.ts`, `src/client/main.ts`
58+
59+
**Details:** See REFACTORING.md Priority 5.
60+
61+
### 2e. Async AI turn loop
62+
Replace the recursive callback chain in `processAIPhases` with an explicit async loop. Animation callbacks resolve promises instead of recursing.
63+
64+
**Benefit:** AI turn becomes readable as a sequence, not a callback graph.
65+
66+
**Files:** `src/client/main.ts`, `src/client/game/ai-flow.ts`
67+
68+
**Details:** See REFACTORING.md Priority 7.
69+
70+
### 2f. Serialisation codec
71+
Create `shared/codec.ts` with explicit serialise/deserialise functions for `GameState`. Add a round-trip test to catch new `Map`/`Set` fields.
72+
73+
**Benefit:** Prevents a class of bugs when adding new collection fields to game state.
74+
75+
**Files:** new `src/shared/codec.ts`
76+
77+
**Details:** See REFACTORING.md Priority 8.
2278

2379
## P3 — Test Coverage
2480

25-
### Improve branch coverage on decomposed engine modules
26-
`engine-combat.ts` (70.5% branches) has coverage gaps. Add tests for edge cases in combat phase validation.
81+
### 3a. Improve branch coverage on engine/combat.ts
82+
Currently 88.39% branches. Add tests for edge cases in combat phase validation (anti-nuke fire, split-fire edge cases, dreadnaught-when-disabled).
83+
84+
**Files:** `src/shared/engine/combat.ts`, `src/shared/engine/combat.test.ts`
85+
86+
### 3b. Improve AI test coverage
87+
`ai.ts` is at 62.66% statements, 58.61% branches, 54.05% functions. Significant gaps in ordnance AI, combat target selection, and fleet-building decisions.
88+
89+
**Files:** `src/shared/ai.ts`, `src/shared/ai.test.ts`
90+
91+
### 3c. Improve victory.ts branch coverage
92+
Currently 85.25% branches. Gaps around escape-edge detection, moral victory conditions, and checkpoint race completion.
93+
94+
**Files:** `src/shared/engine/victory.ts`, `src/shared/engine/victory.test.ts`
95+
96+
### 3d. Add movement.ts edge case tests
97+
Currently 77% branches. Gaps around weak gravity consecutive rules, off-map elimination, and takeoff mechanics.
98+
99+
**Files:** `src/shared/movement.ts`, `src/shared/movement.test.ts`
100+
101+
### 3e. Add protocol validation tests
102+
`server/protocol.ts` is at 46.77% branches. Add tests for malformed payloads, edge cases in fleet-ready validation, and ordnance launch validation.
103+
104+
**Files:** `src/server/protocol.ts`, `src/server/protocol.test.ts`
105+
106+
## Suggested Order of Work
107+
108+
The P2 items build on each other. Suggested sequencing:
109+
1. **20** (Adopt utility helpers) — low-risk sweep that improves readability across the board
110+
2. **2a** (PlanningState) — removes the tightest coupling, minimal disruption
111+
2. **2b** (Transport) — eliminates isLocalGame branching, big main.ts shrink
112+
3. **2c** (Command dispatch) — unifies all input routing
113+
4. **2d** (UI event bus) — feeds naturally into 2c's dispatch
114+
5. **2e** (Async AI) — standalone, can be done anytime
115+
6. **2f** (Codec) — standalone, prevents future bugs
116+
117+
P3 items are independent of each other and of P2. They can be interleaved freely.
27118

28119
## Done
29120

30-
- ~~Decompose game-engine.ts~~ — Extracted into `engine-util.ts`, `engine-victory.ts`, `engine-ordnance.ts`, `engine-combat.ts` with backward-compatible re-exports (681 lines, down from 1957)
121+
- ~~Decompose game-engine.ts~~ — Extracted into `engine/util.ts`, `engine/victory.ts`, `engine/ordnance.ts`, `engine/combat.ts` with backward-compatible re-exports (681 lines, down from 1957)
31122
- ~~Add map-data.test.ts~~ — 23 tests covering map builder, body gravity, base placement, scenarios
32123
- ~~Add processEmplacement tests~~ — 10 tests covering emplacement validation and success paths
33124
- ~~Add constants validation tests~~ — 15 tests covering ship stats sanity, ordnance mass, combat/cost scaling
34-
- ~~Shrink renderer.ts~~ — Extracted `renderer-draw.ts`, `renderer-effects.ts`, `renderer-scene.ts`, `renderer-overlay.ts` (1,771 → 1,011 lines)
125+
- ~~Shrink renderer.ts~~ — Extracted `renderer/draw.ts`, `renderer/effects.ts`, `renderer/scene.ts`, `renderer/overlay.ts` (1,771 → 1,011 lines)
35126
- ~~Shrink ui.ts and input.ts~~ — Already under 1,000 lines (661 and 313 respectively)
127+
- ~~Reorganise into folders~~ — Flat prefixed filenames replaced with `game/`, `renderer/`, `ui/`, `engine/`, `game-do/` subfolders

0 commit comments

Comments
 (0)