Enhance README with updated instructions for world generation and menu navigation; implement world capacity management in the API with new configuration options; improve client interface with a full-screen menu and world list display; add theme toggle functionality and refine styling for better user experience.

This commit is contained in:
Leonid Pershin
2026-08-16 18:48:54 +03:00
parent 312d6bc58a
commit ee077a3bb9
16 changed files with 566 additions and 120 deletions
+11 -3
View File
@@ -31,7 +31,8 @@ dotnet run --project src/TheLivingWorld.AppHost
```
Aspire starts the API, runs `npm install` for the client, launches the Vite dev server, and prints a dashboard
URL. Open the `web` endpoint from the dashboard, enter coordinates, and press **Generate world**.
URL. Open the `web` endpoint from the dashboard: the main menu lists existing worlds and lets you create a new
one. Enter coordinates and press **Generate world**, then open a ready world to explore the map.
The default coordinates are Robert Lee, Texas (`31.8966010, -100.4858591`) — a small town that generates in a
few seconds.
@@ -102,8 +103,8 @@ them without reworking the data model.
| Endpoint | Purpose |
| --- | --- |
| `POST /api/worlds` | Start generating a world. Returns immediately with `status: "pending"` |
| `GET /api/worlds` | List worlds, with live status for anything still generating |
| `POST /api/worlds` | Start generating a world. Returns immediately with `status: "pending"`; `409` when the slot budget is full |
| `GET /api/worlds` | `{ worlds, maxConcurrentWorlds }` — list plus the server slot budget, with live status for anything still generating |
| `GET /api/worlds/{id}` | Status of one world |
| `GET /api/worlds/{id}/map` | Metadata plus the chunk index |
| `GET /api/worlds/{id}/chunks/{x}/{y}` | One chunk of geometry |
@@ -111,6 +112,8 @@ them without reworking the data model.
Generation takes tens of seconds — mostly waiting on Overpass — so `POST` returns straight away and the client
polls for status. Only one generation runs at a time, to stay a good citizen on the shared Overpass mirrors.
The number of worlds that may exist at once is capped by `WorldStorage:MaxConcurrentWorlds` (today that means
folders on disk; later the same budget will limit concurrent simulation).
Geometry travels as flat `[x0, y0, x1, y1, …]` arrays of world metres, which is exactly what PixiJS
`Graphics.poly()` accepts, so the client never reshapes it. Responses are compressed; chunk files are written
@@ -118,6 +121,10 @@ in wire format and streamed straight from disk.
## The client
The app opens on a full-screen main menu: a list of worlds with a slot counter, the create form, and theme
controls. Opening a ready world switches to the map screen (back button returns to the menu). PixiJS is
initialised on first open and kept alive across visits.
`MapView` owns one scaled container holding the layer stack from `layers.ts`, plus a screen-space layer for
place names above it. `Camera` is the only place the Y flip lives; everything else thinks in map coordinates.
@@ -161,6 +168,7 @@ usual dissolve instead of a special case. The page chrome follows via a `data-th
`src/TheLivingWorld.Api/appsettings.json`:
- `WorldStorage:RootDirectory` — where generated worlds go (default `data/worlds`)
- `WorldStorage:MaxConcurrentWorlds` — how many worlds may exist at once (default `8`)
- `Osm:Endpoints` — Overpass mirrors, tried in order
- `Osm:CacheDirectory` — raw Overpass responses (default `data/osm-cache`)
- `Osm:QueryTimeoutSeconds` / `Osm:RequestTimeoutSeconds` — server-side and client-side budgets