fix: three post-rebuild regressions — asar asset paths, tilt feather at radius 0, blank-MIME uploads#170
Merged
EtienneLescot merged 3 commits intoJul 26, 2026
Conversation
… wallpapers load
The native compositor is a Rust addon that opens asset paths with `image::open`.
`resolveSceneAssetPaths` handed it paths rooted at `VITE_PUBLIC`, which is
`<root>/public` in dev but `<resources>/app.asar/dist` in a packaged build: vite
copies `public/` into `dist`, so the files are in there, but inside the archive.
Only Electron's patched `fs` reads through an asar, so every bundled wallpaper
and every themed cursor sprite failed to load in an installed app — silently, on
the native side's colour/default-art fallbacks. Picking a cursor theme looked
like it did nothing, and a bundled image background came out a flat colour.
A CUSTOM uploaded background kept working the whole time, which is what pinned
it down: it travels as a `data:` URL the addon decodes in memory, never a path.
`extraResources` already copies both trees to `<resources>/{wallpapers,cursors}`
as real files — electron-builder.json5's own "Asset layout contract" comment
names exactly this, and `ASSET_BASE_DIR` in electron/windows.ts already resolves
them that way for the renderer. So probe the bases in order and take the one
that actually holds the file, the same candidate-list idiom
`ffmpegSharedBinCandidates` uses right below. Existence-probing rather than
branching on `app.isPackaged` keeps `--dir` staging builds working too.
This resolver also feeds `exportMulti`, so the same assets were missing from
rendered exports in installed builds, not just from the preview.
…stops reading as truncated The tilt path (mode 8) decides coverage with a binary `r.z < 0.5` reject, and the 1.5px SDF feather that turns that staircase into an edge sat behind `if (radius_px > 0.0)`. With the Roundness slider at 0 — its default — the plane kept hard aliased edges, which is precisely the failure this branch's own comment describes: "des arêtes de couteau qui coupent le contenu en pleine phrase, et ça se lit comme une troncature plutôt que comme une inclinaison". Hence the report that the 3D zoom looks cut off, but only below some minimum corner radius. `sd_round_rect` degenerates to a plain box SDF at r = 0, so the guard bought nothing: drop it and clamp with `max(radius_px, 0.0)`. The mode 12 shadow already applies its radius unguarded for the same reason. The geometry was never the problem — `every_preset_stays_inside_the_original_rect` already holds, so nothing was being clipped by the frame.
…en a file is refused
`handleFileSelected` gated custom wallpaper uploads on
`file.type.startsWith("image/")`, so a file the browser reports no MIME type for
— which Windows does for some files and some locales — was dropped on the floor,
with no toast, no message, nothing. The user picked a PNG and the pane simply did
not react.
That exact case had been fixed once, in "Allow PNG custom background uploads":
`isSupportedBackgroundImageType` fell back to the file extension when `type` was
blank, and its test named a real offender (`生成画像1.png`). The module was never
imported by the upload path though — only by its own test — so the 2026-07-26
reorg removed it as dead code, correctly, and the repo lost the fallback while
keeping the weaker check that needed it.
So restore the fallback where the upload actually happens, and derive the
`accept` filter from the same two lists the validation uses, since those had
already drifted apart once (the accept string was an inline copy of the deleted
module's constant). An explicit non-image type is still refused — only a blank
one earns the extension fallback, so `notes.txt` renamed to `notes.png` does not
get through.
Rejections and unreadable files now raise a toast, localized across all 13
locales. Tests are the recovered cases plus a component test asserting the toast
actually reaches the user, which is the half that was really missing.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three regressions reported after rebuilding from
release/1.8.0, with the worry that the 2026-07-26 history reorg (317 → 126 commits) had dropped features.It hadn't.
poc-d3d/src/*.rs— the whole native renderer — is byte-identical betweenbackup/ai-edition-pre-reorgandrelease/1.8.0; the zoom/tilt/corner fixes all survived. The cursor, background and zoom sources differ only by benign refactors (a sharedclamp, reusing the gradient parser), assets are intact, and the freshly builtcompositor_view.nodehashes identical to the one in the installer. Two unrelated real bugs, neither caused by the reorg.1. Cursor themes and bundled backgrounds — a packaging bug
The native compositor is a Rust addon calling
image::openon raw OS paths.resolveSceneAssetPathsrooted those atVITE_PUBLIC, which is<root>/publicin dev but<resources>/app.asar/distwhen packaged. Vite copiespublic/intodist, so the files are there — inside the archive, where only Electron's patchedfscan read. Both features failed silently on the native side's fallbacks: default cursor art, flat background colour.This is why it looked new: the app is now run as a packaged installer rather than
npm run dev. The bug was latent all along and is invisible in dev.The clue that cracked it: a custom uploaded background worked the whole time, because it travels as a
data:URL the addon decodes in memory (decode_data_uri), never as a path. Feature works with a data URL but not a file path ⇒ path resolution, not rendering.Fix follows the layout contract already documented in
electron-builder.json5and already used byASSET_BASE_DIRinelectron/windows.ts:extraResourcescopies both trees to<resources>/{wallpapers,cursors}as real files. Candidate bases are probed for existence rather than branching onapp.isPackaged, mirroringffmpegSharedBinCandidatesright below it, which keeps--dirstaging builds and tests working.Verified against the real installed build — every path the old code produced is missing, every path the fix produces exists:
This resolver also feeds
exportMulti, so bundled wallpapers and themed cursors were missing from rendered exports too, not only the preview.2. 3D zoom read as truncated at Roundness 0
The tilt path (mode 8) decides coverage with a binary
r.z < 0.5reject, and the 1.5px SDF feather that turns that staircase into an edge sat behindif (radius_px > 0.0). At the slider's default of 0 the plane kept hard aliased edges — exactly what the branch's own comment describes: "des arêtes de couteau qui coupent le contenu en pleine phrase, et ça se lit comme une troncature plutôt que comme une inclinaison." Hence "truncated, but not above some minimum corner radius".sd_round_rectdegenerates to a plain box SDF at r = 0, so the guard bought nothing. Dropped, clamped withmax(radius_px, 0.0). The mode 12 shadow already applies its radius unguarded for the same reason.Geometry was never at fault —
every_preset_stays_inside_the_original_rectalready passes, so nothing was being clipped by the frame.3. Custom uploads silently dropped on a blank MIME type
handleFileSelectedgated onfile.type.startsWith("image/"), so a file the browser reports no MIME type for (Windows does this for some files and locales) was dropped with no toast, no message. That case had been fixed once in "Allow PNG custom background uploads", butisSupportedBackgroundImageTypewas never imported by the upload path — only by its own test — so the reorg removed it as dead code, correctly, and the repo lost the fallback while keeping the weaker check that needed it.Restored at the upload path.
acceptis now derived from the same two lists the validation reads, since those had already drifted once (the inlineIMAGE_ACCEPTwas a copy of the deleted module's constant). An explicit non-image type is still refused, sonotes.txtrenamed tonotes.pngdoes not get through. Rejections and read failures now raise a toast, localized across all 13 locales.Verification
tsc --noEmitclean, biome clean.生成画像1.pngwith a blank MIME type) plus two component tests that renderBackgroundPane, fire a realchange, and assert the toast actually reaches the user. All would fail against the previous code.Fixes 1 and 2 need a rebuild to observe (
npm run build:win) — one lives indist-electron, the other in the addon.Notes for review
sonnertoast inRightPanes.tsxis the pane's first, but the established idiom in this shell (ExportDialog,LeftPanel).video-editorupload path; nothing there referenced the deleted module either, so whether a second uploader needs the same treatment is a separate question I'd rather confirm than assume.padding; the "custom upload does display" observation killed it (padding is baked into the app-resolved screen rect). No code shipped from it, noted only so the same dead end isn't retried.