Creator corrected the "loupe" zoom on 2026-10-08: the click anchors a fixed
capture region (box/2 centred on the click) and the box is a live 2x view of
that region — dragging the box never changes its content; it magnifies the
fully-composited frame (every layer, incl. webcam) and draws LAST (n+1).
Rectangle shape is 4:3 ("more of a 640x480 aspect").
- MainViewModel.Zoom.cs rewritten: ActivateZoom anchors CaptureX/CaptureY
(independently clamped); UpdateZoomMove relocates the box only; the per-frame
BuildZoomFrame/ZoomFrameBuilder path is gone.
- SceneCompositor: skips the active ZoomSceneElement in every layer loop and
BlitZooms it last via the new pure ZoomMagnifier (2x bilinear, temp snapshot
via ArrayPool, round clip).
- Preview: ZoomBox hoisted above CanvasGrid as a sibling; its brush samples the
whole composed preview at the fixed capture (2x).
- Tests: ZoomMagnifierTests (box-over-blue shows green capture at 2x incl. an
extra red "layer" — the loupe/backdrop-only regressions both fail it) +
round-clip; ZoomBoxInteractionTests rewritten (anchored capture, move-doesn't-
change-capture, 4:3/9:16/square). 404 pass, 2 known environment flakes.
4.1 KiB
HANDOFF — 2026-10-08 (zoom rework)
Branch
- main (no feature branch)
Dirty files (NOT mine — the in-flight "pinned chat" work unit; do NOT commit or co-edit)
Models/YouTube.csViewModels/MainViewModel.Chat.csControls/LeftPanel.xaml(pinned-message UI)- Untracked:
Helpers/RelayCommandGeneric.cs
What just happened (2026-10-08, second zoom pass — creator correction)
The zoom box shipped in 4b3d82f was a loupe (box follows its own content, built from the
backdrop only, slotted at z-index 1). The creator corrected it; the model is now:
- Anchored capture, not a loupe. Right-clicking the live preview fixes a capture window —
the box/2 region centred on the click (
CaptureX/Y, clamped to the master) — and parks a movable 2x magnifier box. The box is a live, always-on 2x view of that captured region; dragging the box relocates it,UpdateZoomMovenever touches the capture (creator ruling). - Content = every layer. The zoom pass runs on the already-composited frame (backdrop + all
elements), so the magnified webcam/square/layers all show in the box.
SceneCompositorskips the activeZoomSceneElementin every layer loop andBlitZooms it LAST (layer n+1, on top of everything) via the pure staticZoomMagnifier(2x bilinear, 8.8 fixed-point, temp snapshot viaArrayPoolso a box overlapping its own source never recurses, optional round clip). - Rectangle = 4:3 ("more of a 640x480 aspect ratio"); Circle = square, Phone = 9:16 (kept).
Changes in this pass: new Services/Compositor/ZoomMagnifier.cs; ZoomSceneElement/ZoomState
gained CaptureX/CaptureY; MainViewModel.Zoom.cs rewritten (BuildZoomFrame/ZoomFrameBuilder
and the zoom-as-crop resolver case removed — no per-frame builder/cache anymore);
PreviewPane.xaml: ZoomBox hoisted OUT of OverlayCanvas to be a sibling of CanvasGrid
(renders above everything in the preview); PreviewPane.xaml.cs UpdateZoomBox samples CanvasGrid
(the whole composed preview) at the fixed capture, Stretch=Fill. ZoomFrameBuilderTests.cs deleted
(superseded); new ZoomMagnifierTests.cs (the "box over blue shows green capture, at 2x, all layers"
proof + round-clip); ZoomBoxInteractionTests.cs rewritten (per-shape 4:3/9:16/square + capture
anchor centred on the click + move-moves-only-the-box assertion + corner-clamp).
Zoom feature state
- Models:
ZoomState.cs,ZoomShape.cs(Circle/VerticalRectangle/HorizontalRectangle),ZoomSceneElement.cs. - ViewModel (
MainViewModel.Zoom.cs):ActivateZoom/ToggleZoom/DismissZoom/StartZoomMove/UpdateZoomMove/EndZoomMove+RebuildDimRectsForZoom; transient element healed/mirrored byHealZoomLayers/EnsureZoomLayer. - Output: box composited last via
BlitZoom/ZoomMagnifier; output crop = tier (box never the crop). - Preview:
ZoomBox= sibling aboveCanvasGrid, samples the full composite at the fixed capture, 2x; circle→ellipse clip, rect/square outline per shape;LeftPanelhides the placeholder row viaIsZoomLayer.
Tests
- Full suite: 404 passed / 2 failed (both = known pre-existing environment flakes, unrelated to
zoom):
AudioPipelineTests.Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback(audio timing) andLayerReorderPersistenceTests.RealMouseDrag_OnTheLayerList_PersistsTheReorder(needs interactive desktop). Zoom tests 3/3 green, 0 build warnings.
Known issues / follow-ups
- Background "Use default background" toggle still not working (carried from 2026-10-07):
binding exists (
UseDefaultBackground), VM handler invalidates bake; investigate when time permits. - Preview shows editing chrome (dim rects, selection) inside the zoom box — accepted preview artefact; the output only shows composed content.
Next step
- User runs the app live to eyeball the corrected zoom: right-click preview → anchored capture stays
fixed while the box is dragged; the box shows ALL layers at 2x on top of everything; rectangle box
is 4:3. Then TASK 51 (webcam background Remove + Blur) per
TASKS/task-51-webcam-bg-effects.md, and the background-toggle investigation if still open.