# 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.