| 1 |
# CLAUDE.md |
| 2 |
|
| 3 |
DF/RimWorld-style colony sim, Rust + Bevy 0.20 (newer than training data — check `docs/bevy/` before guessing APIs). |
| 4 |
|
| 5 |
## User rules |
| 6 |
- Commit after each logical chunk; short commit msgs. |
| 7 |
- Minimal code comments. "Why" explanations go into a test asserting the behaviour, comment lives in the test. |
| 8 |
- Track work in `tasks.md` (done + planned). |
| 9 |
- This file: dense notes for Claude, not user facing. |
| 10 |
|
| 11 |
## 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`. |
| 15 |
- `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 |
- `src/selection.rs` `HoveredTile`/`SelectedTile` resources (Option<UVec2>). PostUpdate after `TransformSystems::Propagate` (fresh camera GlobalTransform): cursor→world→`map.tile_at`; LMB selects hovered (off-map clears), Esc clears; gizmo `rect_2d` outlines (white hover, yellow selected); top-left UI text via `describe_tile`. Selection logic tested with headless `App` + `ButtonInput` resources. |
| 17 |
|
| 18 |
## Gotchas |
| 19 |
- WebGL2 (wgpu GLES) guesses array texture view dim from layer count: 1→D2, 6→Cube, 6k→CubeArray. Tileset layer count padded via `tileset_layer_count`. Symptom: black screen + "wgpu-hal heuristics assumed ... Cube" errors. |
| 20 |
- `UVec2::div_ceil` doesn't exist in this glam. |
| 21 |
- No `rand` dep yet; use `hash2` for deterministic noise. |
| 22 |
|
| 23 |
## Build / run |
| 24 |
- Native: `cargo run`. Tests: `cargo test`. |
| 25 |
- 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). |
| 26 |
- 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. |
| 27 |
- 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. |
| 28 |
|
| 29 |
## Docs |
| 30 |
- `docs/bevy/examples/` full 0.20 examples (e.g. `2d/tilemap_chunk.rs`, `camera/*`). `docs/bevy/release-content/` migration guides + release notes. |
| 31 |
- Crate sources: `~/.cargo/registry/src/index.crates.io-*/bevy_*-0.20.0/`. |