Docs: record the zoom box as TASK 52 and fix the task-numbering drift (Unit: zoom docs)
The zoom feature shipped without a task record while its index rows carried the "TASK 51" label — which belongs to the webcam background effects (Remove + Blur). For an honest catalogue and handoff: - TASKS/task-52-zoom-box.md: feature provenance (creator-requested), the three 2026-10-08 corrections (loupe -> anchored capture over the full composite drawn last -> never show the dim shading), shapes, implementation map, tests, DONE. - TASKS.md: row 52 added (shipped); row 51 reworded — unblocked now that the zoom build shipped. - TASK 51 -> TASK 52 in Models/index.md, ViewModels/index.md, and the two code comments that pointed at the zoom as "TASK 51". - HANDOFF.md: pre-push readiness notes (5 commits ahead, push-safe).
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# TASK 52 — Zoom box (anchored 2× magnifier)
|
||||
|
||||
**Status:** ✅ Done — shipped 2026-10-08 (three creator corrections during the build).
|
||||
|
||||
## What it is
|
||||
Right-clicking the live preview parks a movable **2× magnifier box** that shows a
|
||||
**live, always-on magnified view of a FIXED capture region** — the box/2 window centred
|
||||
on the click. The captured area is whatever was under the click; it stays the same no
|
||||
matter where the box is dragged.
|
||||
|
||||
## Creator rulings (order received, 2026-10-08)
|
||||
1. **Not a loupe.** The click fixes the capture; **moving the box never changes its
|
||||
content**. First cut shipped `4b3d82f` as a box-following loupe — reworked in
|
||||
`6bff21b` to anchored `CaptureX/Y` (drag = `UpdateZoomMove` moves box only).
|
||||
2. **Content = every layer.** The box magnifies the **fully-composited frame**
|
||||
(backdrop + every element incl. webcam), drawn **LAST, on top of everything**
|
||||
(layer n+1) — `SceneCompositor` skips the active `ZoomSceneElement` in every layer
|
||||
loop and `BlitZoom`s it at the end via `Services/Compositor/ZoomMagnifier`.
|
||||
3. **Never show shading.** The dim rectangles around the box must never appear inside
|
||||
it — the `DimRects` overlay is a sibling of `CanvasGrid`, never a descendant, so the
|
||||
zoom box's `VisualBrush` can't pick it up (`948dd08`).
|
||||
4. **Rectangle = 4:3** ("more of a 640×480 aspect ratio"); Circle square, Phone 9:16.
|
||||
|
||||
## Shapes (master 1920×1080; max box 0.7·frame)
|
||||
| Shape | Box | Notes |
|
||||
|---|---|---|
|
||||
| Circle | square, min(maxW,maxH) | round clip |
|
||||
| VerticalRectangle (Phone) | 9:16 | h = 0.7·1080 |
|
||||
| HorizontalRectangle (Tablet, default) | **4:3** | w = h·4/3 |
|
||||
|
||||
Box and capture are each centred on the click and clamped independently.
|
||||
|
||||
## Implementation
|
||||
- `ViewModels/MainViewModel.Zoom.cs` — activate/move/dismiss + dims; transient
|
||||
`ZoomSceneElement` healed/mirrored (`HealZoomLayers`/`EnsureZoomLayer`, z-index 1, never persisted).
|
||||
- `Services/Compositor/ZoomMagnifier.cs` — pure 2× bilinear over an already-composited
|
||||
opaque buffer (temp snapshot via `ArrayPool`, optional round clip).
|
||||
- `Models/ZoomSceneElement.cs` / `Models/ZoomState.cs` — box rect + `CaptureX/Y`.
|
||||
- `Controls/PreviewPane.xaml(.cs)` — `ZoomBox` (sibling above `CanvasGrid`, brushes the
|
||||
whole composed preview at the fixed capture, 2×) + `DimRectsLayer` (sibling above the
|
||||
content, below the box) + `UpdateZoomBox`.
|
||||
- Output crop always equals the tier — the box is never the crop source.
|
||||
|
||||
## Tests
|
||||
`ZoomMagnifierTests` (money proof: box over blue shows green capture at 2× incl. an extra
|
||||
red "layer"; round-clip) + `ZoomBoxInteractionTests` (aspects, capture anchor centred on the
|
||||
click, move-moves-only-the-box, corner clamp, dims-layer-structure invariant).
|
||||
Full suite 406/406 on a clean run at `948dd08`.
|
||||
Reference in New Issue
Block a user