Files
Damon Pidhajecky f25b246b61 Add add-multiplayer skill + maze-tanks example (#20)
* Add add-multiplayer skill (PartyKit backend)

New user-invocable skill that adds real-time or turn-based multiplayer to
existing browser games via PartyKit (Cloudflare Durable Objects). Follows
the additive-edit pattern from scaffold-gateables and the integration-flow
pattern from monetize-game.

Single-player gameplay is preserved when the server is unreachable —
NetworkManager catches all connection errors and emits network:disconnected
without throwing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add maze-tanks example to dogfood the add-multiplayer skill

Built via the /make-game pipeline + /add-multiplayer end to end —
4-player Phaser tanks-in-a-maze with PartyKit realtime sync (20Hz),
shooter-authoritative bullets, broadcast deaths, and design-pixel
wire format that's PX-independent across clients with different
window sizes/DPRs. Live-players-only (no NPC bots).

Live deploy verified at maze-tanks-multiplayer.dpid.partykit.dev.

STEP*-DONE.md files capture ~14 actionable findings from running
both pipelines as a real user would. Notable ones: clerk auth flow
is broken in 2026 (use --provider github), wire format must be
PX-independent, local-human deaths must broadcast regardless of
killer, round-end consensus needs human-only counting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Apply add-multiplayer skill fixes from maze-tanks dogfood findings

Addresses 9 of the 10 findings surfaced while building examples/maze-tanks.
The 10th (RECONNECT_*BACKOFF_MS naming) was a non-issue — the skill files
are internally consistent; the inconsistency was introduced by a per-game
override in the dogfood example.

Changes by file:

- SKILL.md: Step 6 now requires `--provider github` for partykit login
  (default `clerk` flow hangs on retired dashboard.partykit.io). New
  troubleshooting entries for the clerk hang and the welcome race.

- deploy.md: Step 2 rewritten around GitHub device-code OAuth. New
  troubleshooting entries for clerk hang, partykit npm-audit transitive
  vulns (don't `audit fix --force`), and parent .env inheritance by
  partykit dev.

- partykit-server.md: `compatibilityDate` bumped to 2026-01-15 with a
  policy note about keeping it within ~6 months. `src/types.ts` marked
  REQUIRED (the realtime/turn-based templates import from it).

- architecture.md: documents that the wire schema is open (games may add
  fields like `rotation`); requires positions broadcast in design pixels
  for PX-independence; constructor-ordering footgun for `gameState.multiplayer`
  reset(); detect Constants umbrella vs per-block export shape before
  patching.

- client-integration.md: `NetworkManager._connect` guards `import.meta`
  for non-Vite contexts; reset() block uses `if (this.multiplayer)`
  guard; new "Welcome-race gotcha" section with idempotent seed-then-
  subscribe pattern; comment in NetworkManager imports about adapting
  to umbrella vs per-block Constants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove implementation logs; clean up README and package.json

The 6 STEP*-DONE.md files were build-session implementation logs from
the agentic pipeline that produced this example. Their useful findings
have already been folded into the skill docs (architecture.md,
client-integration.md, deploy.md, partykit-server.md, SKILL.md). The
maze layout, code changes, and bug fixes are all visible in the source
and git history.

- Delete STEP{1,1.5,2,3}-DONE.md, STEP-MULTIPLAYER-DONE.md, STEP-MP-GLUE-DONE.md
- Update README.md header tagline + remove the build-journal section
- Update package.json description

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add maze-tanks to the examples list in CLAUDE.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address coderabbit major findings on add-multiplayer

8 fixes for issues flagged in CodeRabbit's review pass:

1. server.ts: UTF-8 byte-length check via TextEncoder so multibyte
   chars don't slip past MAX_MESSAGE_BYTES (was using JS string .length).
   Also persist the server-stamped state in `peers` so late joiners
   see the same `ts` as everyone else.
2. NetworkManager.js: clear room-switch race by deferring the new
   connect to _onSocketClosed via `pendingRoomId`. Old behavior raced
   the previous socket's async close, misclassifying it as an error
   and triggering a duplicate reconnect on top of the new room.
3. NetworkManager.js: emit network:disconnected when client.connect()
   throws synchronously — the single-player fallback was relying on
   socket callbacks that never fire in that path.
4. MazeSystem.js: handle zero-distance overlap in resolveCircle().
   When dx == dy == 0, the previous code yielded NaN normals and
   left the entity embedded in the wall.
5. GameScene.js: extract the TANK_DIED / ROUND_ENDED HUD listeners to
   stable refs and unregister them on Phaser SHUTDOWN. Previous inline
   lambdas leaked across scene restarts.
6. Bullet.js: cross-client unique IDs (shooterId:timestamp:seq)
   instead of `b${seq++}` which collided across tabs.
7. RemotePlayerRegistry.js: validate playerId is a non-empty string
   before mutating the remotePlayers map (defends against malformed
   network messages, including __proto__-style attacks).
8. EventBus.js: add SPAWN_ASSIGNMENTS_CHANGED to the catalog (it was
   being emitted as a string literal, breaking the no-magic-events
   convention).

Skill docs updated to match (architecture.md PX scaling for remote
positions, client-integration.md room-switch handoff, partykit-server.md
TextEncoder pattern).

partykit.json compatibility date pinned to 2024-09-25 (a stable
PartyKit-published date; previous 2025-01-01 wasn't a real release).
tsconfig adds WebWorker lib so TextEncoder + console types resolve.

All changes verified via tsc + node --check.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: rshtirmer <rshtirmer@gmail.com>
2026-04-30 18:11:09 -04:00
..