web implmentation for tunisian card game chkobba
# Chkobba Web (4‑player 2v2)
Online Chkobba with a Tunisian café table vibe. Monorepo with a React client, a Socket.IO game server, shared TS types, and Playwright E2E tests.
## Stack
- Client: React + TypeScript + Vite + Tailwind + Zustand
- Realtime: Socket.IO (typed event maps)
- Server: Node.js + Express + Zod validation
- E2E: Playwright (`e2e/`)
## Repo Layout
```
client/
src/
animations/ # useFlightChoreographer, geometry helpers
features/ # game/, room/, ui/ feature components
net/ # socketClient (singleton), useGameNetwork hook
store/ # Zustand slices: connection, room, game, ui, audio
test/ # vitest setup
server/
src/
game/ # rules, scoring
lib/ # validation (Zod), rateLimit, socketHandlers
shared/
events.ts # ServerToClient / ClientToServer typed event maps
types.ts # Card, Player, GameState …
e2e/ # Playwright tests
```
## Architecture
### State (client)
Single Zustand store with 5 typed slices. All components subscribe via fine-grained selectors using `useShallow` to avoid spurious re-renders.
```
useConnection → { status, socketId }
useRoom → { code, seats, settings, phase }
useGame → { table, hands, scores, lastPlay, … }
useSelection → { handCard, tableCards, sum, canPlay }
useAudio → { muted }
```
`GamePhase` state machine: `'idle' → 'lobby' → 'playing' → 'roundEnd' → 'lobby'`
### Network (client)
`socketClient.ts` — typed singleton socket with exponential reconnect backoff.
`useGameNetwork.ts` — binds all socket events to Zustand; handles room resync on reconnect. Exposes: `createRoom`, `join`, `play`, `updateRoomSettings`, `launchGame`, `setProfile`, `replay`, `playSoundboard`, `renameTeam`, `quit`.
### Animations
`useFlightChoreographer` drives card-flight animations entirely from `lastPlay.t` (server timestamp). Single `useLayoutEffect` snapshots DOM rects from the *previous* render before React com …