Skip to content

Commit ca71bf7

Browse files
committed
Extract lobby UI view
1 parent 1960ddc commit ca71bf7

File tree

3 files changed

+56
-43
lines changed

3 files changed

+56
-43
lines changed

docs/ARCHITECTURE.md

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,16 @@ This is the heart of the project. All game rules live in a shared folder, making
4040
|--------|-----|---------|-------------|
4141
| `hex.ts` | 306 | Axial hex math: distance, neighbours, line draw, pixel conversion | **Fully generic** — zero game knowledge |
4242
| `util.ts` | 170 | Functional collection helpers (`sumBy`, `minBy`, `indexBy`, `cond`, etc.) | **Fully generic** — no game knowledge |
43-
| `types.ts` | 358 | All interfaces: `GameState`, `Ship`, `Ordnance`, C2S/S2C messages, scenarios | Game-specific |
43+
| `types.ts` | 364 | All interfaces: `GameState`, `Ship`, `Ordnance`, C2S/S2C messages, scenarios | Game-specific |
4444
| `constants.ts` | 135 | Ship stats, ordnance mass, detection ranges, animation timing | Game-specific |
4545
| `movement.ts` | 435 | Vector movement with gravity, fuel, takeoff/landing, crash detection | Game-specific |
4646
| `combat.ts` | 627 | Gun combat tables, LOS, range/velocity mods, heroism, counterattack | Game-specific |
47-
| `map-data.ts` | 704 | Solar system bodies, gravity rings, bases, 8 scenario definitions | Game-specific |
48-
| `ai.ts` | 981 | Rule-based AI with three difficulty levels | Game-specific |
49-
| `engine/game-engine.ts` | 945 | Pure state machine: game creation, phase orchestration, state filtering | Game-specific |
47+
| `map-data.ts` | 712 | Solar system bodies, gravity rings, bases, 8 scenario definitions | Game-specific |
48+
| `ai.ts` | 860 | Rule-based AI with three difficulty levels | Game-specific |
49+
| `engine/game-engine.ts` | 838 | Pure state machine: game creation, phase orchestration, state filtering | Game-specific |
5050
| `engine/combat.ts` | 537 | Combat phase controller: asteroid hazards, attack validation, base defence | Game-specific |
5151
| `engine/ordnance.ts` | 522 | Ordnance launch/movement/detonation, asteroid hazard queuing | Game-specific |
52-
| `engine/logistics.ts` | 315 | Surrender, fuel/cargo transfers, looting, logistics phase | Game-specific |
52+
| `engine/logistics.ts` | 284 | Surrender, fuel/cargo transfers, looting, logistics phase | Game-specific |
5353
| `engine/victory.ts` | 634 | Victory conditions, turn advancement, reinforcements, fleet conversion | Game-specific |
5454
| `engine/util.ts` | 180 | Game rule helpers: base ownership, escape checks, ordnance capacity | Game-specific |
5555

@@ -118,16 +118,16 @@ The frontend renders the pure hex-grid state into a smooth, continuous graphical
118118

119119
| Directory | Files | LOC | Purpose |
120120
|-----------|-------|-----|---------|
121-
| `client/` (root) | 6 | ~2300 | Entry point (`main.ts` ~1510 LOC), raw input, audio, tutorial, DOM helpers, telemetry |
122-
| `client/game/` | 35 | ~5200 | Game logic: planning, commands, phases, transport, presentation, connection, actions |
123-
| `client/renderer/` | 13 | ~4500 | Canvas rendering: camera, scene, entities, effects, overlays |
124-
| `client/ui/` | 8 | ~1900 | DOM overlays: menu, HUD, ship list, fleet shop, formatters |
121+
| `client/` (root) | 8 | ~2300 | Entry point (`main.ts` ~1040 LOC), raw input, audio, tutorial, DOM helpers, telemetry, viewport, reactive signals |
122+
| `client/game/` | 39 | ~5650 | Game logic: command routing, planning, phases, transport, presentation, connection, actions |
123+
| `client/renderer/` | 13 | ~4600 | Canvas rendering: camera, scene, entities, effects, overlays |
124+
| `client/ui/` | 13 | ~2100 | DOM overlays: menu, HUD, ship list, fleet building, game log, formatters, button bindings, screens |
125125

126126
#### Three-Layer Input Architecture
127127

128128
1. **Raw Input** (`input.ts`): Mouse/touch/keyboard → `InputEvent` (clickHex, hoverHex). No game knowledge.
129129
2. **Game Interpretation** (`game/input-events.ts`): `InputEvent` + phase + state → `GameCommand[]`. Pure function.
130-
3. **Command Dispatch** (`main.ts`): `GameCommand` → local state update or network transmission.
130+
3. **Command Dispatch** (`game/command-router.ts`): `GameCommand` → local state update or network transmission.
131131

132132
#### Client State Machine (`ClientState`)
133133
- `menu``connecting``waitingForOpponent``playing_*``gameOver`
@@ -141,10 +141,12 @@ The frontend renders the pure hex-grid state into a smooth, continuous graphical
141141

142142
#### Key Design Patterns
143143

144-
- **`main.ts`**: The client-side controller. Manages WebSocket connections, local-AI execution, and phase transitions. It orchestrates the Renderer, Input, and UI through a centralized **`ClientContext`** and a single **`dispatch(GameCommand)`** entry point.
144+
- **`main.ts`**: The client-side coordinator. Manages WebSocket connections, local-AI execution, and phase transitions. Orchestrates the Renderer, Input, and UI through a centralized **`ClientContext`**. Commands are dispatched via `dispatchGameCommand()` in `game/command-router.ts`.
145145
- **`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.
146146
- **`input.ts`**: Manages user interaction (panning, zooming, clicking). It translates raw browser events into `InputEvent` objects. Pure `interpretInput()` then maps these to `GameCommand[]`, ensuring the input layer never directly mutates the application state.
147-
- **`game/` / `renderer/` / `ui/` subfolders**: Pure client-side helpers for combat selection, input planning, minimap geometry, phase derivation, formatting, and tooltip/view-model logic.
147+
- **`game/`**: Command routing, action handlers (astrogation/combat/ordnance), phase derivation, transport abstraction, connection management, input interpretation, view-model helpers, and presentation logic.
148+
- **`renderer/`**: Canvas drawing layers (scene, entities, vectors, effects, overlays), camera, minimap, and animation management.
149+
- **`ui/`**: Screen visibility, HUD view building, button bindings, game log, fleet building, ship list, formatters, and layout metrics.
148150
- **`ui/ui.ts`** / **`audio.ts`**: Handles the HTML overlay (menus, HUD) and Web Audio API interactions.
149151
- **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.
150152

@@ -196,12 +198,13 @@ main.ts (GameClient)
196198
├→ renderer/renderer.ts (draw canvas, reads planningState by reference)
197199
├→ input.ts (parse mouse/keyboard → InputEvent)
198200
├→ ui/ui.ts (manage screens, accept UIEvent)
201+
├→ game/command-router.ts (GameCommand → state mutation or network)
199202
├→ game/network.ts, game/messages.ts (handle S2C)
200203
├→ game/transport.ts (choose WebSocket or Local)
201204
├→ game/phase.ts (derive ClientState from GameState)
202205
├→ game/keyboard.ts (KeyboardAction → GameCommand)
203206
├→ game/helpers.ts (derive HUD view models)
204-
├→ game/[combat|burn|ordnance].ts (game-specific UI logic)
207+
├→ game/[combat|burn|ordnance]-actions.ts (phase-specific actions)
205208
├→ game/planning.ts (user input accumulation)
206209
├→ shared/types.ts (GameState, Ship, Ordnance, etc.)
207210
├→ shared/engine/game-engine.ts (createGame, local resolution)
@@ -242,7 +245,7 @@ An analysis of what could be extracted as a reusable hex-grid multiplayer game f
242245

243246
| Component | LOC | Reusability | Notes |
244247
|-----------|-----|-------------|-------|
245-
| `shared/hex.ts` | 289 | **100%** | Zero game knowledge. Axial coords, line draw, pixel conversion. |
248+
| `shared/hex.ts` | 306 | **100%** | Zero game knowledge. Axial coords, line draw, pixel conversion. |
246249
| `shared/util.ts` | 170 | **100%** | Pure FP collection helpers. |
247250
| `renderer/camera.ts` | 96 | **95%** | Pan/zoom/lerp. Only tie: `HEX_SIZE` constant. |
248251
| `client/input.ts` | 234 | **90%** | Mouse/touch/pinch → clickHex/hoverHex. No game knowledge. |
@@ -325,4 +328,4 @@ All three engine safety items are complete:
325328
- **Generic `RuleSet<S, C, E, P>` interface**: Designing a framework from N=1 games is premature abstraction. The current code is readable because it knows what a Ship is.
326329
- **Full package extraction** (`hex-core`, `match-runtime`, `delta-v-rules`): Wait until game #2 exists. Build the framework from two concrete implementations, not one.
327330
- **Serialisation codec**: `GameState` is plain JSON. A codec adds overhead with zero current benefit.
328-
- **UI framework adoption**: The DOM UI layer is ~1900 LOC across 8 files. A framework (Preact, etc.) adds build complexity and migration risk for a layer that works and is small enough to iterate on directly.
331+
- **UI framework adoption**: The DOM UI layer is ~2100 LOC across 13 files. A framework (Preact, etc.) adds build complexity and migration risk for a layer that works and is small enough to iterate on directly.

docs/BACKLOG.md

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,47 @@ The project is in a good place mechanically. The next work
2020
should focus on reducing shell complexity and tightening
2121
authority boundaries rather than rewriting the engine.
2222

23-
### Phase 0. Reliability fixes
23+
### ~~Phase 0. Reliability fixes~~ *(done)*
2424

25-
- Persist authoritative game state before broadcasting it to clients.
26-
- Make intentional client disconnects bypass reconnect logic.
27-
- Keep docs aligned with the current file layout and feature set.
25+
- Persist authoritative game state before broadcasting.
26+
- Intentional client disconnects bypass reconnect logic.
27+
- Docs alignment (ongoing).
2828

29-
### Phase 1. Client shell decomposition
29+
### ~~Phase 1. Client shell decomposition~~ *(done)*
3030

31-
- Split `src/client/main.ts` into a thin coordinator plus focused modules:
32-
command routing, UI event routing, phase flow, and client state storage.
33-
- Keep coordination in the shell; keep decision logic in pure
34-
`derive*` / `resolve*` helpers.
31+
`main.ts` reduced from ~1500 to ~1040 LOC. Extracted modules:
32+
command routing (`game/command-router.ts`), UI event routing
33+
(`game/ui-event-router.ts`), phase flow (`game/phase.ts`,
34+
`game/phase-entry.ts`), phase telemetry
35+
(`game/turn-telemetry.ts`). Coordination stays in the shell;
36+
decision logic in pure `derive*` / `resolve*` helpers.
3537

36-
### Phase 2. UI shell decomposition
38+
### ~~Phase 2. UI shell decomposition~~ *(done)*
3739

38-
- Break `src/client/ui/ui.ts` into focused menu, HUD, fleet,
39-
log, and overlay modules behind the existing `UIManager`
40-
facade.
41-
- Replace repeated button wiring with a small declarative
42-
registry.
40+
`ui.ts` reduced from ~800 to ~590 LOC. Extracted modules:
41+
button bindings (`ui/button-bindings.ts`), game log view
42+
(`ui/game-log-view.ts`), fleet building view
43+
(`ui/fleet-building-view.ts`), ship list view
44+
(`ui/ship-list-view.ts`), overlay view
45+
(`ui/overlay-view.ts`). Declarative button registry replaces
46+
repeated wiring.
4347

44-
### Reactive experiment note
48+
### Reactive signals note
4549

46-
- `src/client/reactive.ts` should stay experimental until it has
47-
owner-scoped cleanup for nested effects, a disposal strategy for
48-
`computed()`, and clearer propagation semantics.
49-
- Current review findings: nested effects leak subscriptions,
50-
`computed()` stays permanently hot, and shared-dependency updates
51-
can emit glitchy intermediate states.
52-
- Do not make it a core UI pattern yet; reconsider after those
53-
lifecycle and scheduling gaps are closed with tests.
50+
`src/client/reactive.ts` is a standalone signals library
51+
(signal, computed, effect, batch, DOM helpers) with 26 tests
52+
including property-based coverage. Known limitations:
53+
54+
- Nested effects created inside an outer effect are not
55+
auto-disposed when the outer re-runs.
56+
- `computed()` has no dispose — its internal effect stays
57+
permanently subscribed.
58+
- Diamond dependencies can emit glitchy intermediate states
59+
outside of `batch()`.
60+
61+
These are acceptable for the current standalone/experimental
62+
scope. Address lifecycle gaps before wiring into core UI
63+
state (PlanningState, HUD).
5464

5565
### Phase 3. Shared model boundaries
5666

@@ -77,9 +87,9 @@ authority boundaries rather than rewriting the engine.
7787

7888
### Delivery order
7989

80-
1. Reliability fixes with tests.
81-
2. `main.ts` coordinator extraction.
82-
3. `ui.ts` view extraction.
90+
1. ~~Reliability fixes.~~
91+
2. ~~`main.ts` coordinator extraction.~~
92+
3. ~~`ui.ts` view extraction.~~
8393
4. Shared type/module split.
8494
5. Rules consolidation.
8595
6. Optional stronger state-model refactors.

docs/CODING_STANDARDS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ Client game modules use two patterns depending on purity (see [dependency inject
241241

242242
- **Managers** use a factory pattern: `createXxx(deps: XxxDeps): XxxManager`. The returned object's methods close over the deps. Examples: `createConnectionManager()`, `createTurnTimerManager()`, `createLocalTransport()`.
243243

244-
`GameClient` in `main.ts` wires deps objects via lazy getters that bind callbacks to live context. The `dispatch()` switch routes commands to the extracted action functions.
244+
`GameClient` in `main.ts` wires deps objects via lazy getters that bind callbacks to live context. `dispatchGameCommand()` in `game/command-router.ts` routes commands to the extracted action functions.
245245

246246
When adding new side-effecting logic, prefer extending an existing `*Deps` interface over adding methods to `GameClient`. Keep pure derivation functions as direct-parameter exports — they don't need deps.
247247

0 commit comments

Comments
 (0)