Browser co-op kitchen game: FastAPI + native WebSockets, server-authoritative 20 Hz simulation, in-memory anonymous lobbies, data-driven YAML levels, Canvas 2D vanilla ES-module client with locally authored SVG art and no external CDNs. .agents/PLAN.md records the LOCKED decisions; .agents/user_stories/ holds the 12 flow contracts; .agents/phases/todo/ breaks them into 14 sequential, test-gated phases (71 task files), each leaving the app launchable and the suite green. LLM-Generated: true
91 lines
3.6 KiB
Markdown
91 lines
3.6 KiB
Markdown
# Undercooked
|
||
|
||
A cooperative, **in-browser**, Overcooked-style kitchen game: 1–4 players share one
|
||
kitchen over WebSockets, cook orders against the clock, and climb a campaign of
|
||
levels that get progressively harder. Lobbies are **anonymous** — no accounts, no
|
||
email, no password: you create a room, share the 5-character code, play.
|
||
|
||
> Working title. "Overcooked" is a trademark of Ghost Town Games/Studio MDG; this
|
||
> project is an independent homage with its own art, code, and content.
|
||
|
||
## Status
|
||
|
||
Roadmap authored, implementation pending. This repository currently contains the
|
||
project scaffold and the `.agents/` phased-execution plan. Execute phases with the
|
||
`phased-execution` skill (`auto-phase.sh`), starting at
|
||
`.agents/phases/todo/01_runnable_service_scaffold/`.
|
||
|
||
## Quickstart (development)
|
||
|
||
Requires [`uv`](https://docs.astral.sh/uv/), Python ≥ 3.12, and `podman`/`docker`
|
||
for container builds. **There is no database** — all live game state is in memory.
|
||
|
||
```bash
|
||
uv sync --extra dev
|
||
uv run undercooked # http://127.0.0.1:8000
|
||
uv run undercooked --reload # dev reload
|
||
uv run undercooked-levels validate # check every level file loads and is solvable
|
||
```
|
||
|
||
Run the checks:
|
||
|
||
```bash
|
||
uv run ruff check .
|
||
uv run pyright
|
||
uv run pytest -m "not e2e" # unit + integration
|
||
uv run playwright install chromium # once, before the first e2e run
|
||
uv run pytest -m e2e # browser suites (app must be running)
|
||
bash .agents/validate.sh # the full pipeline gate
|
||
```
|
||
|
||
## Container
|
||
|
||
```bash
|
||
podman build -t undercooked -f Containerfile .
|
||
podman run --rm -p 8000:8000 undercooked
|
||
# or
|
||
podman compose up -d
|
||
```
|
||
|
||
## Configuration
|
||
|
||
All settings come from the environment (a local `.env` is loaded automatically;
|
||
never commit it — see `.env.example`).
|
||
|
||
| Variable | Default | Meaning |
|
||
|---|---|---|
|
||
| `UNDERCOOKED_HOST` | `127.0.0.1` | Bind address |
|
||
| `UNDERCOOKED_PORT` | `8000` | Bind port |
|
||
| `UNDERCOOKED_TICK_HZ` | `20` | Server simulation rate |
|
||
| `UNDERCOOKED_SNAPSHOT_HZ` | `20` | Snapshot broadcast rate to players |
|
||
| `UNDERCOOKED_MAX_PLAYERS` | `4` | Players per room |
|
||
| `UNDERCOOKED_MAX_ROOMS` | `200` | Concurrent rooms before new rooms are refused |
|
||
| `UNDERCOOKED_LEVELS_DIR` | `levels/` | Directory of level YAML files |
|
||
| `UNDERCOOKED_LOBBY_IDLE_TIMEOUT_S` | `900` | Close empty/idle lobbies |
|
||
| `UNDERCOOKED_GUEST_IDLE_TIMEOUT_S` | `45` | Drop a disconnected player's seat after this |
|
||
| `UNDERCOOKED_MAX_MESSAGE_BYTES` | `4096` | Hard cap on inbound WS frame size |
|
||
| `UNDERCOOKED_MAX_INPUTS_PER_S` | `40` | Per-connection inbound message rate limit |
|
||
| `UNDERCOOKED_SIM_LATENCY_MS` | `0` | Injected server-side downlink latency (netcode tests) |
|
||
| `DEBUGPY` | `0` | `1` = open a debugpy listener on `DEBUGPY_PORT` at startup |
|
||
| `DEBUGPY_PORT` | `5678` | debugpy listen port |
|
||
|
||
## Layout
|
||
|
||
```
|
||
src/undercooked/ server: FastAPI app, rooms, WebSocket protocol, simulation
|
||
levels/ data-driven level definitions (YAML) + recipes
|
||
app/static/ browser client: ES modules, Canvas 2D renderer, own SVG art
|
||
tests/ unit/, server/, integration/, sim/, e2e/ (one Playwright suite per story)
|
||
docs/PROTOCOL.md wire protocol contract (versioned)
|
||
.agents/ PLAN.md, user_stories/, phases/ — the phased-execution plan
|
||
```
|
||
|
||
**No external CDNs.** Every byte of JS, CSS, font, and image is served by this app
|
||
from `app/static/`. A test enforces it.
|
||
|
||
## Contributing
|
||
|
||
Read [AGENTS.md](AGENTS.md) first: it points at `.agents/PLAN.md` (LOCKED decisions)
|
||
and the phase protocol. Code changes land by executing phase task files, not by
|
||
editing ad hoc.
|