Files
LlamaCasty/HANDOFF.md
T
gramps 6bff21b234 Zoom: anchor the capture, magnify the full composite, draw on top (Unit: zoom rework per creator correction)
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.
2026-10-08 08:26:29 -07:00

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.cs
  • ViewModels/MainViewModel.Chat.cs
  • Controls/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, UpdateZoomMove never 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. SceneCompositor skips the active ZoomSceneElement in every layer loop and BlitZooms it LAST (layer n+1, on top of everything) via the pure static ZoomMagnifier (2x bilinear, 8.8 fixed-point, temp snapshot via ArrayPool so 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 by HealZoomLayers/EnsureZoomLayer.
  • Output: box composited last via BlitZoom/ZoomMagnifier; output crop = tier (box never the crop).
  • Preview: ZoomBox = sibling above CanvasGrid, samples the full composite at the fixed capture, 2x; circle→ellipse clip, rect/square outline per shape; LeftPanel hides the placeholder row via IsZoomLayer.

Tests

  • Full suite: 404 passed / 2 failed (both = known pre-existing environment flakes, unrelated to zoom): AudioPipelineTests.Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback (audio timing) and LayerReorderPersistenceTests.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.