Brand Refresh (by @michalkopanski, #3130)#3367
Conversation
…ution Replaces the workspace-name-colored border overlay with explicit icon files per build type. Resolution order: icon-dev.png → icon.png (dev), icon-canary.png → icon.png (canary), icon.png (stable).
Adds support for a custom background.tiff in the DMG installer window. Falls back to electron-builder's default if the file is absent.
Overlays a hash-colored triangle in the top-right corner of the dock icon in dev mode so multiple workspaces are visually distinguishable at a glance. The fill is clipped to the icon's alpha so it hugs the rounded corner. Replaces the previous rounded-rect border implementation.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds conditional DMG background handling to Electron Builder, refactors macOS dock icon logic to support dev/canary assets and workspace-colored corner-fold overlays with alpha-aware compositing, and reformats minor pane-reuse logic in the tabs store. Changes
Sequence DiagramsequenceDiagram
participant App as App
participant Ver as VersionDetector
participant FS as FileSystem
participant Icon as IconManager
participant Img as ImageProcessor
participant Dock as macOS Dock
App->>Ver: getVersion()
Ver-->>App: version
App->>Ver: prerelease(version)
Ver-->>App: prerelease?
alt prerelease (canary)
App->>Icon: select 'icon-canary.png'
else development
App->>Icon: select 'icon-dev.png'
else production
App->>Icon: select 'icon.png'
end
Icon->>FS: exists(iconPath)
FS-->>Icon: boolean
alt icon exists
Icon->>FS: read icon
FS-->>Icon: image data
else fallback
Icon-->>App: use default icon
end
alt development & workspace name
App->>Img: pickWorkspaceColor(name)
Img-->>App: RGB
App->>Img: drawCornerFold(icon, RGB)
Img-->>App: decorated icon
end
App->>Dock: setAppIcon(icon)
Dock-->>App: ok
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~40 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR delivers a brand refresh across the desktop and marketing apps: new per-build-type dock icons ( The main code change is a significant refactor of Key observations:
Confidence Score: 5/5Safe to merge — all binary/asset changes are visual-only and the TypeScript refactor is clean with correct fallbacks throughout. The only code changes are in apps/desktop/src/main/lib/dock-icon.ts — minor alpha-compositing artefact in blendPixel worth a follow-up but not a blocker Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[setWorkspaceDockIcon called] --> B{platform === darwin?}
B -- No --> Z[return no-op]
B -- Yes --> C[getIconPath]
C --> D{NODE_ENV === development?}
D -- Yes --> E{icon-dev.png exists?}
E -- Yes --> F[use icon-dev.png]
E -- No --> G[use icon.png]
D -- No --> H{isCanaryBuild?\nsemver.prerelease}
H -- Yes --> I{icon-canary.png exists?}
I -- Yes --> J[use icon-canary.png]
I -- No --> G
H -- No --> G
F & G & J --> K[nativeImage.createFromPath]
K --> L{icon.isEmpty?}
L -- Yes --> M[warn + return]
L -- No --> N{NODE_ENV === development\nAND workspaceName set?}
N -- No --> O[app.dock.setIcon directly]
N -- Yes --> P[findContentBounds\nscan all RGBA pixels]
P --> Q[pickWorkspaceColor\nhash → Tailwind 500 palette]
Q --> R[drawCornerFold\ntriangle in top-right corner]
R --> S[blendPixel per triangle pixel\nalpha-composited onto bitmap]
S --> T[nativeImage.createFromBitmap]
T --> U[app.dock.setIcon]
Reviews (1): Last reviewed commit: "lint" | Re-trigger Greptile |
| const outA = alpha + da * (1 - alpha); | ||
| if (outA <= 0) return; | ||
|
|
||
| bitmap[offset] = Math.round((rgb[0] * alpha + dr * da * (1 - alpha)) / outA); | ||
| bitmap[offset + 1] = Math.round( | ||
| (rgb[1] * alpha + dg * da * (1 - alpha)) / outA, | ||
| ); | ||
| bitmap[offset + 2] = Math.round( | ||
| (rgb[2] * alpha + db * da * (1 - alpha)) / outA, | ||
| ); | ||
| bitmap[offset + 3] = Math.round(outA * 255); |
There was a problem hiding this comment.
Alpha increases for semi-transparent edge pixels inside the fold
blendPixel receives alpha = diagAlpha * iconAlpha as the source alpha and then reads da = iconAlpha as the destination alpha. For a fully-opaque icon pixel this is fine (outA = 1), but for semi-transparent pixels (e.g., the anti-aliased rounded corners of the icon that happen to fall inside the corner-fold triangle), the output alpha is:
outA = alpha + da * (1 - alpha)
= (diagAlpha × iconAlpha) + iconAlpha × (1 − diagAlpha × iconAlpha)
For example, an edge pixel with iconAlpha = 0.5 and diagAlpha = 1.0:
- Expected: destination alpha stays
0.5 - Actual:
outA = 0.5 + 0.5 × 0.5 = 0.75
In practice, keeping the destination alpha unchanged while blending only the RGB channels is simpler and avoids the artefact:
// Simple RGB lerp, preserve destination alpha
const offset = (y * width + x) * 4;
const t = diagAlpha * iconAlpha; // fold coverage, masked by icon shape
bitmap[offset] = Math.round(rgb[0] * t + (bitmap[offset] ?? 0) * (1 - t));
bitmap[offset + 1] = Math.round(rgb[1] * t + (bitmap[offset + 1] ?? 0) * (1 - t));
bitmap[offset + 2] = Math.round(rgb[2] * t + (bitmap[offset + 2] ?? 0) * (1 - t));
// bitmap[offset + 3] left unchangedThe visual difference is subtle at dock scale, but this avoids the rounded-corner edge becoming slightly more opaque than the rest of the icon in the fold area.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/desktop/src/main/lib/dock-icon.ts`:
- Around line 207-210: The tint currently multiplies into the source alpha
(calling blendPixel(..., diagAlpha * iconAlpha)), which increases opacity of
partially transparent edge pixels; instead pass the original icon alpha as the
source alpha and apply diagAlpha only to the source color channels. Concretely:
call blendPixel(bitmap, width, height, x, y, rgb, iconAlpha, diagAlpha) (or add
a separate colorMultiplier arg) and change blendPixel to use the provided
sourceAlpha for alpha compositing while multiplying only the source RGB by
colorMultiplier (diagAlpha) before doing the source-over blend, leaving
iconAlpha unchanged as the source alpha.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 926661f7-dbf9-4678-b8e9-ade54c6affc8
⛔ Files ignored due to path filters (11)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/assets/superset-empty-state-wordmark.svgis excluded by!**/*.svgapps/desktop/src/resources/build/icons/icon-canary.icois excluded by!**/*.icoapps/desktop/src/resources/build/icons/icon-canary.pngis excluded by!**/*.pngapps/desktop/src/resources/build/icons/icon-dev.icois excluded by!**/*.icoapps/desktop/src/resources/build/icons/icon-dev.pngis excluded by!**/*.pngapps/desktop/src/resources/build/icons/icon.icois excluded by!**/*.icoapps/desktop/src/resources/build/icons/icon.pngis excluded by!**/*.pngapps/desktop/src/resources/build/installer/background.tiffis excluded by!**/*.tiffapps/desktop/src/resources/tray/iconTemplate.pngis excluded by!**/*.pngapps/marketing/public/favicon-192.pngis excluded by!**/*.pngapps/marketing/public/title.svgis excluded by!**/*.svg
📒 Files selected for processing (5)
apps/desktop/electron-builder.tsapps/desktop/src/main/lib/dock-icon.tsapps/desktop/src/resources/build/icons/icon-canary.icnsapps/desktop/src/resources/build/icons/icon-dev.icnsapps/desktop/src/resources/build/icons/icon.icns
| const iconAlpha = (bitmap[(y * width + x) * 4 + 3] ?? 0) / 255; | ||
| if (iconAlpha <= 0) continue; | ||
|
|
||
| blendPixel(bitmap, width, height, x, y, rgb, diagAlpha * iconAlpha); |
There was a problem hiding this comment.
Preserve the icon alpha when tinting the fold.
Line 210 passes diagAlpha * iconAlpha into a source-over blend. On partially transparent edge pixels that turns alpha a into a + a(1-a), so the fold makes rounded corners slightly more opaque instead of just recoloring inside the existing mask.
🎯 Suggested fix
- const iconAlpha = (bitmap[(y * width + x) * 4 + 3] ?? 0) / 255;
- if (iconAlpha <= 0) continue;
-
- blendPixel(bitmap, width, height, x, y, rgb, diagAlpha * iconAlpha);
+ const offset = (y * width + x) * 4;
+ const iconAlpha = bitmap[offset + 3] ?? 0;
+ if (iconAlpha <= 0) continue;
+
+ bitmap[offset] = Math.round(
+ (bitmap[offset] ?? 0) * (1 - diagAlpha) + rgb[0] * diagAlpha,
+ );
+ bitmap[offset + 1] = Math.round(
+ (bitmap[offset + 1] ?? 0) * (1 - diagAlpha) + rgb[1] * diagAlpha,
+ );
+ bitmap[offset + 2] = Math.round(
+ (bitmap[offset + 2] ?? 0) * (1 - diagAlpha) + rgb[2] * diagAlpha,
+ );
+ bitmap[offset + 3] = iconAlpha;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/main/lib/dock-icon.ts` around lines 207 - 210, The tint
currently multiplies into the source alpha (calling blendPixel(..., diagAlpha *
iconAlpha)), which increases opacity of partially transparent edge pixels;
instead pass the original icon alpha as the source alpha and apply diagAlpha
only to the source color channels. Concretely: call blendPixel(bitmap, width,
height, x, y, rgb, iconAlpha, diagAlpha) (or add a separate colorMultiplier arg)
and change blendPixel to use the provided sourceAlpha for alpha compositing
while multiplying only the source RGB by colorMultiplier (diagAlpha) before
doing the source-over blend, leaving iconAlpha unchanged as the source alpha.
…#3367) * feat(desktop): custom dev/canary dock icons with per-build-type resolution Replaces the workspace-name-colored border overlay with explicit icon files per build type. Resolution order: icon-dev.png → icon.png (dev), icon-canary.png → icon.png (canary), icon.png (stable). * feat(desktop): custom DMG installer background Adds support for a custom background.tiff in the DMG installer window. Falls back to electron-builder's default if the file is absent. * Update macOS tray icon asset * Update favicon-192.png asset for marketing application * Update title.svg with new updated logo design * Update superset-empty-state-wordmark.svg with new logo design and dimensions * feat(desktop): workspace-colored corner fold on dev dock icon Overlays a hash-colored triangle in the top-right corner of the dock icon in dev mode so multiple workspaces are visually distinguishable at a glance. The fill is clipped to the icon's alpha so it hugs the rounded corner. Replaces the previous rounded-rect border implementation. * lint --------- Co-authored-by: Michal Kopanski <info@michalkopanski.com>
Summary
icon.png/icns/ico,icon-canary,icon-dev) with updated logo treatmenticonTemplate.png) with new designbackground.tiff) for macOSicon-dev.png, canary →icon-canary.png, stable →icon.pngtitle.svg) andfavicon-192.pngwith new logo designsuperset-empty-state-wordmark.svg) with new logo and dimensionsDesign Updates
How It Works
Build-type detection uses
semverprerelease tags — dev builds pickicon-dev, canary picksicon-canary, stable falls back toicon.png. The dock icon setter is simplified but still overlays a workspace-colored corner fold in dev mode to visually distinguish simultaneous workspaces.Test plan
icon-dev.pngin the dock with a workspace-colored corner foldicon-canary.pngin the dockicon.pngin the dockTesting
bun run typecheckbun run lint