FR-DEV-17 — Warn when a crop orphans a mask #10

Closed
opened 2026-09-05 16:09:19 +00:00 by dtourolle · 2 comments
Owner

Where a change to the crop would place existing local work outside the visible frame, say so before the change is committed.

Why

This is the entire counter-argument to cropping early, and the reason the sources are genuinely split on crop-first-versus-crop-last.

Mask geometry is stored in normalised source coordinates, so re-cropping tighter does not destroy the work — it makes it invisible, which is worse, because nothing announces it. A warning turns a silent loss into a decision, and lets DarkRoom keep the crop-early default that the histogram argument supports.

Acceptance

  • Reported at commit, not during the drag — a crop handle passing over a mask mid-gesture is not an event.
  • Names how many layers are affected, and offers to keep the crop anyway. Never blocks it.
  • Reversed by undo along with the crop, as one step.
  • Silent when no layer is affected — no dialog on the common path.

Sequencing

Cheap, but only matters once masks are worth losing. Do it after range masks and mask composition.


Part of the Develop Ergonomics spec (FR-DEV series proposal), 2026-09-05.

Where a change to the crop would place existing local work outside the visible frame, say so **before the change is committed.** ## Why This is the entire counter-argument to cropping early, and the reason the sources are genuinely split on crop-first-versus-crop-last. Mask geometry is stored in normalised source coordinates, so re-cropping tighter does not *destroy* the work — it makes it **invisible**, which is worse, because nothing announces it. A warning turns a silent loss into a decision, and lets DarkRoom keep the crop-early default that the histogram argument supports. ## Acceptance - [ ] Reported at commit, not during the drag — a crop handle passing over a mask mid-gesture is not an event. - [ ] Names how many layers are affected, and offers to keep the crop anyway. **Never blocks it.** - [ ] Reversed by undo along with the crop, as one step. - [ ] Silent when no layer is affected — no dialog on the common path. ## Sequencing Cheap, but only matters once masks are worth losing. Do it after range masks and mask composition. --- Part of the Develop Ergonomics spec (FR-DEV series proposal), 2026-09-05.
dtourolle added the developergonomicsmasksuisize:S labels 2026-09-05 16:09:19 +00:00
Author
Owner

Sequence after #7 and #9 — cheap, but only matters once masks are worth losing.

**Sequence after** #7 and #9 — cheap, but only matters once masks are worth losing.
Author
Owner

Merged to master: 9772785, fc0ea88, c3d1f83. The clause is now in requirements.md as FR-DEV-17, the ID this issue reserved.

  • core/dr-pipeline/src/orphan.rs: hidden_by_crop samples each layer on a 64×64 lattice with the mask shader's geometry, folds parts with their joins (through Join::apply, so intersect counts too) and inversions, maps the samples through crop and turns, and reports a layer when less than 10% of its coverage is left in the frame and it was not already that low. Ranges and region selections are never reported.
  • UI: when a crop drag is let go, or a ratio is picked, a notice at the top of the canvas reads "This crop leaves N mask(s) outside the frame: ", with Undo crop and Keep crop. The notice is tied to the crop's history step, so one undo takes both back.

All four acceptance items are met, with tests: reported on release not during the drag; names the layers and never blocks; undone as one step; silent when nothing is affected. Also checked in the app.

Judgement calls: the 10% threshold (HIDDEN_SHARE), and feather and morphology are left out of the estimate on purpose. The auto-crop after a straighten is not checked; it has no "before" rect and only trims slivers.

Merged to master: 9772785, fc0ea88, c3d1f83. The clause is now in requirements.md as **FR-DEV-17**, the ID this issue reserved. - `core/dr-pipeline/src/orphan.rs`: `hidden_by_crop` samples each layer on a 64×64 lattice with the mask shader's geometry, folds parts with their joins (through `Join::apply`, so intersect counts too) and inversions, maps the samples through crop and turns, and reports a layer when less than 10% of its coverage is left in the frame and it was not already that low. Ranges and region selections are never reported. - UI: when a crop drag is let go, or a ratio is picked, a notice at the top of the canvas reads "This crop leaves N mask(s) outside the frame: <names>", with **Undo crop** and **Keep crop**. The notice is tied to the crop's history step, so one undo takes both back. All four acceptance items are met, with tests: reported on release not during the drag; names the layers and never blocks; undone as one step; silent when nothing is affected. Also checked in the app. Judgement calls: the 10% threshold (`HIDDEN_SHARE`), and feather and morphology are left out of the estimate on purpose. The auto-crop after a straighten is not checked; it has no "before" rect and only trims slivers.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dtourolle/DarkRoom#10