cmux-next: place a background picture by hand (drag, zoom, reset)
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
BackdropAdjustOverlayover 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).
- It puts
- 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, throughdidChange. - CmuxNextApp unchanged. The op is
cmux.settings.backdrop.image.adjustonBackdropImagesPageProvider, 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 fmtandvp lintare clean, andtschas no settings errors.lint-ios-package-conventions.shis 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-cior 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
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.
CmuxNextAppis unchanged: the ops rideBackdropImagesPageProviderand the overlay lives inCmuxNextDesign.