cmux-next: place a background picture by hand (drag, zoom, reset)

Closed
TE
16d ago
+1565-100

Phase 6 of the backgrounds plan (briefs/next-backgrounds-plan.md): place a background picture by hand.

Stacked on manaflow-ai/cmux#21709 and manaflow-ai/cmux#21731. It needs the placement math from the first and the Settings page provider from the second, so this branch is #21731's head with #21709 merged in. Review only the last commit, 93f4995082d. Once both merge, this PR shows only that commit.

What changes

  • Adjust Placement… in Settings > Background. It's offered for a still picture, not for None, Desktop or videos.
    • It puts BackdropAdjustOverlay over the frontmost window that shows a picture, and fades the window's content to 12% so the art shows.
    • Drag moves the picture. Scroll or pinch zooms (1×–4×).
    • Reset goes back to the automatic subject framing from phase 1. Done, Escape or Return ends it and brings the content back.
    • With no window showing a still picture, the page says so (cmux.settings.backdrop.not_adjustable).
  • The placement (BackdropUserPlacement) is the image point at the middle of the visible span, plus a zoom past the cover fit.
    • The art always still covers the window: a placement past an edge slides back.
    • It starts from the framing on screen (userPlacement(from:)), so the first drag doesn't jump.
  • Saved per background id in background-placement.json, next to the Backgrounds folder (BackdropPlacementStore), and written off the main actor. Every window showing that picture follows it live, through didChange.
  • CmuxNextApp unchanged. The op is cmux.settings.backdrop.image.adjust on BackdropImagesPageProvider, and the overlay lives in CmuxNextDesign. There's no catalog entry (WINDOW); a palette and right-click "Adjust Background…" comes with phase 5.

Strings

All 21 locales:

  • backdrop.adjust.hint, backdrop.adjust.reset, backdrop.adjust.done (Design)
  • settingsWindow.backdropPicker.adjust, adjustHelp, notAdjustable (Settings page)

Tests

  • CmuxNextDesignTests/BackdropUserPlacementTests:
    • the person's point sits mid-span, the zoom is respected, an edge slides back to cover, and zoom is clamped
    • converting the automatic framing and back gives the same framing
    • the store saves, reloads and announces changes once
  • CmuxNextAppTests/BackdropAdjustOverlayTests:
    • in a real window, the content fades, zoom and drag move the art and save it for that background, Reset restores the automatic framing, and Done restores the content
    • a window with no picture refuses
  • CmuxNextPagesTests/BackdropImagesPageProviderTests: adjust refuses or places.
  • Web hostCards.test.tsx: the button runs the op, and isn't shown for None. All 129 settings tests pass.

Verification

  • vp fmt and vp lint are clean, and tsc has no settings errors.
  • lint-ios-package-conventions.sh is clean. CmuxNextApp source lines are unchanged.
  • Swift: not built locally (no Mac in this lane), so CI is the first compile. Swift tests need a full-ci or next-batch run, which I've asked the coordinator about.
  • Not dogfooded.

Not in this PR

  • Per-workspace placements. A placement is per picture, so a workspace with its own background gets that picture's placement.
  • Placing videos.
  • The menu and palette entry, which comes with phase 5's catalog change.

WINDOW

None.

Changelog

Added: Place a background picture by hand: drag to move it, scroll or pinch to zoom, and reset to the automatic framing.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Settings > Background now lets you place a still background picture by hand and add your own images from a link. Adjust Placement… fades the window's content (including views added while placing) and overlays a drag-to-move, scroll-or-pinch-to-zoom (1×–4×), reset-to-automatic-framing session; Done, Return, or Escape ends it and restores the content. Arrow keys nudge (Shift nudges further), +/− zoom, and 0 resets.

  • The placement is saved per background id in background-placement.json, followed live by every window showing the picture; it starts from the on-screen framing so the first drag doesn't jump, and removing a picture drops its placement.
  • Bundled art now names its subject box, and the picture zooms, slides, or shrinks so the subject stays clear of the sidebar and a docked agent chat.
  • The overlay opens in the workspace window (brought forward from a separate Settings window), one at a time app-wide; the action only shows for still pictures, and a window with none refuses with a page message.
  • Add from a Link downloads an https image or movie under a size cap and uses it as a picked file; your images get remove, Show in Finder, and a disk-usage tally computed off the main actor. File imports check the bytes decode or play before they are copied in.
  • CmuxNextApp is unchanged: the ops ride BackdropImagesPageProvider and the overlay lives in CmuxNextDesign.