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).
2.7 KiB
2.7 KiB
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)
- Not a loupe. The click fixes the capture; moving the box never changes its
content. First cut shipped
4b3d82fas a box-following loupe — reworked in6bff21bto anchoredCaptureX/Y(drag =UpdateZoomMovemoves box only). - Content = every layer. The box magnifies the fully-composited frame
(backdrop + every element incl. webcam), drawn LAST, on top of everything
(layer n+1) —
SceneCompositorskips the activeZoomSceneElementin every layer loop andBlitZooms it at the end viaServices/Compositor/ZoomMagnifier. - Never show shading. The dim rectangles around the box must never appear inside
it — the
DimRectsoverlay is a sibling ofCanvasGrid, never a descendant, so the zoom box'sVisualBrushcan't pick it up (948dd08). - 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; transientZoomSceneElementhealed/mirrored (HealZoomLayers/EnsureZoomLayer, z-index 1, never persisted).Services/Compositor/ZoomMagnifier.cs— pure 2× bilinear over an already-composited opaque buffer (temp snapshot viaArrayPool, optional round clip).Models/ZoomSceneElement.cs/Models/ZoomState.cs— box rect +CaptureX/Y.Controls/PreviewPane.xaml(.cs)—ZoomBox(sibling aboveCanvasGrid, 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.