cmux-next: place a Chief's picture in its circle, and go back to the default
Phase 4 of the backgrounds plan (briefs/next-backgrounds-plan.md): custom Chief pictures.
What changes
Chief sheet (named Chiefs, home-channels page):
- Place a still in the circle. After choosing a PNG, JPEG or WebP, a circular preview appears. Drag to move the picture, and use the Zoom slider (1×–4×).
- On save, the placed square is drawn at 512 px (never scaled up), as PNG, or as JPEG if a busy photo's PNG would pass 1 MB.
- So a photo up to 20 MB now fits the daemon's 1 MB. Before, anything over 1 MB was refused.
- GIFs keep their motion. A GIF is sent as it is (still capped at 1 MB) and drawn centered, as before. Placing it would mean re-encoding the animation.
- Use Default Picture clears the picture.
chief.profile.avatar.setgetsclear: true, which the daemon already accepts, and the bundled default shows again. - The crop math is pure (
picture.ts:cropSquareanddragCrop), andpreparePicturetakes the renderer as a parameter, so tests run without a canvas.
Chief Settings (the default Chief, native):
- Choose Picture… draws a still at 512 px as
avatar.png, or copies a GIF of up to 5 MB asavatar.gif, next tooptchat/profile.json, and pointsavatarat it. Choosing again replaces the old file. - Use Default Picture clears the avatar and removes those files.
- A file that isn't a picture says so in the panel's error line and changes nothing.
- GIF and WebP now show in the header and tile.
HomeChiefFiles.namesPictureused to accept only PNG, JPEG and HEIC, so a GIF or WebP named in the profile showed as nothing. HomeHostView.onAvatarnow just re-reads the avatar (header and tile) after the write finishes, instead of guessing from the text field. That makes the App 2 source lines smaller.
Strings
All 21 locales:
- Home page catalog: 4 keys (
chief.picture.zoom,cropHint,useDefault,tooBig). Home.xcstrings: 3 keys (home.engine.choosePicture,useDefaultPicture,pictureUnreadable).generated/strings.jsonis regenerated.
Tests
webviews/test/home-chief-picture.test.ts:- crop square clamping at every zoom and drag
- drag direction and the edge stop
- a 5 MB still is drawn rather than refused, at its crop and 512 px
- a still over 20 MB, a GIF over 1 MB, and SVG are refused
- a GIF passes through untouched
- Use Default sends
clear: truewith no data
CmuxNextAppTests/ChiefPictureFilesTests:- GIF and WebP names are accepted
- a 3000×2000 photo becomes 512 px
- a 3-frame GIF is kept byte for byte and replaces the old PNG
- a non-picture changes nothing
- Use Default goes back to the cat
Verification
- Web:
- new tests pass (4/4)
vp lintandvp fmtare clean on the changed filestschas no errors in home-channelscheck:browser-lanesis OK- the existing
test/home*suites pass, except one fixture outside my sparse checkout
- Swift: not built locally (no Mac in this lane), so CI is the first compile.
lint-ios-package-conventions.shis clean. - Not dogfooded.
Not in this PR (follow-ups)
- Native crop for the default Chief. The native panel draws the picture centered. Placing it there needs an AppKit crop sheet.
- Using the Chief's picture as the agent-pane dock mascot, and as notification thumbnails. Both touch the agent pane and App notification code, so they'll be separate PRs.
- The "animate Chief pictures" toggle (Always / On hover / Never) is in phase 5, the settings PR that Leo reviews first.
WINDOW
None. No settings schema, catalog or Package.swift change.
Changelog
Added: Place your own picture for a Chief in its circle, or go back to the default picture; GIF and WebP pictures show on the Home header.
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Phase 4 of the backgrounds plan: users can now place a Chief's picture in its circle on the web, and choose or clear the default Chief's picture in native settings.
Web Chief sheet
- A chosen PNG, JPEG or WebP is shown in a circle with drag and a 1×–4× zoom slider; on save it is drawn at 512 px as PNG, or as JPEG when a busy photo's PNG would pass the daemon's 1 MB limit.
- Stills up to 20 MB are now accepted; anything over 1 MB was refused before.
- GIFs are sent as-is (still capped at 1 MB) and keep their motion, drawn centered.
- Use Default Picture sends
clear: true, which the daemon already accepts.
Native Chief Settings
- Choose Picture… writes a still at 512 px as
avatar.pngor copies a GIF up to 5 MB asavatar.gif, and points the profile'savatarat it; choosing again replaces the old file. - GIF and WebP pictures now show in the header and tile; only PNG, JPEG and HEIC were recognized before.
- Use Default Picture clears the avatar and removes the written files; an unreadable file reports an error and changes nothing.
All 21 locales get the 4 new web keys and 3 new native keys. Tests cover crop clamping and dragging, drawn size and format, GIF passthrough, and clearing.