docs: phase 5b editor design spec
This commit is contained in:
1 parent
f9b70ca35a
commit
2df93f7d6b
1 file changed
+119
@@ -0,0 +1,119 @@
|
||||
# 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.
|
||||
Reference in new issue
Block a user