Skip to content

feat: add InteractiveActionSource and playable browser game (Slice 17.5) - #80

Open
Jamerrone wants to merge 2 commits into
mainfrom
sandcastle/issue-56-slice-17-5-playable-browser-ga
Open

feat: add InteractiveActionSource and playable browser game (Slice 17.5)#80
Jamerrone wants to merge 2 commits into
mainfrom
sandcastle/issue-56-slice-17-5-playable-browser-ga

Conversation

@Jamerrone

Copy link
Copy Markdown
Owner

Closes #56

Summary

Adds InteractiveActionSource so the tower-defense engine can accept real-time keyboard/mouse input, and wires it into a fully playable browser game at the demos/browser entry point. A new demos/game-data/ directory holds all JSON content (maps, enemies, towers, waves, scenario, upgrades, difficulty) for the "Defend the Pass" scenario. A separate replay viewer entry (demos/browser/replay/) is also added for reviewing recorded game sessions.

Test Plan

  • test/interactive-action-source.test.ts (143 lines) was added, covering the new InteractiveActionSource class.
  • test/browser/browser-demo.test.ts was updated to reflect the revised multi-entry Vite config.
  • Playwright config was updated to match the new MPA layout; both the main game and replay routes are covered.

Jamerrone and others added 2 commits May 22, 2026 13:47
)

Implement the playable browser game entry with full interactive UI alongside
the existing transcript replay debugger, per the Slice 17.5 acceptance criteria.

Key decisions:
- InteractiveActionSource buffers PlayerActions pushed via DOM event handlers and
  drains them at the next BrowserDemoLoop tick boundary; exportTranscript() returns
  the recorded (tickIndex, action) pairs in TranscriptFile-compatible shape.
- Two Vite MPA HTML entries: game at / (index.html + game.ts) and replay debugger
  at /replay (replay/index.html + replay/main.ts). One vite.config.ts handles both.
- demos/game-data/ seeds from a verbatim copy of shared-data/ with the scenario's
  waveTrigger overridden to {"kind":"manual"} so the player controls wave timing.
  shared-data/ and its tests are entirely unaffected.
- Vite plugin (renamed gameDataPlugin) emits both data.json (shared-data) and
  game-data.json (game-data) to dev server and production build; ADR-0021 already
  documented this two-bundle design.
- game.ts implements: menu → scenario card → playing → win/loss overlay state
  machine; Idle/Build/Inspect interaction modes; tower palette with cost/affordability
  and armed-ghost cursor; Inspect panel with attack summary, sell button (refund
  computed from cost + purchased upgrade costs × refundPercent), TargetingStrategy
  dropdown (all 5 built-ins) with tag-priority sub-picker (up/down reorder + add/remove);
  tiered UpgradeTree cards with ○/✓/🔒 badges and locked-state tooltips; send-wave
  button (Send / spawning… / hidden after last wave); export-transcript download;
  3-second failure toast for ActionResult failures.
- Canvas overlays: tile tinting (Build: green/red via free-placement validation;
  Inspect on Guard Tower: per ADR-0011 rally eligibility within rallyPointRange);
  range circles (Build cursor, Inspect selected, hover Tower/Enemy/Guard); ghost
  tower in Build mode; rally overlays when Guard Tower is in Inspect (placement
  radius, engagement zone circles, rally point marker).
- replay/main.ts updates the replay debugger with a source picker: default demo
  transcript or user-supplied .json via file input; both bundles fetched on load;
  scenario id resolved against whichever registry contains it.
- package.json scripts flattened: dev/build/preview map directly to vite;
  *:browser namespacing removed; test:e2e replaces test:browser.
- Headless vitest test (test/interactive-action-source.test.ts): 6 tests covering
  unit push/drain behaviour, transcript export shape, and an end-to-end run that
  places a Tower and sends a Wave against game-data via MaxSpeedClock.

Files changed (12):
  demos/browser/action-source.ts: add InteractiveActionSource
  demos/browser/game.ts: new game entry (menu, game loop, interactive UI)
  demos/browser/index.html: new game HTML (replaces transcript replay at /)
  demos/browser/replay/index.html: replay HTML at /replay
  demos/browser/replay/main.ts: replay entry with file picker + dual-bundle resolve
  demos/game-data/: new content directory (14 JSON files; scenario uses manual waveTrigger)
  vite.config.ts: two-bundle plugin, MPA rollupOptions.input for both entries
  package.json: script flattening (dev/build/preview/demo:cli/test:e2e)
  playwright.config.ts: webServer.command updated to npm run preview
  test/browser/browser-demo.test.ts: navigate to /replay/?headless (replay route)
  test/interactive-action-source.test.ts: 6 new vitest unit + e2e tests

Verification: 0 typecheck errors, kernel-purity clean, 414/414 unit tests pass (+6 new).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove unused AudioRenderer import in game.ts
- Drop redundant `as HTMLElement` casts (palettePanel/inspectPanel are
  already HTMLElement after the non-null assertion)
- Remove unused `registry` parameter from drawInspectOverlay and
  drawHoverOverlay; update call sites in drawOverlays
- Flatten triple-nested if in drawHoverOverlay using optional chaining
- Remove unused buildRegistry and TowersState imports in test file
- Remove dead makeNullRenderer helper that was never called

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slice 17.5: Playable browser game (InteractiveActionSource + game content)

1 participant