Update ARCHITECTURE.md and CLAUDE.md for new module structure
Documents render.rs, editor.rs, and glyph_picker.rs; updates the module structure diagram and main.rs section to reflect the refactored layout. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+57
-23
@@ -24,11 +24,14 @@ This document records the architectural decisions made so far and the reasoning
|
||||
|
||||
```
|
||||
src/
|
||||
main.rs — app entry point, rendering, input
|
||||
game.rs — core data types and game logic
|
||||
map_file.rs — TOML deserialization, Board loader
|
||||
main.rs — App, AppMode, frame loop (input → menu → panels → board → dialogs)
|
||||
game.rs — core data types and game logic
|
||||
map_file.rs — TOML deserialization, Board loader
|
||||
render.rs — cell-size constants, draw_glyph/draw_board, board_origin, pos_to_cell
|
||||
editor.rs — EditorTab, EditorState, show_editor_panel
|
||||
glyph_picker.rs — floating Glyph picker dialog; decoupled (open, glyph) interface
|
||||
maps/
|
||||
start.toml — the starting map (loaded at launch)
|
||||
start.toml — the starting map (loaded at launch)
|
||||
```
|
||||
|
||||
### `game.rs` — core types
|
||||
@@ -86,36 +89,67 @@ eframe requires `NativeOptions` (including window size) to be set before calling
|
||||
|
||||
---
|
||||
|
||||
### `main.rs` — app + rendering
|
||||
### `main.rs` — app + frame loop
|
||||
|
||||
`App` holds a `GameState`, an `AppMode` (`Play` | `Edit`), and an `EditorState`. `EditorState` carries:
|
||||
- `selected: Archetype` — the archetype class to stamp
|
||||
- `glyph: Glyph` — the visual to stamp (independent of the archetype's default; resets to `archetype.default_glyph()` when the archetype selection changes)
|
||||
- `glyph_picker_open: bool` — whether the glyph picker dialog is visible
|
||||
- `tab: EditorTab` (`Palette` | `Board` | `World`) — which side-panel tab is active
|
||||
|
||||
The `update` method:
|
||||
`App` holds a `GameState`, an `AppMode` (`Play` | `Edit`), and an `EditorState`. The `update` method phases:
|
||||
|
||||
1. Reads arrow key input and calls `GameState::try_move` — **Play mode only**
|
||||
2. Draws the menu bar with a File menu and a Play/Edit mode toggle
|
||||
3. In Edit mode: draws a resizable right-side panel (default 200 px) with a Palette/Board/World tab bar — declared before `CentralPanel` so egui allocates its space first
|
||||
4. Draws the board and player (see viewport sections below)
|
||||
5. In Edit mode: renders the glyph picker `egui::Window` if open — board-palette of unique glyphs, fg/bg `color_edit_button_srgba`, and a 16×6 ASCII character grid
|
||||
3. In Edit mode: calls `editor::show_editor_panel` — declared before `CentralPanel` so egui allocates its space first
|
||||
4. Draws the board and player via `render::draw_board` (see viewport sections below)
|
||||
5. In Edit mode: calls `glyph_picker::show` if `editor.glyph_picker_open`
|
||||
|
||||
**Viewport — Play mode (`board_origin`):**
|
||||
The `board_origin(available, board_w, board_h, player)` function computes the pixel position of cell (0,0). If the board fits along an axis, it is centered. If it overflows, the viewport is centered on the player and clamped so no empty space appears at the board edges. No scroll bars.
|
||||
**Viewport — Play mode:**
|
||||
`render::board_origin(available, board_w, board_h, player)` computes the pixel position of cell (0,0). If the board fits along an axis it is centered; if it overflows the viewport is centered on the player and clamped so no empty space appears at the board edges. No scroll bars.
|
||||
|
||||
**Viewport — Edit mode (`ScrollArea`):**
|
||||
The board is wrapped in `egui::ScrollArea::new([true, true])` which shows scroll bars when the board overflows the viewport. Content is allocated at exact board size; `rect.min` from `allocate_exact_size` serves as the origin.
|
||||
|
||||
**Cell rendering constants:** `CELL_W = 14.0`, `CELL_H = 20.0` pixels. Window uses fixed default size (`DEFAULT_WINDOW_W = 840`, `DEFAULT_WINDOW_H = 524`) and a small fixed minimum — map size no longer drives window dimensions.
|
||||
|
||||
**Click-to-cell math:** `rel = click_pos - origin; cell_x = (rel.x / CELL_W).floor() as i32`. Negative `rel` values stay negative and are caught by a `>= 0` guard. This mirrors the rendering math exactly so clicks land on the correct cell.
|
||||
**Viewport — Edit mode:**
|
||||
The board is wrapped in `egui::ScrollArea::new([true, true])`, which shows scroll bars when the board overflows the viewport. Content is allocated at exact board size; `rect.min` from `allocate_exact_size` serves as the origin passed to `render::draw_board`.
|
||||
|
||||
**Stamp action:** `*board.get_mut(cx, cy) = (self.editor.glyph, self.editor.selected)` — the custom glyph and selected archetype are written together. The glyph can differ from the archetype's `default_glyph()` if the user has customized it.
|
||||
|
||||
---
|
||||
|
||||
### `render.rs` — constants and drawing primitives
|
||||
|
||||
All pixel-level rendering knowledge lives here. No dependency on `EditorState` or `App`.
|
||||
|
||||
**Constants:** `CELL_W = 14.0`, `CELL_H = 20.0` pixels per cell. Window sizing constants (`DEFAULT_WINDOW_W = 840`, `DEFAULT_WINDOW_H = 524`, `MIN_WINDOW_W/H`) are defined here so they stay co-located with the cell measurements they derive from.
|
||||
|
||||
**`draw_glyph(painter, origin, x, y, glyph)`** — renders one cell as a filled background rect plus a centered monospace character.
|
||||
|
||||
**`draw_board(painter, origin, board)`** — iterates all cells calling `draw_glyph`, then draws the player as an overlay on top.
|
||||
|
||||
**`pos_to_cell(origin, pos) -> (i32, i32)`** — converts a pixel position to cell coordinates using floor division. Returns negative values for clicks above/left of the origin; callers must guard `>= 0`. Mirrors the rendering math so clicks land on the correct cell.
|
||||
|
||||
**`board_origin(available, board_w, board_h, player) -> Pos2`** — computes the pixel origin for Play-mode rendering (centering or player-tracking with edge clamping).
|
||||
|
||||
---
|
||||
|
||||
### `editor.rs` — editor state and side panel
|
||||
|
||||
**`EditorTab`** (`Palette` | `Board` | `World`) — which tab is active in the side panel.
|
||||
|
||||
**`EditorState`** — transient editor state:
|
||||
- `selected: Archetype` — the archetype class to stamp
|
||||
- `glyph: Glyph` — the visual to stamp (independent of the archetype's default; resets to `archetype.default_glyph()` when the archetype selection changes)
|
||||
- `glyph_picker_open: bool` — whether the glyph picker dialog is visible
|
||||
- `tab: EditorTab` — which side-panel tab is active
|
||||
|
||||
**`show_editor_panel(ctx, editor, board)`** — renders the resizable right-side panel (default 200 px). On the Palette tab: a scrollable archetype list (at most 5 rows visible) and a current-glyph preview button that sets `glyph_picker_open = true`. Board and World tabs are placeholders.
|
||||
|
||||
---
|
||||
|
||||
### `glyph_picker.rs` — glyph picker dialog
|
||||
|
||||
**`show(ctx, open, glyph, board_cells)`** — renders a floating `egui::Window`. Takes `open: &mut bool` and `glyph: &mut Glyph` directly, with no dependency on `EditorState`, so it can be invoked from any context that needs glyph selection.
|
||||
|
||||
Three sections:
|
||||
1. **Board palette** — unique glyphs found on the current board, shown as clickable cells. The current glyph is highlighted with a white stroke.
|
||||
2. **Colors** — `color_edit_button_srgba` pickers for `glyph.fg` and `glyph.bg`.
|
||||
3. **Character grid** — 16 × 6 grid of printable ASCII (0x20–0x7E). Clicking a cell updates `glyph.ch`. The current character is highlighted.
|
||||
|
||||
---
|
||||
|
||||
## Map file format
|
||||
|
||||
XPM-inspired (XPM is an old X11 image format that uses a character palette to define pixel colors). A `[palette]` section maps single characters to both a `Glyph` (visual) and an `Element` (behavior). The `[grid] content` is a TOML multi-line string where each character is a palette key.
|
||||
|
||||
Reference in New Issue
Block a user