- Python 53.3%
- Vue 31.2%
- TypeScript 12.7%
- Dockerfile 1.9%
- JavaScript 0.4%
- Other 0.5%
| .forgejo/workflows | ||
| backend | ||
| frontend | ||
| .gitignore | ||
| docker-compose.yml | ||
| LICENSE | ||
| README.md | ||
bunker
minimal web edition of bunker.
stack
- api: fastapi
- web: vue 3, tailwind
- ops: docker, nginx (alpine-slim)
run
nginx serves the SPA and proxies /api + /ws to the API container.
docker compose up -d
- web: http://localhost:80
- api: http://localhost:8000
- health: http://localhost:8000/api/health
api
POST /api/create_room → {"room_code":"AX8B7"}
websocket
path: /ws
client:
{"action":"join_room","room_code":"AX8B7","name":"alice"}
{"action":"join_room","room_code":"AX8B7","name":"alice","player_id":"abc12345"}
{"action":"start_game"}
{"action":"reveal_stat","stat_name":"phobia"}
{"action":"leave_room"}
{"action":"kick_player","target_id":"abc12345"}
{"action":"start_vote","target_id":"abc12345"}
{"action":"cast_vote","vote":"yes"}
Optional player_id reconnects the same seat together with the same name.
Without player_id, the server still reconnects to an existing seat when name matches a player who is not in online state (e.g. closed tab → disconnected, or after leave_room → left). If that name is already taken by someone online, join is rejected. kicked names cannot rejoin.
Invite link (SPA): https://host/?room=AX8B7 — the client pre-fills the room code.
stat_name one of:
sex_age, gender, body_type, profession, health, hobby, phobia, large_inventory, backpack, extra_info
player display name = name from join_room (not a dealt card).
reveal adds stat to revealed_stats; server sends per-client room_state_update (others see null until revealed).
server:
{"event":"joined","payload":{"player_id":"…","room_code":"…"}}
{"event":"room_state_update","payload":{…}}
{"event":"error","message":"…"}
data
json lists under backend/data/ (each file must exist and contain a non-empty JSON array).