Every consumer of /wallpapers/*.jpg — SettingsPanel, VideoPlayback,
frameRenderer — was doing async IPC round trips, useEffect dances, and
Promise.all for a value that is a build-time constant per process. Each
consumer showed briefly-empty or briefly-404ing state on first paint
until the handler's reply resolved.
The asset base URL depends only on process.defaultApp and
process.resourcesPath / __dirname — all available in preload at
context-bridge time. Compute once there, expose as a sync string.
- preload.ts resolves baseDir (process.resourcesPath packaged,
<appRoot>/public unpackaged) and emits assetBaseUrl synchronously.
- get-asset-base-path IPC handler + main-process branching deleted.
- getAssetPath() is now sync. Returns string, not Promise<string>.
Throws AssetBaseUnavailableError (new) when electronAPI.assetBaseUrl
is missing — catastrophic preload failure, not silent 404.
- resolveImageWallpaperUrl() sync; same sync throw semantics.
- SettingsPanel: Promise.all + useState + useEffect collapse to one
useMemo. First paint has real URLs, no 18× ERR_FILE_NOT_FOUND, no
flicker.
- VideoPlayback: wallpaper-resolve useEffect collapses to useMemo.
- frameRenderer.setupBackground: drops the await.
- electronAPI type decls updated in both .d.ts files.
- 35 unit tests updated to reflect sync signature + new
AssetBaseUnavailableError contract.
Silent-fallback behavior from getAssetPath (returning /relative when
electronAPI failed) is gone. Renderers now surface preload failures
instead of rendering 404s.
- Added electron IPC handler 'reveal-in-folder' to show exported file in finder
- Created toast notification with clickable action to reveal exported video
- Added Show in Folder button in export success dialog
- Implemented proper state management for exported file path
- Fixed timing issue where exportedFilePath was reset too early