remagec498905
Document M3 grid and thumbnail decisions in CLAUDE.md
+30 −5
1 file changed
- M CLAUDE.md +30 −5
| @@ -178,17 +178,39 @@ The directory listing continues in the background; only the first image is await | |||
| 178 | 178 | - Writes are atomic (tmp + rename) with mode 0600, and failures go in `fail/remage/`. | |
| 179 | 179 | - `-p` disables writing. Because the cache is shared with file managers, thumbnails are often | |
| 180 | 180 | already there. | |
| 181 | + | - URIs are escaped exactly as GLib's `g_filename_to_uri` escapes them (`!$&'()*+,;=:@` stay | |
| 182 | + | literal, hex is uppercase), or the names won't match other tools' entries. A bare path in | |
| 183 | + | `Thumb::URI` (ffmpegthumbnailer writes those) also counts as valid. | |
| 184 | + | - A `fail/remage/` entry is trusted only if its `Software` is this remage version, so formats a | |
| 185 | + | newer version can decode aren't hidden forever. | |
| 186 | + | - Images no bigger than the bucket aren't written: re-decoding them costs about as much. | |
| 181 | 187 | - **Fast paths:** JPEG uses a DCT-scaled decode (`jpeg-decoder` `Decoder::scale`). RAW uses the | |
| 182 | − | embedded preview. Then `fast_image_resize` finishes the job. | |
| 183 | − | - **Generation and storage:** visible thumbnails are generated first. On the GPU they live in atlas | |
| 184 | − | pages with LRU slot eviction. | |
| 188 | + | embedded preview. Then `fast_image_resize` finishes the job (Lanczos, premultiplied alpha). | |
| 189 | + | - **Generation and storage:** | |
| 190 | + | - Visible thumbnails are P2. A page above and two pages below are P3. Requests that scroll out of | |
| 191 | + | that range are cancelled (`Pool::cancel`). | |
| 192 | + | - On the GPU, thumbnails live in 2048² atlas pages at 1:1 pixels, each with a 1 px clear border. | |
| 193 | + | The least recently drawn thumbnail outside the prefetch range is evicted first; if every one is | |
| 194 | + | in range, the atlas grows a page. A new grid size or scale factor rebuilds the atlas. | |
| 195 | + | - Thumbnails fade in over 150 ms. A thumbnail that fails drops the file from the queue (counted in | |
| 196 | + | `[SKIPPED n]`), as in image mode. | |
| 197 | + | - **Cursor:** the grid cursor *is* the queue's current image, so `n`/`p`/`gg`/`G` move it too. The | |
| 198 | + | full image decodes only once the cursor has rested 250 ms (`GRID_REST`). That way `<CR>` opens it | |
| 199 | + | at once without decoding everything the cursor passes over. | |
| 185 | 200 | - **Navigation:** `hjkl`, `gg`/`G`/`[count]G`, `<C-d>`/`<C-u>`, `<C-f>`/`<C-b>` and `0`/`$`. | |
| 186 | − | Scrolling animates smoothly, and `+`/`-` steps through `grid.sizes`. | |
| 201 | + | Scrolling animates smoothly, and `+`/`-` steps through `grid.sizes`. The wheel scrolls by rows, | |
| 202 | + | pixel-exact on touchpads. | |
| 203 | + | - **Visual mode:** `v` anchors a range and movement extends it. `m` (`mark on`) marks it and returns | |
| 204 | + | to the grid; `mark` toggles, unmarking a range that is all marked. `v` or `<Esc>` leaves. The range | |
| 205 | + | sits on `surface_raised`, and the bar shows `[VISUAL n]`. | |
| 187 | 206 | ||
| 188 | 207 | ### Marks | |
| 189 | 208 | - `m` toggles a mark, `M` inverts all marks and `u` unmarks everything. | |
| 190 | 209 | - `N`/`P` jump to the next/previous marked image. | |
| 191 | 210 | - Marks are the default target of user commands, and `-o` prints them on exit. | |
| 211 | + | - Marks are kept by path, so sorting and reversing keep them. | |
| 212 | + | - In the status bar, an accent dot plus the count shows the marks. The dot is filled when the | |
| 213 | + | current image is marked and a ring when it isn't. | |
| 192 | 214 | ||
| 193 | 215 | ### Input | |
| 194 | 216 | - **Key notation** follows vim: `n`, `G`, `<C-x>`, `<S-Tab>`, `<Space>`, `<BS>`, `<Esc>`, `<CR>`, | |
| @@ -462,7 +484,10 @@ Each milestone should end with a usable binary. | |||
| 462 | 484 | - **Decoder tests** run against `tests/fixtures/`: dimensions and pixels for each format, EXIF | |
| 463 | 485 | orientations 1–8, ICC-tagged images and animated frame counts. | |
| 464 | 486 | - **Visual checks without a display:** `REMAGE_SNAPSHOT=/tmp/x.png remage …` renders each settled | |
| 465 | − | frame offscreen to a PNG as well. Use it to check the UI when the screen is locked or remote. | |
| 487 | + | frame offscreen to a PNG as well. Use it to check the UI when the screen is locked or remote. In | |
| 488 | + | the grid, a frame counts as settled once every visible thumbnail is in the atlas. Point | |
| 489 | + | `XDG_CACHE_HOME` at a scratch directory to test cold thumbnail generation without touching the | |
| 490 | + | real cache. | |
| 466 | 491 | - **Before every commit:** `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings` and | |
| 467 | 492 | `cargo test`. | |
| 468 | 493 | - **Manual smoke test:** run `cargo run --release -- /mnt/media/pix` and check that: | |