| @@ -3,19 +3,22 @@ |
| 3 |
3 |
DF/RimWorld-style colony sim, Rust + Bevy 0.20 (newer than training data — check `docs/bevy/` before guessing APIs). |
| 4 |
4 |
|
| 5 |
5 |
## User rules |
|
6 |
+- Code is `cargo fmt`ed; run it before committing. |
| 6 |
7 |
- Commit after each logical chunk; short commit msgs. |
| 7 |
8 |
- Minimal code comments. "Why" explanations go into a test asserting the behaviour, comment lives in the test. |
| 8 |
9 |
- Track work in `tasks.md` (done + planned). |
| 9 |
10 |
- This file: dense notes for Claude, not user facing. |
| 10 |
11 |
|
| 11 |
12 |
## Layout |
| 12 |
|
-- `src/main.rs` app wiring: DefaultPlugins (nearest sampling, canvas `#bevy`, fit_canvas_to_parent), inserts `WorldMap`, adds plugins. |
| 13 |
|
-- `src/world.rs` `Terrain` enum (index = tileset layer, `ALL` order matters), `WorldMap` resource (row-major, (0,0)=bottom-left, y up), `TILE_SIZE`=16 world units, `hash2` deterministic int hash, `static_world()` handmade 192x128 map (placeholder until procgen). |
| 14 |
|
-- `src/tilemap.rs` renders map as `TilemapChunk`s (bevy::sprite_render) of `CHUNK_SIZE`=64; chunk transform = chunk center (TilemapChunk is centered on its transform). Tile (x,y) world center = (pos+0.5)*TILE_SIZE, so map spans [0, size*TILE_SIZE]. Tileset is generated in code (no assets): stacked 16x16 layers -> `reinterpret_stacked_2d_as_array`. Per-tile tint via `TileData.color`. |
|
13 |
+- `src/main.rs` app wiring: DefaultPlugins (nearest sampling, canvas `#bevy`, fit_canvas_to_parent), adds plugins. |
|
14 |
+- `src/world.rs` `Terrain` enum (index = tileset layer, `ALL` order matters), `WorldMap` resource (row-major, (0,0)=bottom-left, y up), `TILE_SIZE`=16 world units, `hash2` deterministic int hash. |
|
15 |
+- `src/noise.rs` seeded 2D gradient (Perlin-style, quintic fade) noise + `fbm` (octave i uses seed+i). Range [-1,1]. |
|
16 |
+- `src/worldgen.rs` `WorldGenPlugin` inserts `WorldSeed` + `WorldMap` (256x256) at build time and writes `WorldGenerated` message at Startup; R → seed+1, regenerate, write message. `generate(size, seed)`: elevation fbm → deep/shallow/sand/stone by **quantile** thresholds (fixed terrain shares per seed), fertility fbm top 20% → soil. `largest_region` (4-conn flood of walkable), `spawn_tiles(map, n)` = BFS from largest-region tile nearest map center. Everything reacting to a new world runs `.run_if(on_message::<WorldGenerated>)`: tilemap refresh, colonist respawn, camera recenter, selection clear. |
|
17 |
+- `src/tilemap.rs` renders map as `TilemapChunk`s (bevy::sprite_render) of `CHUNK_SIZE`=64; chunk transform = chunk center (TilemapChunk is centered on its transform). Tile (x,y) world center = (pos+0.5)*TILE_SIZE, so map spans [0, size*TILE_SIZE]. Tileset is generated in code (no assets): stacked 16x16 layers -> `reinterpret_stacked_2d_as_array`. Per-tile tint via `TileData.color`. Chunks spawned once at Startup (`Chunk{origin}`); world changes overwrite `TilemapChunkTileData` in place (bevy's `update_tilemap_chunk_indices` re-uploads via change detection). |
| 15 |
18 |
- `src/camera.rs` `CameraController` on Camera2d: WASD/arrows pan (shift = fast, speed scaled by ortho scale), middle/right drag pan (from cursor delta, not AccumulatedMouseMotion — that doesn't fire for web), scroll zoom toward cursor (`zoom_towards`), camera center clamped to world rect. |
| 16 |
19 |
- `src/selection.rs` `Cursor` resource (screen/world/tile) and `Selection` enum (None/Tile/Colonist(Entity)). PostUpdate after `TransformSystems::Propagate` (fresh camera GlobalTransform). LMB: pick nearest colonist within `PICK_RADIUS` of cursor world pos, else tile, off-map clears; Esc clears. RMB click (press/release within `CLICK_SLOP_PX`, else it was a drag-pan) writes `MoveOrder` for selected colonist. Gizmos: hover rect, selected rect / colonist circle + remaining path linestrip. Top-left UI text (PAUSED, hover, selection). Tests use headless `App` + `ButtonInput`/`Cursor` resources, `Messages<MoveOrder>::drain`. |
| 17 |
20 |
- `src/pathfinding.rs` `find_path(map, start, goal) -> Option<Vec<UVec2>>` A*, 8-dir, no corner cutting, cost = (10|14) * `Terrain::move_cost` of entered tile (100 = normal, None = impassable), octile heuristic. Path excludes start, includes goal; start==goal → empty. |
| 18 |
|
-- `src/colonist.rs` `Colonist{name}` requires `TilePos` (last reached tile), `Path(VecDeque)`, `Wander(Timer)`. Update chain: `handle_move_orders` (`repath` keeps tile being entered at front), `wander` (idle + timer → random goal within radius), `follow_path` (speed / terrain cost, `step_towards`). Space toggles `Time<Virtual>` pause; sim systems use `Res<Time>` (virtual), camera uses `Time<Real>` so it works while paused. Rendered as Mesh2d circles z=1. |
|
21 |
+- `src/colonist.rs` `Colonist{name}` (spawned/respawned on `WorldGenerated` at `spawn_tiles`) requires `TilePos` (last reached tile), `Path(VecDeque)`, `Wander(Timer)`. Update chain: `handle_move_orders` (`repath` keeps tile being entered at front), `wander` (idle + timer → random goal within radius), `follow_path` (speed / terrain cost, `step_towards`). Space toggles `Time<Virtual>` pause; sim systems use `Res<Time>` (virtual), camera uses `Time<Real>` so it works while paused. Rendered as Mesh2d circles z=1. |
| 19 |
22 |
- `src/rng.rs` `SimRng` SplitMix64 resource, seeded (deterministic sim; no `rand` dep). |
| 20 |
23 |
|
| 21 |
24 |
## Gotchas |
| @@ -27,6 +30,7 @@ DF/RimWorld-style colony sim, Rust + Bevy 0.20 (newer than training data — che |
| 27 |
30 |
- Native: `cargo run`. Tests: `cargo test`. |
| 28 |
31 |
- Web: `./scripts/build-web.sh [profile]` (default `wasm-release`, ~3.5 min cold) → `target/web/`. Needs wasm-bindgen-cli matching Cargo.lock `wasm-bindgen` version (currently 0.2.129, installed in ~/.cargo/bin). |
| 29 |
32 |
- Browser verification: `.claude/launch.json` config `web` (python http.server :8080 serving target/web) → `preview_start name=web`, then screenshot/scroll in built-in browser. Synthetic JS pointer events are ignored by winit; real drags only via computer tool left_click_drag (left button) — temporarily bind Left to test drag code. computer tool `right_click` works for RMB clicks. Pause (Space) before clicking moving colonists. |
|
33 |
+- Browser pane screenshots can lag 1-2s behind the canvas (verified: rAF gaps ≤51ms while screenshot still showed old frame). Wait ≥3s after an action, or cross-check via hover text before concluding a render bug. |
| 30 |
34 |
- Bevy logs in browser console; check for ERROR after load. Console log persists across reloads in the pane — count "Creating new window" lines to tell which load an error belongs to. |
| 31 |
35 |
|
| 32 |
36 |
## Docs |