Add kiln-tui: a terminal player for kiln boards
New `kiln-tui` crate (ratatui 0.30 / crossterm) that plays a board from a .toml map named on the command line, letting the player walk around with the arrow keys or hjkl. It depends only on kiln-core — the engine needed zero changes, confirming it is genuinely UI-agnostic. - Text rendering: each Glyph.tile index is reinterpreted as a character via a CP437->Unicode table (cp437.rs); fg/bg map to ratatui Color::Rgb truecolor. - render.rs BoardWidget: per-axis viewport that centers a small board and scrolls a large one to keep the player visible. - term.rs TerminalCaps: detects truecolor and Kitty keyboard-protocol support, enabling the protocol when present (held-key repeat, modifier-only keys); shows a rainbow "truecolor" badge in the bottom border. - Input loop acts on Press and Repeat (continuous held-key movement) and ignores Release. Workspace: removed kiln-egui from members (files left untouched). Updated CLAUDE.md and ARCHITECTURE.md to document the workspace split and kiln-tui. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+44
-11
@@ -12,7 +12,9 @@ This document records the architectural decisions made so far and the reasoning
|
||||
|
||||
| Concern | Choice | Reason |
|
||||
|---------|--------|--------|
|
||||
| GUI/windowing | eframe 0.33 / egui 0.33 | Pure Rust, retained-mode, works on desktop and (eventually) WASM |
|
||||
| Engine core | `kiln-core` crate | UI-agnostic game types + map I/O; the one crate every front-end depends on |
|
||||
| Terminal front-end | `kiln-tui` — ratatui 0.30 / crossterm | Pure Rust TUI **player**; renders boards as colored text |
|
||||
| Desktop front-end | `kiln-egui` — eframe / egui 0.33 | Pure Rust retained-mode GUI player + editor. **Currently not a workspace member** (see Module structure) |
|
||||
| Scripting | Rhai 1.x | Pure Rust, sandboxed, WASM-compatible; designed for embedding |
|
||||
| Map format | TOML + serde | Human-readable, good Rust tooling, standard in the ecosystem |
|
||||
|
||||
@@ -22,22 +24,27 @@ This document records the architectural decisions made so far and the reasoning
|
||||
|
||||
## Module structure
|
||||
|
||||
Cargo **workspace**; root `members = ["kiln-core", "kiln-tui"]`. `kiln-egui` stays in the tree but was removed from the workspace and is not built at the root.
|
||||
|
||||
```
|
||||
src/
|
||||
main.rs — App, AppMode, frame loop (input → menu → panels → board → dialogs)
|
||||
kiln-core/src/ — the engine (UI-agnostic)
|
||||
game.rs — core data types and game logic
|
||||
map_file.rs — TOML deserialization, Board loader
|
||||
render.rs — drawing primitives; cell size comes from BitmapFont
|
||||
font.rs — BitmapFont, tile UV mapping, placeholder font
|
||||
font_dialog.rs — floating font-picker dialog (path, tile dims, preview, apply)
|
||||
editor.rs — EditorTab, EditorState, show_editor_panel
|
||||
glyph_picker.rs — floating Glyph picker dialog; decoupled (open, glyph, font) interface
|
||||
map_file.rs — TOML deserialization, Board load/save
|
||||
kiln-tui/src/ — terminal player (no editor)
|
||||
main.rs — CLI arg + play loop; TerminalCaps detection; Kitty flags
|
||||
render.rs — BoardWidget: draws the board into a ratatui buffer as text
|
||||
cp437.rs — CP437 → Unicode table; renders tile indices as characters
|
||||
term.rs — TerminalCaps detection + Kitty keyboard-protocol setup
|
||||
kiln-egui/src/ — eframe/egui player + editor (NOT a workspace member)
|
||||
main.rs, render.rs, font.rs, font_dialog.rs, editor.rs, glyph_picker.rs
|
||||
maps/
|
||||
start.toml — the starting map (loaded at launch)
|
||||
start.toml — example map; play via `cargo run -p kiln-tui -- maps/start.toml`
|
||||
assets/
|
||||
vga-font-8x16.png — default CP437 bitmap font (256×128 px, 32 cols × 8 rows, 8×16 tiles)
|
||||
vga-font-8x16.png — default CP437 bitmap font (256×128 px, 8×16 tiles); used by kiln-egui
|
||||
```
|
||||
|
||||
The per-module deep-dives below are labeled by file. `game.rs`/`map_file.rs` are **kiln-core**; the kiln-tui player has its own section; `font.rs`, `font_dialog.rs`, and the egui `main.rs`/`render.rs`/`editor.rs`/`glyph_picker.rs` are **kiln-egui** (retained as design notes for when the GUI is revived).
|
||||
|
||||
### `game.rs` — core types
|
||||
|
||||
The types here are the runtime representation of a game world. They are deliberately free of any file-loading or rendering concerns.
|
||||
@@ -87,6 +94,30 @@ Currently a thin wrapper around `Board` that provides game-logic methods (`try_m
|
||||
|
||||
---
|
||||
|
||||
### kiln-tui — terminal player
|
||||
|
||||
`kiln-tui` is a **play-only** front-end (no editor yet): it takes a map-file path on the command line, loads a `Board` via `kiln_core::map_file::load`, and lets the player walk around with the arrow keys (or `hjkl`). It depends only on `kiln-core`, `ratatui`/`crossterm`, and the `color` crate — none of the egui stack. This is the proof that `kiln-core` is genuinely UI-agnostic: the engine needed **zero changes** to add a second front-end.
|
||||
|
||||
**Text rendering instead of bitmap tiles.**
|
||||
A terminal can't blit a bitmap font, so kiln-tui reinterprets each `Glyph.tile` index as a *character*. The default kiln font is CP437, where the tile index equals the code point, so `cp437::tile_to_char` maps indices through a 256-entry CP437→Unicode table (graphic glyphs for 0x00–0x1F, box-drawing for 0xB0–0xDF, ASCII in between). The `[font]` map section is still parsed and stored on `Board`, but kiln-tui ignores the image path and uses the tile indices directly. `Glyph.fg`/`bg` (`Rgba8`) map to `ratatui::style::Color::Rgb` — full 24-bit truecolor, alpha dropped (256-color terminals approximate it).
|
||||
|
||||
**`render.rs` — `BoardWidget`.**
|
||||
A `ratatui::widgets::Widget` that draws the board into the frame buffer. The `axis(board_len, view, player) -> (offset, pad, count)` helper resolves each axis independently: a board smaller than the viewport is **centered** with screen padding; a larger one **scrolls** to keep the player visible, clamped so no empty margin shows past the board edge. Per cell, glyph priority is player > object > grid floor.
|
||||
|
||||
**`term.rs` — capability detection + Kitty protocol.**
|
||||
`TerminalCaps { keyboard_enhancement, truecolor }` is detected once at startup: `keyboard_enhancement` via crossterm's `supports_keyboard_enhancement()` (a real query/response with the terminal), `truecolor` from `$COLORTERM`. When keyboard enhancement is supported, kiln-tui pushes the Kitty keyboard-protocol flags (`DISAMBIGUATE_ESCAPE_CODES | REPORT_EVENT_TYPES | REPORT_ALTERNATE_KEYS | REPORT_ALL_KEYS_AS_ESCAPE_CODES`) after `ratatui::init()` and pops them before `restore()`. This unlocks richer input — modifier-only keypresses, key release/repeat events, unambiguous Ctrl combos — which the engine intends to hand to scripts so they can choose bindings the terminal actually supports.
|
||||
|
||||
**Input loop.**
|
||||
Because `REPORT_EVENT_TYPES` makes the terminal emit Release (and Repeat) events, the loop acts on `Press` **and** `Repeat` — so holding a key moves the player continuously at the terminal's own repeat cadence — and skips `Release`, which would otherwise fire a second, spurious move per keypress. In legacy terminals no Repeat events arrive, so held-key movement falls back to terminal auto-repeat; same behavior, no special-casing.
|
||||
|
||||
**Capability badge.**
|
||||
`TerminalCaps::summary_line()` renders a one-line badge in the bottom border. When truecolor is available it shows off by drawing the word "truecolor" with each letter a different rainbow color (`hue_to_rgb`, a full-saturation HSV→RGB helper); otherwise it shows a plain "256-color", followed by the input descriptor ("enhanced input" / "legacy input") in the default color.
|
||||
|
||||
**Why a capability struct, not a terminal name.**
|
||||
Scripts should branch on *what works* (truecolor, keyboard enhancement), not on a brittle terminal brand string that is often unset over SSH or inside tmux. `TerminalCaps` deliberately carries no program-identity field.
|
||||
|
||||
---
|
||||
|
||||
### `font.rs` — bitmap font
|
||||
|
||||
**`BitmapFont`** wraps an egui `TextureHandle` plus tile geometry (`tile_w`, `tile_h`, `img_w`, `img_h`). The texture is preprocessed at load time: the top-left pixel of the source PNG becomes the "background" sentinel — those pixels are stored as `TRANSPARENT`, all others as opaque `WHITE`. This lets egui's image tinting do all the colorization work at render time:
|
||||
@@ -289,6 +320,8 @@ A direct mapping from palette character → `(Glyph, Archetype)` means the map f
|
||||
|
||||
**Map save** — the editor can paint cells but has no way to write changes back to a `.toml` file. Saving will require serializing the `Board` back to `MapFile` format and writing it to disk.
|
||||
|
||||
**Terminal editor** — `kiln-tui` is play-only; it has no editing UI. The editor currently lives only in `kiln-egui`, which is out of the workspace. A future TUI editor (or reviving the egui one) is an open direction.
|
||||
|
||||
---
|
||||
|
||||
## Future considerations
|
||||
|
||||
Reference in New Issue
Block a user