# COOLRL Lost Cities Web

Browser-only Lost Cities client. The rules engine, observation builder, and PPO
inference all run on the device; there is no application server.

The verified final JAX PPO policy is committed at
`public/models/jax-ppo.onnx` (3.1 MB). Vite copies it to the static build, and
the app resolves the asset relative to the deployed site so it works on GitHub
Pages, GitLab Pages, or a normal web root. Its size and SHA-256 are recorded in
[`public/models/jax-ppo.json`](public/models/jax-ppo.json).

Pushes to `main` build and publish the client through the repository's GitHub
Pages and GitLab Pages workflows. Each workflow supplies the correct base URL
for its host.

## Seeded deals

Every game is dealt from a seed, shown in the menu and kept in the URL as
`?seed=<seed>`. Loading that URL — or typing the seed into the menu — replays
the exact same deal, so a game can be shared, replayed, or reported with a bug.
Seeds are arbitrary text; the deal is derived from a deterministic PRNG in
`src/game/random.ts` and is independent of the Python shuffle bank.

The seed shuffles the deck and nothing else. The policy is deterministic: it
always plays its highest-logit legal action, so the same deal and the same moves
reproduce the same game.

## Hints, undo, and review

`HINT` asks the same policy that drives the rival what it would play in your
seat, and highlights the card, its destination, and the draw source (with the
policy's confidence when the ONNX model is loaded).

Undo and redo work per *action*, not per turn: choosing a card, choosing its
destination, and drawing are separate steps, and each is undone on its own. The
rival's moves are steps too, so a finished game can be stepped through from the
result screen (`REVIEW GAME`) all the way back to the deal. While undone moves
are pending the rival is suspended; `PLAY FROM HERE` drops them and resumes play
from the position on screen.

## Setup

Install and run the checked-in final policy:

```bash
cd web
npm ci
npm run dev
```

Build the same static bundle used by a host:

```bash
npm run build
npm run preview
```

To replace the shipped policy, export a verified Orbax checkpoint from the
repository root. The exporter writes both the ONNX file and its public
metadata manifest:

```bash
uv run --with onnx scripts/export_jax_ppo_onnx.py \
  --checkpoint /path/to/checkpoint \
  --output web/public/models/jax-ppo.onnx
```

The policy tries WebGPU first and falls back to ONNX Runtime WebAssembly. If
the model asset is absent, the UI remains playable using a simple local
heuristic and reports that fallback in the header.

## Checks

```bash
cd web
npm test
npm run build
```

The TypeScript engine follows `src/lost_cities_jax/engine.py` and its 96-action
atomic action space. Cross-runtime fixtures can be regenerated with:

```bash
uv run python scripts/generate_web_parity_fixture.py
```
