ShippedLarge

Playable core loop in Phaser: Preparation/Raid/Results phases, dungeon scene, HUD with pause/speed, extension registries

Proposed by Jonathan Miller 2 hours agoFunding opened 2 hours agoFunded 2 hours agoShipped 1 hour ago
Acceptance · round 1
Shipped
CINo checks
Automated reviewPass with concerns

A complete, well-structured implementation. A pure TypeScript core (phase machine, fixed-step raid simulation, registries, economy) is cleanly separated from the Phaser scene and DOM HUD, every unit-test category the spec asks for is present and meaningfully asserted, and the README covers running and extending the game. The main gaps are verification ones: no CI ran, the builder's verification notes are truncated, and HUD layout at the required resolutions is not demonstrated. The README/engines claim of Node 20.19 support conflicts with the locked Vitest 5, which requires Node 22.12+, so `npm test` may fail on Node 20.

Acceptance criteria · 10 of 14 met
  • UNCLEAR`npm install && npm run dev` serves the gamepackage.json defines `dev: vite`; index.html loads src/main.ts, which boots Phaser, the DungeonScene and the HUD; not verified by CI.
  • UNCLEAR`npm run build` produces static files that run in current Chrome and Firefox`build: tsc --noEmit && vite build` with `base: './'` and a separate Phaser chunk in vite.config.ts; no build output or CI run to confirm.
  • YESTests: all legal phase transitions, and Start Raid rejected outside Preparation with state unchangedtests/phases.test.ts covers the full cycle, plus Start Raid during Raid and during Results, using snapshot equality and IllegalTransitionError.
  • YESTests: build actions rejected during Raidtests/build-lock.test.ts calls buildRoom, removeRoom, hireMonster and placeTrap during a raid, expects BuildLockedError for each, and checks the snapshot is unchanged.
  • YESTests: new-game starter gold and room count match configphases.test.ts 'starts in Preparation with starter gold and rooms from config' and 'follows config overrides'.
  • YESTests: raid success and failure for given party strengths (deterministic)raid.test.ts runs it.each over strengths including the PATH_DEFENSE boundary, plus a determinism test and a game-level win/lose test.
  • YESTests: gold correct after Results for success and failure, never negativeeconomy.test.ts checks the success reward (+300), the floor(999×0.25) loss, a loop over loss fractions up to 2 keeping gold ≥0, and the zero-gold case.
  • YESTests: cycle counter increments per raidphases.test.ts 'increments the cycle counter once per raid started' runs 4 cycles.
  • YESTests: pause halts simulation ticksraid.test.ts 'pause halts simulation progress' asserts position, elapsedMs and event count do not change across 100 paused updates.
  • YESTests: 2x/4x advance 2×/4× as far as 1x for equal real dtraid.test.ts it.each([2,4]) compares the distance moved and elapsedMs against a 1x baseline.
  • YESTests: a newly registered room type is usable in a dungeon without modifying core modulesregistry.test.ts registers 'lava-pit', uses it as a starter room via config and through buildRoom, and confirms its getDefense hook drives the raid.
  • UNCLEARHUD elements do not overlap or obscure the whole play area at 1280×720 and 1920×1080style.css uses a flex top bar with flex-shrinking progress, a 192px sidebar and a <1400px media query; no screenshots or verification provided.
  • UNCLEAR`tsc --noEmit` passes; lint if configuredtsconfig is strict and includes src, tests and vite.config.ts, and the code looks type-clean on inspection; no lint is configured; no CI run to confirm.
  • YESScope: phase machine, starter dungeon, Phaser scene with pan/zoom, DOM HUD, build lock, real-time raid, Results screen, registries, READMEImplemented across src/core/*, DungeonScene.ts (drag, WASD/arrow pan, wheel zoom clamped to config), Hud.ts (top bar, prep/raid groups, locked sidebar, Results with Continue), src/content/placeholders.ts and the README extension section.
Concerns
  • No CI ran, and the builder summary is cut off at 'Verificatio', so there is no evidence that `npm install`, `npm test`, `tsc --noEmit` or `npm run build` were actually run successfully on this commit.
  • Node version mismatch: package.json `engines` and the README say Node >=20.19, but the locked vitest 5.0.3 declares `node: ^22.12.0 || ^24.0.0 || >=26.0.0`. On Node 20 (which the README says is supported), `npm test` may refuse to run or break, which would fail the `npm test passes` criterion for those backers.
  • HUD non-overlap at 1280×720 and 1920×1080 is plausible from the CSS (flex top bar, a media query hiding hint and subtitle below 1400px, fixed-width sidebar), but no screenshots or checks were provided. It cannot be confirmed from the diff.
  • DungeonScene re-runs `centerCamera()` on every resize, which resets the zoom and discards any pan the player made. This is a minor UX issue.
  • `Game` exposes mutable public fields (`phase`, `gold`, `cycle`, `paused`, `speed`), so callers can bypass the phase machine and build lock by assigning directly. Only the methods enforce the rules; making these fields read-only (or private setters) would harden the state layer.
CI details
No CI checks ran on this commit.

BackersAccepted
1 accept · 0 rebuild · 0 not voted · quorum 1 of 1
MaintainerMerge

Accepted by the backers and merged by the maintainer.

Ballots · 1
AcceptJonathan Miller

Automated review cost $0.35, counted as builder cost.

Motivation

Dungeon Company needs a working, playable core loop (Preparation → Raid → Results) that later features can plug into: rooms, monsters, traps, combat, economy and raids. The attached mockup Dungeon Company_ Preparation and Raid.png shows the target layout for both phases. This ticket delivers the layout and mechanics with placeholder visuals, not the final art.

Decisions (from review round 1)

  • Stack: If the repository is empty, use TypeScript + Vite + Phaser 3. Phaser owns the game loop, scenes, camera pan/zoom, input, sprites/tweens and timing. The HUD and management panels use DOM/CSS overlaid on the canvas. If the repo already has an established stack, keep it and adapt. (This replaces the original A1 "plain Canvas 2D, no engine" assumption.)
  • Raid: A real-time walking simulation, not an instant result. The party visibly moves room to room along the path from entrance to core. Combat is a simple numeric strength check per room.
  • Failure: There is no game over. A failed defense costs gold, the Results screen shows the loss, and the player returns to Preparation.
  • Persistence: In memory only. Save/load is a separate planned feature.
  • Tests: Vitest, or the project's existing runner.

Architecture assumptions

  • Pure logic layer. Game logic lives in plain TypeScript modules with no Phaser or DOM imports, so Vitest can test it headlessly in Node. This covers state, the phase machine, the raid simulation, registries and economy.
  • Fixed-tick simulation. The raid simulation exposes tick(dtMs). Phaser's update loop drives it with dt * speed while not paused. The renderer only reads simulation state.
  • Single config file. All tunables live in one file, e.g. src/config.ts: starter gold, starter rooms, failure gold-loss fraction, base reward, party base strength, party move speed, and zoom min/max.
  • Placeholder rules (assumptions, tunable in config):
    • Party strength = base + cycle × increment.
    • Each room subtracts the strength contributed by its RoomType and any assigned monster or trap via hooks.
    • Success means party strength reaches 0 before entering the core room.
    • On success, gold is awarded through the economy reward hook.
    • On failure, the player loses floor(gold × lossFraction). Gold never goes below 0.

Scope

  1. Game state & phase machine.
    • Phases cycle Preparation → Raid → Results → Preparation.
    • Illegal transitions throw a typed error, or return a rejected result, and leave state unchanged.
    • The cycle counter increments when a raid starts.
  2. New game. Creates a starter dungeon of at least 3 connected placeholder rooms, from entrance to core, plus starter gold. Both come from config.
  3. Play area (Phaser scene).
    • Rooms render as labeled placeholder shapes or sprites, with connections between them. A top-down or simple isometric look is acceptable.
    • Pan by mouse drag or arrow keys/WASD.
    • Zoom by mouse wheel, clamped to the config min/max.
  4. HUD (DOM, layout per mockup).
    • Top bar: game title, a phase banner ("Preparation" or "Raid"), gold, and raid/cycle number.
    • Top bar, Preparation only: a "Start Raid" button, enabled only in Preparation.
    • Top bar, Raid only: a raid progress bar (party progress through the path, in %), the adventurer count, a pause/resume button, and speed buttons 1x/2x/4x. Speed buttons show the active state and are active only during Raid.
    • Left sidebar: category buttons Rooms, Traps, Monsters, Decorations, Utilities and Remove. In this ticket they are placeholders: clicking one may open an empty or stub panel, or do nothing. During Raid they show a lock and are disabled.
  5. Build lock. During Raid, all build/hire/configure/remove actions are disabled in the UI and rejected by the state layer, even if called directly.
  6. Raid.
    • The placeholder party (one or more marker sprites) moves visibly room to room.
    • The outcome follows the placeholder rules above.
    • Pause stops simulation progress. The speed setting multiplies simulation time.
  7. Results screen. Shows success or failure, gold earned or lost, and a "Continue" button that returns to Preparation.
  8. Extension points.
    • Provide typed registries/interfaces for RoomType, MonsterType, TrapType, HeroPartyGenerator, and an economy reward hook.
    • Register at least one placeholder implementation of each.
    • Core logic looks these up by id through the registries. It never hard-codes concrete types.
  9. Docs. Add a README section covering how to run, test and build, and how to register a new room, monster or trap.

Acceptance criteria

  • npm install && npm run dev serves the game.
  • npm run build produces static files that run in current Chrome and Firefox with no install.
  • npm test passes, with unit tests covering:
    • all legal phase transitions, and rejection of Start Raid outside Preparation (state unchanged);
    • build actions rejected during Raid;
    • new-game starter gold and room count matching config;
    • raid success and failure for given party strengths (deterministic);
    • gold updated correctly after Results for both success and failure, never negative;
    • cycle counter increments per raid;
    • pause halts simulation ticks (no progress while paused);
    • the speed multiplier scales progress (2x/4x advance 2×/4× as far as 1x for equal real dt);
    • registering a new room type via the registry makes it usable in a dungeon without modifying core modules.
  • HUD elements do not overlap each other or obscure the whole play area at 1280×720 and 1920×1080.
  • tsc --noEmit passes. Lint passes if configured.

Out of scope

  • Final art matching the mockup's illustrated isometric style. Use simple shapes or placeholder sprites only.
  • From the mockup, deferred to later tickets:
    • Room Info panel and Upgrade button
    • gold income rate ("+320/min")
    • "Next raid in" timer
    • per-adventurer health list
    • Active Threats / trap cooldowns panel
    • health bars
  • Deep room, monster and trap catalogs; advanced combat AI; campaign narrative; multiplayer; mobile/touch controls; save/load.
Attachments

No comments yet.