diff --git a/PROJECT.md b/PROJECT.md index f2943d2..24e2b45 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -2349,6 +2349,35 @@ never an interstitial. An interstitial after death would land exactly in the "on is not), and canvas perf at `RES` 4 — the third place that risk lands, after OPEN 1 and item 2 above. `matchMedia('(pointer: coarse)')` does still work there, so the mobile branches are fine. +7. **MULTIPLAYER: 1v1 zombie tennis (decided worth pursuing, 2026-08-12).** Tennis is one of the + friendliest genres in existence for netcode, and this codebase is unusually ready for it — record + the decision and the architecture so neither is re-derived: + - **The sync unit is THE SHOT, not world state.** One ball, one legal hitter at a time + (`ball.lastHit` already enforces alternation), ~one interaction per second, and each flight's + ~1 s swallows 100-150 ms of latency before the opponent needs the data. Each client is + authoritative for its OWN contacts (your swing window is judged on your phone — lag never eats + your tap); a dumb relay forwards shot events (~9 numbers: launch pos/vel/gravity/quality) and + point results. No rollback, no shared physics contention. + - **What already exists toward it**: the sim is deterministic-driven (the suite plays the real + modules headless on seeded randomness), `update()` steps fixed dt, ball state is one small + object, `beats.js` is where `startNetMatch()` would live under the court-ownership contract, + and the whole serve/swing/volley system tuned for the zombie match IS the netplay input model. + - **Zero-dep server**: python stdlib has no WebSocket, but RFC6455 handshake + framing is ~120 + lines of stdlib and `server.py` is already the one process holding state. Rooms = a 4-letter + friend code in a dict. No accounts, no matchmaking service. + - **The honest cost is the last 20%**: phone radios (screens lock, apps background, networks + switch — reconnect-and-resume is the bulk of the real work), cross-continent mush, and + hitter-authoritative trust (a plausibility check server-side is enough for friend codes; do + not build ranked-stranger anti-cheat). Prototype = a few focused sessions; robust = weeks of + paper cuts. + - **STEP ONE IS THE GHOST MATCH, not the socket.** Record a run's shot timings + placements + (tiny data), serve it over plain HTTP from the existing server, play against the recording — + racing-game ghost logic. Zero realtime infrastructure, feels close to a duel, and half the + netcode (shot serialization, replay determinism) falls out of it as a byproduct. + - **The hook that makes it ours**: score-is-the-body applied to BOTH players — every point you + lose, YOUR sprite decays a wound stage, so the loser of a long match is a shambling one-armed + wreck by match point. Losing IS zombification. Nobody else's tennis game does that. + **Expectations, so nobody is surprised:** with no marketing, 20-100 units in year one is the honest central estimate (~$40-210 net, i.e. under Apple's fee at the low end). The monetization model is worth maybe $200 either way; the video channel is worth ~100x that. Ship paid because it is cheap and