6.1 KiB
6.1 KiB
Checkpoint — Linux display compatibility + icon alpha fixes (2026-09-09)
Where things are
- Project:
/home/avi/Projects/Keynctr - Branch:
master@d580139("fix(icons): true alpha channel, no white matte or white tile") on top of0814a53("fix(linux): work on X11, Wayland, and Hyprland"). - Working tree: clean for tracked files. Untracked leftovers are the pre-existing
hygiene entries (
.directory,.impeccable/,.opencode/,COSMIC_THEME.md,src/publish.rs.bak,src/signer/nip46_external.rs) plusdeferred/SignerConnectionPanel.tsx.wip(a broken WIP component, moved out of the build — see below). Original white-background icons are preserved underdeferred/original-icons/(tracked).
What was completed (this session)
1. Linux display-server compatibility — 0814a53
The app did not start on a friend's Wayland machine. Root causes found and fixed:
- No explicit platform choice. Hyprland (and any Wayland session with XWayland)
exports both
$DISPLAYand$WAYLAND_DISPLAY, so Electron must be told which backend to use before Chromium initializes.frontend/electron/main.tsnow setsozone-platform(wayland/x11) fromXDG_SESSION_TYPE/WAYLAND_DISPLAYat module load, withKEYNCTR_FORCE_X11=1/KEYNCTR_FORCE_WAYLAND=1overrides. - GPU process crashes (SIGSEGV in
eglCreateWindowSurface, MesalibGLESv2). Reproduced on this box (Intel Iris Xe, Hyprland, mesa 26.2.1): with hardware GL the GPU helper died repeatedly and the window never appeared. Fix: software rendering by default on Linux (app.disableHardwareAcceleration()); hardware GL is opt-in viaKEYNCTR_ENABLE_GPU=1. - Startup watchdog + bounded relaunch ladder. A marker file
(
<tmp>/keynctr-startup.json, stamped clean on deliberate quit) records each launch; if the previous process died before its window proved itself (painted and survived 8 s), the next launch advances one rung: detected platform → other platform → GPU opt-in → other+GPU, then stops with an error dialog listing the escape hatches. AppImage-safe relaunch via$APPIMAGE. No infinite cascades. - Sandbox pre-flight. Packaged builds check for a non-setuid
chrome-sandboxcombined with blocked unprivileged user namespaces (Ubuntu 24.04 AppArmor knob,unprivileged_userns_clone) and fall back to--no-sandboxinstead of dying silently. Root also gets--no-sandboxas Chromium requires. - Window now uses
show: false+ready-to-show(always shown, even with the watchdog disabled).
2. Icon white-fringe fix — d580139
The source icons were grayscale (mode L, no alpha at all): a black bird on a flat white field, which rendered as a white box/halo on every non-white surface (window icon, taskbar, sidebar, launchers).
frontend/public/icon.pngandfrontend/src/assets/logo.pngregenerated as RGBA: alpha = ink coverage of the original artwork; RGB forced to 0 everywhere, so no white matte can bleed through semi-transparent edge pixels (verified: 0 pixels with RGB > 200 at alpha < 20). Artwork bbox/shape unchanged (IoU 1.0 vs originals).frontend/src/styles.css:.sidebar-logodropped itsbackground: #fffwhite tile,border-radius, andobject-fit: cover; the artwork now composites directly withcontain. Dark-themeinvert(1)kept (ink artwork must flip on dark sidebars).- Originals preserved:
deferred/original-icons/icon-public-512-white.png,deferred/original-icons/logo-sidebar-338-white.png.
3. Build hygiene (uncommitted by design? no — landed with the fixes)
frontend/src/components/signer/SignerConnectionPanel.tsxwas an untracked, non-compiling WIP (brokenuseCallbackclosures, APIs that don't exist onSignerManager, dependency on uninstalledreact-router-dom) that blockednpm run typecheck. Moved intact todeferred/SignerConnectionPanel.tsx.wip(untracked) — nothing deleted; it needs a rewrite against the real hooks before returning.
Verification (all run this session)
- Rust:
cargo fmt --checkclean,cargo clippy --all-targetsclean,cargo testgreen,cargo build --releasesucceeded. - Frontend:
npm run electron:build,npm run typecheck,npm run lintclean;npm test116/116 passed;npx prettier --check electron/main.tsandsrc/styles.cssclean;npm run buildsucceeded. (5 pre-existing Prettier warnings in untouched files —ExportSecretKeyModal.tsx,SignerModeScreen.tsx,AppProvider.tsx,ExportSecretKey.test.tsx,fakeBackend.ts— predate this session and were left alone.) - On-device (Hyprland/Wayland, this machine): app launched under a clean systemd
user scope: Keynctr window mapped (
class: keynectr), watchdog marker cleared (= config proven), no new Electron core dumps after 19:40 while multiple software-render launches ran.grimscreenshot + visual inspection confirmed the sidebar bird sits directly on the sidebar with no white tile, border, or halo. - Icon proof: checkerboard composite of the new
public/icon.pngshows clean anti-aliased edges into transparency, no white fringe.
How to run / reproduce
- GUI:
cd frontend && npm start(or the packaged AppImage/deb once rebuilt vianpm run dist). - Escape hatches:
KEYNCTR_FORCE_X11=1,KEYNCTR_FORCE_WAYLAND=1,KEYNCTR_ENABLE_GPU=1,KEYNCTR_DISABLE_GPU=1,KEYNCTR_NO_RELAUNCH=1. - CLI:
cargo run --release -- serve(JSON-lines IPC) as before.
Outstanding / next steps
- Repackage for the friend:
npm run dist(AppImage + deb) with the new icon and display fixes; the oldfrontend/release/artifacts predate both commits. deferred/SignerConnectionPanel.tsx.wip: rewrite against the realuseSignerManagerAPI (+ either addreact-router-domor drop the import) before reinstating.- Consider a taskbar-visible test on a pure-X11 session and on GNOME Wayland for the friend matrix (only Hyprland/Wayland was verifiable here).
- Step 3 sub-step 2 (IPC reroute) is untouched and remains the next signer milestone.
- The user's crash-reporter still holds old core dumps from pre-fix launches
(
coredumpctl rmclears them).