cmux-next: collages: arrange several pictures as one background

Closed
TE
10d ago
+10622-5200

Phase 7 of the backgrounds plan: collages, approved by Leo through the coordinator.

Stacked on manaflow-ai/cmux#21743, which carries #21731's Settings page provider. Review only 8afeb67d5ed.

What changes

  • appearance.background takes collage:<id> (BackdropSelection.collage).
    • The id is letters, digits and dashes only (1–64), so it never names another path.
    • The native BackdropSelectionSetting.accepts and the page's validate.ts both take it. A schema sample and a refused sample (collage:../evil) are added, and the base-autofix regenerates the export.
  • Storage: Backgrounds/Collages/<id>.json holds the record (BackdropCollage: name, fill and layers back to front, each with a source, frame, opacity and corner radius). <id>.png is the drawing, which the window shows like any picture.
  • Drawing: BackdropCollages.render draws the fill, then each layer.
    • Each layer is decoded at about the size it's drawn and fills its frame centered.
    • Rounding and opacity are applied, at 3200×2000.
  • Saving: a saved edit gets a new id, and the old files go. That way the image cache, which is keyed by id, never shows an old drawing.
  • Validation:
    • Layers must be still pictures (art, macOS stills or your images), not videos, the desktop or another collage.
    • Layers must sit on the canvas, with finite numbers, opacity from 0 to 1 and corner radius from 0 to 0.5, and there can be at most 12.
    • A collage where nothing can be read is refused rather than saved as a bare fill.
  • Picker: collages are listed as Your collages, right after your images. Each has ✎ to edit and × to remove; the one in use can't be removed, and its hand placement goes with it.
  • Editor (Settings > Background > New Collage…):
    • add pictures from the grid
    • drag to move, and drag the corner handle to resize; edges snap to the canvas's halves and thirds
    • arrow keys nudge (Shift moves further), and Delete removes
    • Bring Forward, Send Backward, Rounded Corners and Remove Picture
    • fill color and name
    • starter layouts: side by side, three columns, mosaic
    • Save draws the collage natively and sets it as the background
  • Ops: cmux.settings.backdrop.image.collage.save | get | delete, on BackdropImagesPageProvider. The page sets appearance.background itself through the normal settings write. CmuxNextApp is unchanged.

Strings

19 page keys and 3 native keys, all in 21 locales.

Tests

  • CmuxNextDesignTests/BackdropCollagesTests:
    • id safety and round trip
    • save draws 3200×2000, reads back and lists
    • an edit replaces under a new id, and delete works
    • every invalid layer kind is refused, and an unreadable-only collage is refused
    • the catalog lists collages right after your images and never as images
  • CmuxNextPagesTests: collage save, get and delete; a malformed collage is refused; the in-use one can't be deleted.
  • Web:
    • collageLayout.test.ts: snapping, staying on the canvas, minimum size, layouts and restacking
    • hostCards.test.tsx: New Collage adds two pictures, applies Side by Side, saves and sets collage:<id>, the in-use one can't be removed, and an edit saves with replacing
    • all 133 settings tests pass
  • vp lint, vp fmt and tsc are clean.

Verification

  • Swift: not built locally. It'll go in the next next-batch run.
  • Not dogfooded.

Not in this PR (follow-ups)

  • Video layers. The spec's "one video plays at a time" needs the collage drawn live, not as one PNG.
  • Placing a layer by hand inside the window. The editor places layers on its canvas.
  • Rotation.

Changelog

Added: Collages: arrange several pictures as one background, with snapping, layouts, rounded corners and a fill color.

🤖 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

Adds collages as a background: several pictures arranged on one 16:10 canvas, drawn natively to a PNG at 3200×2000 and set via appearance.background = collage:<id>.

Collages

  • The Settings editor adds pictures from the grid, drags and resizes with snapping to halves and thirds, nudges with arrow keys, restacks layers, rounds corners, sets a fill color, and picks starter layouts.
  • Collages live in Backgrounds/Collages/ as a JSON record plus a drawing; a saved edit gets a new id, and old files are removed only after the background switches.
  • Still pictures only; videos, the desktop and other collages are refused as layers.
  • The picker lists collages as "Your collages" with edit and remove (never the one in use); ops are cmux.settings.backdrop.image.collage.save | get | delete.

Carried from earlier phases

  • The subject crop keeps art clear of the sidebar and chat.
  • Placing a background by hand via a drag/zoom overlay (cmux.settings.backdrop.image.adjust), saved per background and removed with the picture.
  • Adding your own image from an https link or file drop, with validation and removal; the page's file reads and disk usage run off the main actor.