fix(appx): ship branded Store tiles instead of electron-builder's placeholders - #294
fix(appx): ship branded Store tiles instead of electron-builder's placeholders#294EtienneLescot wants to merge 2 commits into
Conversation
…ceholders Store certification rejected 1.9.0 under 10.1.1.11 "On Device Tiles": "The available product tile icons include a default image." electron-builder reads AppX tile assets from `<buildResources>/appx/` and, when that directory is missing, silently maps its own vendored placeholders into the package — SampleAppx.50x50/150x150/44x44/310x150.png from the winCodeSign bundle, which are blank white squares. `win.icon` does not cover this: it feeds the NSIS installer and the executable, not the tiles. So every Store submission so far carried a default image and nothing in the build warned about it. Add build/appx/, generated from the 1024px master icon by the new `npm run assets:appx`. Each of the seven logos ships its 100% file plus .scale-125/150/200 (and .scale-400 on the small ones), and the 44x44 app-list icon also ships .targetsize-* and .targetsize-*_altform-unplated for the taskbar and Start list. The unqualified file of every asset is kept as the neutral MRT candidate so an unresolved qualifier still finds art rather than falling back to nothing. The generator does its own PNG decode/encode on node:zlib — the dependency tree has no image library, and pulling one with native prebuilds in to draw seven static logos is not a trade worth making. Resampling averages in premultiplied alpha so the transparent black outside the icon's rounded corners cannot bleed into the visible edge at small sizes. Assets are committed rather than generated during packaging: a build-time step goes missing exactly when someone packages from a checkout that skipped it, and the failure mode is a silently generic tile, which is the bug being fixed here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JZV4hzYgcpTfL15wkxyYQz
📝 WalkthroughWalkthroughThe project now generates Microsoft Store AppX/MSIX tile assets from a source PNG. Electron Builder uses ChangesAppX asset generation
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Developer
participant AssetsScript as assets:appx
participant Generator as generate-appx-assets.mjs
participant Builder as Electron Builder
participant Workflow as Windows build workflow
Developer->>AssetsScript: run asset generation
AssetsScript->>Generator: invoke generator
Generator->>Generator: decode, resample, and encode PNG variants
Generator->>Builder: provide assets in build/appx
Builder-->>Workflow: produce .appx package
Workflow->>Workflow: compare packaged PNG hashes
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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 |
The tile substitution that failed certification is invisible from the outside: electron-builder maps a placeholder in for any name missing from build/appx/ and says nothing about it, so a renamed or dropped asset would silently reintroduce the exact bug the previous commit fixes — and we would only learn about it from Partner Center, days later, on a submission that has to be redone. Open the built .appx (it is a ZIP) and compare every committed asset against the copy actually inside it, by hash. Missing or substituted, either way the build fails with the asset named. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JZV4hzYgcpTfL15wkxyYQz
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/build.yml:
- Around line 103-117: Replace the `$expected = Get-ChildItem build/appx -Filter
*.png` source in the APPX validation block with an independent authoritative
asset manifest or clean generator output. Validate the complete expected
filename set against `$entries`, report missing or unexpected PNGs, and retain
hash comparisons for every expected asset so deleted source files or
placeholders cannot pass.
🪄 Autofix
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 Plus
Run ID: a1a1c0b0-26b3-432a-89a6-8b33d7907ac7
📒 Files selected for processing (1)
.github/workflows/build.yml
| $expected = Get-ChildItem build/appx -Filter *.png | ||
| foreach ($asset in $expected) { | ||
| $entry = $entries["assets/$($asset.Name)"] | ||
| if (-not $entry) { $problems += "missing from package: $($asset.Name)"; continue } | ||
| $stream = $entry.Open() | ||
| try { $packaged = [BitConverter]::ToString($sha.ComputeHash($stream)) } | ||
| finally { $stream.Dispose() } | ||
| $source = [BitConverter]::ToString($sha.ComputeHash([IO.File]::ReadAllBytes($asset.FullName))) | ||
| if ($packaged -ne $source) { $problems += "packaged copy differs from build/appx: $($asset.Name)" } | ||
| } | ||
| if ($problems) { | ||
| $problems | ForEach-Object { Write-Output "::error::$_" } | ||
| throw "$($problems.Count) tile asset problem(s) in $($appx.Name)" | ||
| } | ||
| Write-Output "$($expected.Count) tile assets present in $($appx.Name), byte-identical to build/appx/" |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Use an independent expected asset list.
Line 103 derives $expected from the same build/appx directory that supplies the package. If a required PNG is deleted, its name is absent from $expected, so the loop can pass while the package contains a placeholder. An empty directory also reports success with zero assets.
Load expected names from an authoritative manifest or a clean generator output. Compare the complete filename set and hashes.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/build.yml around lines 103 - 117, Replace the `$expected =
Get-ChildItem build/appx -Filter *.png` source in the APPX validation block with
an independent authoritative asset manifest or clean generator output. Validate
the complete expected filename set against `$entries`, report missing or
unexpected PNGs, and retain hash comparisons for every expected asset so deleted
source files or placeholders cannot pass.
Summary
Store certification rejected the 1.9.0 submission under 10.1.1.11 "On Device Tiles" — "The available product tile icons include a default image."
electron-builder reads AppX tile assets from
<buildResources>/appx/, i.e.build/appx/. That directory did not exist, soAppXTarget.computeUserAssets()silently mapped its own vendored placeholders into every package:Those four files (extracted from the
winCodeSign-2.6.0bundle to confirm) are blank white squares.win.icondoes not cover this path — it feeds the NSIS installer and the executable, not the tiles — so every Store submission so far carried a default image, with no warning anywhere in the build.This PR adds
build/appx/(41 PNGs, 960 KB) generated from the 1024 px master icon, plus the generator behindnpm run assets:appx.Design notes
SmallTile,LargeTileandSplashScreenare opt-in: their<uap:>manifest attributes only appear when a matching file is present..scale-125/150/200(plus.scale-400on the small assets), and the 44×44 app-list icon also ships.targetsize-*and.targetsize-*_altform-unplatedfor the taskbar and Start list. This switches electron-builder onto itsmakepri.execode path — verified thatmakepri.exeships in the same vendored bundle asmakeappx.exe(windows-10/x64/), so no new tooling requirement.appx.backgroundColoristransparent, so Windows paints the tile in the user's accent colour: tiles are a padded logo on a transparent canvas rather than full-bleed art, and the two tiles carryingshowNameOnTilesshift their logo up to clear the name band.node:zlib. The dependency tree has no image library, and pulling one with native prebuilds in to draw seven static logos is not a trade worth making. Resampling averages in premultiplied alpha, so the transparent black outside the icon's rounded corners cannot bleed into the visible edge at small sizes.directories.buildResourcesis now spelled out inelectron-builder.json5. It was already the default — behaviour is unchanged — but the whole failure hinged on an implicit path, so it is documented rather than assumed.Related issue
None — reported through Partner Center certification feedback, not a tracked issue.
Type of change
Release impact
Desktop impact
Screenshots / video
Before: there is nothing to show — the shipped 150×150 tile was
SampleAppx.150x150.png, a blank white square from electron-builder's vendored bundle. That blankness is what certification flagged.After — the generated tiles (rendered here at their 100 % dimensions; the transparent canvas is what Windows fills with the accent colour):
Square150x150Logo.scale-200Wide310x150Logo.scale-200StoreLogoSquare44x44Logo.scale-200SmallTileSplashScreenTesting
Verified locally:
npm run assets:appx— 41 files, byte-identical across runs (deterministic output, so re-running never produces a spurious diff).winCodeSign-2.6.0.7zand extractingappxAssets/SampleAppx.150x150.png— a blank white square.windows-10/x64/makepri.exeexists in that same bundle, which is what the scaled-asset code path invokes.node scripts/check-docs.mjs— OK (22 files). Biome clean on the changed JS/JSON.Not verified locally: the
.appxitself cannot be built here (Windows-only). A CI run ofbuild.ymlis in flight on this branch to exercise themakepri.exepath for the first time: https://github.com/getopenscreen/openscreen/actions/runs/31124509799 — the Windows Store package job is the one that matters. The resulting.appxis a ZIP, soassets/Square150x150Logo.pnginside it can be checked directly before the next submission.Note for the next Store submission: this correction round still has to be uploaded manually. Automated submission via the msstore CLI requires the app to be published and live in the Store first, which it is not while 1.9.0 sits rejected.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JZV4hzYgcpTfL15wkxyYQz
Summary by CodeRabbit
New Features
Documentation
Build Improvements