Skip to content

Fix double-frame app icon in DMG installer - #1257

Closed
lawrencecchen wants to merge 1 commit into
mainfrom
issue-1256-dmg-icon-double-frame
Closed

lawrencecchen wants to merge 1 commit into
mainfrom
issue-1256-dmg-icon-double-frame

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Mar 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fix the double-frame app icon in the DMG installer window. macOS Finder adds a gray background plate behind icons with transparent corners. On cmux's light white icon, this creates a prominent double-frame (gray outer squircle behind the white icon squircle). The icon looks fine in the Dock because the plate is less visible at smaller sizes and darker rendering contexts.

Changes:

  • Remove AppIcon.icon (Xcode 16 Icon Composer format) which added an additional dynamic plate
  • Switch from npm create-dmg (sindresorhus, no customization options) to Homebrew create-dmg which supports custom backgrounds, icon positioning, and layout
  • Add a dark charcoal DMG background (scripts/dmg-background.png) with a subtle chevron arrow. Against the dark background, the Finder plate becomes invisible and the icon renders cleanly with its full 3D depth/shadow
  • Update scripts/build-sign-upload.sh to use the same styled DMG layout
  • Update tests/test_ci_create_dmg_pinned.sh for the new Homebrew-based setup

Testing

Trigger a nightly build from this branch to verify the DMG icon renders without the double-frame:

gh workflow run nightly.yml --repo manaflow-ai/cmux -f force=true -f ref=issue-1256-dmg-icon-double-frame

Related

Summary by CodeRabbit

  • Chores
    • Removed an unused app icon configuration.
    • Reworked DMG packaging to use a consistent installer creation tool and explicit DMG parameters (custom background, window/layout, codesigning, notarization, stapling, validation).
  • Tests
    • Updated CI checks to validate the new DMG creation approach and presence of the custom DMG background asset.

@vercel

vercel Bot commented Mar 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Mar 12, 2026 11:17am

@coderabbitai

coderabbitai Bot commented Mar 12, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@lawrencecchen has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 55 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bfeb7ec9-f769-4a41-90d8-2dadf63b5b53

📥 Commits

Reviewing files that changed from the base of the PR and between 720fb98 and c9b7756.

⛔ Files ignored due to path filters (1)
  • AppIcon.icon/Assets/cmux-icon-chevron 2.png is excluded by !**/*.png
📒 Files selected for processing (2)
  • AppIcon.icon/icon.json
  • GhosttyTabs.xcodeproj/project.pbxproj
📝 Walkthrough

Walkthrough

This PR removes the AppIcon.icon asset and its Xcode project references, and changes CI/build packaging to use Homebrew-installed create-dmg with an explicit DMG creation flow (custom background, layout, codesigning) and updated notarization/stapling handling.

Changes

Cohort / File(s) Summary
Icon Asset Deletion
AppIcon.icon/icon.json
Deleted the icon configuration JSON (layers, fill, shadow, translucency, platform metadata).
Project Configuration
GhosttyTabs.xcodeproj/project.pbxproj
Removed AppIcon.icon file reference from PBXFileReference and project groups.
CI Workflows
.github/workflows/nightly.yml, .github/workflows/release.yml
Switched create-dmg installation from npm → Homebrew; replaced simple DMG creation with an explicit parameterized create-dmg invocation (background, window layout, icon placement, codesign integration); adjusted DMG packaging/notarization flow to use the new creation method.
Build Script
scripts/build-sign-upload.sh
Replaced simple DMG creation with enhanced flow: compute SCRIPT_DIR, pre-codesign app, create-dmg with background/window/icon layout, then notarize, staple and validate DMG.
CI Tests
tests/test_ci_create_dmg_pinned.sh
Updated assertions to require Homebrew installation of create-dmg, ensure no npm create-dmg usage, and enforce presence of scripts/dmg-background.png (new DMG background check).

Sequence Diagram(s)

sequenceDiagram
  participant GH as GitHub Actions
  participant Script as build-sign-upload.sh
  participant Codesign as Codesign Tool
  participant CreateDMG as create-dmg (Homebrew)
  participant Notary as Apple Notary Service
  participant Stapler as stapler
  participant Release as Release Storage

  GH->>Script: run packaging job (nightly/release)
  Script->>Codesign: codesign the .app
  Codesign-->>Script: signed .app
  Script->>CreateDMG: create-dmg with background, layout, app-drop link, codesign identity
  CreateDMG-->>Script: generated .dmg
  Script->>Notary: submit .dmg for notarization
  Notary-->>Script: notarization status (approved)
  Script->>Stapler: staple notarization ticket to .dmg
  Stapler-->>Script: stapled .dmg validated
  Script->>Release: upload final .dmg
  Release-->>GH: artifact available
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 A tiny rabbit hops with glee,
Icons trimmed, CI set free,
DMG gets dressed in background art,
Signed and stapled, ready to start,
Off it bounces to release with a heart ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: fixing the double-frame icon issue in the DMG installer by removing the problematic AppIcon.icon file and switching to Homebrew create-dmg with a custom dark background.
Description check ✅ Passed The PR description provides a clear Summary section explaining what changed and why, adequate Testing instructions with a specific command to trigger verification, and mentions the related issue. However, it omits the Demo Video section, Checklist items, and the Review Trigger block specified in the template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-1256-dmg-icon-double-frame

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR removes the AppIcon.icon bundle (Xcode 16 Icon Composer format) and its reference from the Xcode project, fixing a visual bug where macOS dynamically rendered a gray background plate behind the app icon in Finder's large icon view and the DMG installer window. The existing pre-rendered AppIcon.appiconset PNGs in Assets.xcassets — which do not trigger the dynamic plate — remain the sole icon source.

  • Deleted AppIcon.icon/icon.json (Icon Composer manifest) and AppIcon.icon/Assets/cmux-icon-chevron 2.png
  • Removed the corresponding PBXFileReference and group entry (IC000002) from GhosttyTabs.xcodeproj/project.pbxproj
  • No dangling references remain in the project file; ASSETCATALOG_COMPILER_APPICON_NAME correctly continues to point to AppIcon in the asset catalog
  • The change is surgical and low-risk — it is purely a deletion with no modifications to any existing source or asset

Confidence Score: 5/5

  • This PR is safe to merge — it is a clean deletion of unused files with no risk of regression.
  • The change removes only the Icon Composer bundle and its two Xcode project references. The fallback icon source (AppIcon.appiconset) was already in place and is fully intact. No code logic, build settings, or other assets are modified. All dangling references have been properly cleaned up.
  • No files require special attention.

Important Files Changed

Filename Overview
AppIcon.icon/icon.json Xcode 16 Icon Composer manifest deleted — correctly removes the source of the dynamic background plate rendering that caused the double-frame effect in the DMG window.
AppIcon.icon/Assets/cmux-icon-chevron 2.png Binary icon asset deleted alongside its parent Icon Composer bundle; the equivalent pre-rendered PNGs in Assets.xcassets/AppIcon.appiconset/ remain intact.
GhosttyTabs.xcodeproj/project.pbxproj Removes both the PBXFileReference entry and the group membership for AppIcon.icon (ID IC000002); no dangling references remain and ASSETCATALOG_COMPILER_APPICON_NAME still correctly points to AppIcon in the asset catalog.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Xcode Build] --> B{Icon Source?}
    B -->|Before PR: AppIcon.icon\nXcode 16 Icon Composer| C[macOS dynamically adds\nbackground plate]
    C --> D[Double-frame squircle\nvisible in DMG/Finder]
    B -->|After PR: AppIcon.appiconset\nPre-rendered PNGs| E[Icon rendered as-is\nno dynamic plate added]
    E --> F[Clean icon in DMG,\nDock unchanged]
Loading

Last reviewed commit: dabf964

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release.yml:
- Around line 96-99: The "Install build deps" step currently runs an unpinned
brew install create-dmg which allows version drift; update that step in both
release and nightly workflows to install a specific create-dmg version (e.g.,
use a pinned formula like create-dmg@<VERSION> or install from a fixed Homebrew
tap/formula URL) so builds are reproducible, and ensure any related cache or
verification steps are updated to expect the pinned version; modify the step
named "Install build deps" in both workflows accordingly.

In `@tests/test_ci_create_dmg_pinned.sh`:
- Around line 20-23: The current grep only detects "npm install ... create-dmg"
and misses other npm-based invocations; update the grep used on the variable
workflow (the grep -Eq call) to use a broader regex that matches any npm-based
invocation like "npx create-dmg", "npm exec create-dmg", "npm run ...
create-dmg" as well as "npm install ... create-dmg" so the test fails if any npm
runner is used instead of the Homebrew create-dmg; keep the check logic and
error message the same but replace the pattern to include those additional
command forms.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b03ebae-9f35-445c-9511-39044ef8f61a

📥 Commits

Reviewing files that changed from the base of the PR and between dabf964 and 720fb98.

⛔ Files ignored due to path filters (1)
  • scripts/dmg-background.png is excluded by !**/*.png
📒 Files selected for processing (4)
  • .github/workflows/nightly.yml
  • .github/workflows/release.yml
  • scripts/build-sign-upload.sh
  • tests/test_ci_create_dmg_pinned.sh

Comment thread .github/workflows/release.yml Outdated
Comment on lines +96 to +99
- name: Install build deps
if: steps.guard_release_assets.outputs.skip_all != 'true'
run: |
npm install --global "create-dmg@${CREATE_DMG_VERSION}"
brew install create-dmg

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "create-dmg install commands:"
rg -n --glob '.github/workflows/*.yml' '\bbrew install create-dmg\b'

echo
echo "create-dmg invocations:"
rg -n --glob '.github/workflows/*.yml' --glob 'scripts/*.sh' '\bcreate-dmg\b'

echo
echo "Pinning / reproducibility safeguards:"
rg -n 'brew pin|create-dmg@|brew extract|HOMEBREW_NO_AUTO_UPDATE|Brewfile' .github/workflows scripts tests || true

Repository: manaflow-ai/cmux

Length of output: 254


🏁 Script executed:

git ls-files | head -20

Repository: manaflow-ai/cmux

Length of output: 675


🏁 Script executed:

find . -name "*.yml" -o -name "*.yaml" | head -20

Repository: manaflow-ai/cmux

Length of output: 957


🏁 Script executed:

ls -la .github/ 2>/dev/null || echo ".github directory not found"

Repository: manaflow-ai/cmux

Length of output: 372


🏁 Script executed:

cat .github/workflows/release.yml | grep -n "create-dmg" -C 2

Repository: manaflow-ai/cmux

Length of output: 527


🏁 Script executed:

cat .github/workflows/nightly.yml | grep -n "create-dmg" -C 2

Repository: manaflow-ai/cmux

Length of output: 431


🏁 Script executed:

grep -r "brew pin\|create-dmg@\|brew extract\|HOMEBREW_NO_AUTO_UPDATE\|Brewfile" .github/workflows scripts tests 2>/dev/null || echo "No pinning safeguards found"

Repository: manaflow-ai/cmux

Length of output: 87


Pin create-dmg in release and nightly workflows to ensure reproducible signing.

Both release.yml (line 99) and nightly.yml (line 129) use unpinned brew install create-dmg. This allows the installed tool version to drift between runs, potentially altering signed/notarized release artifacts without any repository change. No pinning safeguards exist in the codebase.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release.yml around lines 96 - 99, The "Install build deps"
step currently runs an unpinned brew install create-dmg which allows version
drift; update that step in both release and nightly workflows to install a
specific create-dmg version (e.g., use a pinned formula like
create-dmg@<VERSION> or install from a fixed Homebrew tap/formula URL) so builds
are reproducible, and ensure any related cache or verification steps are updated
to expect the pinned version; modify the step named "Install build deps" in both
workflows accordingly.

Comment thread tests/test_ci_create_dmg_pinned.sh Outdated
Comment on lines +20 to +23
if grep -Eq 'npm install.*create-dmg' "$workflow"; then
echo "FAIL: $workflow should not use npm create-dmg (use Homebrew version)"
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Broaden the npm regression check.

This only catches npm install ... create-dmg. A future switch to npx create-dmg or npm exec create-dmg would still pass this test while reintroducing the same npm-based toolchain.

Suggested fix
-  if grep -Eq 'npm install.*create-dmg' "$workflow"; then
+  if grep -Eq '\b(npm (install|i|exec)|npx)\b.*\bcreate-dmg\b' "$workflow"; then
     echo "FAIL: $workflow should not use npm create-dmg (use Homebrew version)"
     exit 1
   fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_ci_create_dmg_pinned.sh` around lines 20 - 23, The current grep
only detects "npm install ... create-dmg" and misses other npm-based
invocations; update the grep used on the variable workflow (the grep -Eq call)
to use a broader regex that matches any npm-based invocation like "npx
create-dmg", "npm exec create-dmg", "npm run ... create-dmg" as well as "npm
install ... create-dmg" so the test fails if any npm runner is used instead of
the Homebrew create-dmg; keep the check logic and error message the same but
replace the pattern to include those additional command forms.

The Xcode 16 Icon Composer format (AppIcon.icon) causes macOS to
dynamically render a background plate with depth effects behind the
icon. In the DMG Finder view this plate is prominently visible.

Removing it makes Xcode fall back to the pre-rendered AppIcon.appiconset
PNGs, which produce a subtler standard system plate.

Fixes #1256
@lawrencecchen
lawrencecchen force-pushed the issue-1256-dmg-icon-double-frame branch from 720fb98 to c9b7756 Compare March 12, 2026 11:16
@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview — c9b77561 Deployed Mar 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants