Files
valw/docs/superpowers/specs/2026-10-03-valw-phase-5b-editor-design.md
T

120 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# valw Phase 5b: editor text, pixelate, numbers, crop (design)
Date: 2026-10-03
Status: approved in brainstorming, pending written-spec review
Builds on: Phase 5a (`valw edit`), `docs/superpowers/specs/2026-10-02-valw-phase-5a-editor-design.md`
## 1. Goal
Finish the editor's tool set from vision 4.5: text, hiding sensitive
parts, numbered markers and crop, with the same guarantee as 5a: the
saved PNG is what the canvas shows.
### Out of scope
- Editing, moving or selecting finished shapes (text included).
- Blur (pixelate only), font choice, text background boxes.
## 2. Decisions
| Question | Decision | Why |
|---|---|---|
| Text editing | Place and type; Enter or a click elsewhere finishes; no re-editing (undo instead) | No selection model yet |
| Text look | Bold, chosen colour, thin dark outline; S/M/L = 16/24/36 px | Readable on any background |
| Font | DejaVu Sans Bold, vendored in `assets/fonts/` with its licence | Turkish glyphs, permissive licence, works without system fonts |
| Text rendering | Glyph outlines from `ab_glyph`, filled and stroked by tiny-skia | One renderer for canvas and export |
| Hiding | Pixelate only | Can't be undone by deblurring |
| Crop | Drag, adjust edges, Enter applies, Esc cancels; an undoable history step | User choice |
## 3. Behaviour
New tools, after the 5a ones in the toolbar: **Text (T), Pixelate (B),
Number (N), Crop (C)**. Ctrl+C stays Copy.
### 3.1 Text
- A click on the image starts a text at that point (its top-left).
Typing inserts characters, Backspace deletes, Shift+Enter starts a new
line, Enter or a press anywhere else finishes it. Esc while typing
drops the text (and does not trigger the close flow).
- An empty text is discarded. While typing, the single-letter tool keys
and Ctrl+Z/Ctrl+Y act on the text box only as text (letters) or not at
all (Ctrl shortcuts are ignored until the text finishes).
- Look: the glyphs filled in the chosen colour over an outline in near
black (`#1c1c1e` at 80 % opacity) of width `size / 8`, so it reads on
light and dark backgrounds. White text gets the same dark outline.
- Size from the width control: S 16, M 24, L 36 px (image pixels); line
height 1.2 × size; kerning from the font.
- A caret (a thin line after the last glyph) blinks while typing; it is
never exported.
### 3.2 Pixelate
- Drag a rectangle (Shift: square). On release the area turns into
blocks of S 8, M 12, L 20 px, aligned to the rectangle's top-left; each
block takes the average colour (alpha included) of what is under it at
that point in the history, so earlier shapes are pixelated too. Edge
blocks are partial.
- A click (under 2 px) is discarded.
### 3.3 Numbers
- A click places a filled circle in the chosen colour with a white bold
number centred in it. Diameter S 24, M 32, L 44 px; the number's size
is 0.55 × diameter.
- The number is 1 + the count of numbers already in the document, so
undo makes the next number reuse the freed one.
### 3.4 Crop
- Drag a rectangle: the outside darkens (50 % black over the canvas), the
inside stays clear, with a 1 px white border. Dragging within 8 screen
px of an edge or corner moves that edge (corners move two); the cursor
shows the resize direction.
- Enter applies it, Esc cancels it (Esc then does not start the close
flow). Switching tools cancels it.
- An applied crop is one history step: undo restores the previous view.
The canvas shows only the cropped area, fitted as in 5a. Shapes keep
their original image coordinates; drawing is clamped to the crop.
- A later crop happens inside the current one.
- Export: everything is drawn on the full image, then the last crop's
rectangle is cut out. "Unsaved" compares the history including crops.
## 4. Structure
| File | Change |
|---|---|
| `assets/fonts/DejaVuSans-Bold.ttf`, `assets/fonts/LICENSE-DejaVu` | The vendored font |
| `src/editor/text.rs` (new) | The embedded font, layout (lines, advances, kerning), glyph outlines → tiny-skia paths, text width/height |
| `src/editor/shape.rs` | `Tool::{Text, Pixelate, Number, Crop}`; `Shape` gains the text payload; geometry for numbers |
| `src/editor/doc.rs` | History entries become `Item::{Shape(Shape), Crop(PixelRect)}`; `crop()`; next number |
| `src/editor/export.rs` | Text, pixelation, number glyphs; final crop |
| `src/editor/view.rs` | Fitting the crop rectangle instead of the whole image |
| `src/editor/mod.rs` | Text input, crop handles and keys, toolbar entries |
Dependency: `ab_glyph`.
## 5. Testing
Unit tests (`cargo nextest`):
- `text`: line breaking on `\n`, width grows with characters, kerning
applied, Turkish letters (`ğüşıöçİ`) have glyphs, an empty string has no
size.
- `export`: text pixels inside the glyph box use the colour; the outline
darkens the edge; pixelation makes each block uniform with the block's
average; a pixelate after a red line pixelates the line; a number draws
a filled circle with white in its centre; a crop sets the output size
and offset.
- `doc`: numbers count only `Number` shapes and follow undo; crops are
undoable and nest; dirty includes crops.
- `view`: fitting a crop rectangle; screen ↔ image round trip with a
crop.
- `mod`: the crop edge hit-test (edges, corners, inside, outside).
Manual checks go to the Phase 5b section of `docs/test-checklist.md`.
## 6. Definition of done
`cargo clippy -- -D warnings`, `cargo fmt --check`, `cargo nextest run`
and `nix flake check` pass; the checklist section is written.