Skip to content

feat(egui): port the front-end to egui with pixel parity against Tauri - #89

Draft
klNuno wants to merge 56 commits into
mainfrom
boite/evaluate-switch-to-egui
Draft

klNuno wants to merge 56 commits into
mainfrom
boite/evaluate-switch-to-egui

Conversation

@klNuno

@klNuno klNuno commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Note

Clanker Claude Opus 5.5 is responding on behalf of meetsu

Summary

the whole front-end is being ported to egui, one screen at a time, each checked pixel by pixel against the Tauri build so the switch can ship as a normal update. work in progress, not ready to merge.

settings, General tab at 150 %: Tauri on top, egui below

  • crates/accshift-app holds the logic without UI: the backend trait with mock and real implementations, stores, i18n, account pipeline, actions, secure flows, and the lifecycle (updater on the same latest.json and key, single instance, deep links). 592 tests.
  • crates/accshift-egui holds the UI: title bar, workspace grid with folder, back and full account cards (CS2 bridge badge, armed state) and the hover extension panel (warnings, note, CS2 level), the list view with its preview panel and sliding sections, the search field with Chromium's own clear button, the settings panel with its General, Platforms and Privacy tabs and the descriptor preview dialog, toasts, the context menu, the input and confirm dialogs, the command palette, the secure screen (PIN lock, AFK cover with the waving wordmark) and the streamer mode overlay.
  • dialogs, the secure screen and the glass card extension blur what is behind them like backdrop-filter and filter: blur(), through a layer pass added to the vendored software rasterizer; the card's blur is cropped to its rounded box like Chromium's.
  • text-shadow glows are rasterized from the glyph atlas and blurred the way Skia does (ui::text_shadow).
  • buttons ease only the colours their CSS transition lists, the rest switches at once (controls::button).
  • Steam avatars are JPEG: they are decoded, cropped to their centre square and scaled down the way Skia does (app/avatars.rs, ui::resample).
  • keys go through the app's binding table from accshift-app before any widget reads them, so Ctrl+K, Escape, Ctrl+Tab, Ctrl+F and the swallowed WebView shortcuts behave like the Tauri build; the arrows move a focus ring across the cards and Enter, F2 and Delete act on it.
  • text fields take Blink's intrinsic size=20 width from the font and put the caret where Blink rounds it (TextStyle::text_field_width, controls::text_input).
  • the list preview column shrinks its avatar and username like Blink's flex shrink when a note and the active label overflow it.
  • crates/accshift-egui/parity captures the Tauri app at the real device scale factor and diffs it against egui frames.
  • text goes through DirectWrite with Skia's settings from WebView2, through a vendored epaint with a rasterizer hook and OpenType features for the shaper (tabular-nums maps to tnum).
  • boxes, borders and layout snap to the device grid the way Chromium does at 125 % and 150 %.
area PSNR against Tauri
typography, 1x to 1.5x 54.9 to 67.8 dB
title bar, 1x and 1.5x 41.8 dB and up
settings, 22 shots 39.3 to 49.9 dB
settings Platforms tab (chips, startup select, search, no match, scrolled, English and French), 21 shots 47.9 to 50.4 dB, mean 49.1
descriptor preview dialog, 7 shots 50.6 to 59.0 dB, mean 54.4
workspace grid, 40 shots 43.6 to 53.7 dB, mean 48.0 (what is left is avatar edge antialiasing, resvg against Skia)
card extension panel, 20 shots 43.2 to 48.2 dB
CS2 bridge badge and panel, 16 shots 43.3 to 48.0 dB, mean 45.9
armed cards (blurred initials, confirm hint), 8 shots 45.5 to 48.2 dB, mean 46.5
context menu, 32 shots 45.1 to 47.6 dB
input and confirm dialogs, 24 shots 45.2 to 57.6 dB, mean 52.0
list view, 24 shots 46.5 to 51.0 dB, mean 48.9
Steam JPEG avatars in the grid, list and preview, 16 shots 45.8 to 50.5 dB
command palette (idle, scrolled to the end, hover, typed, no match), 20 shots 48.4 to 52.3 dB
arrow-key card focus (grid, sections, banned and active cards, menu, rename, list), 50 shots 45.0 to 57.2 dB, mean 47.1
PIN lock, 16 shots 47.1 to 49.3 dB, mean 48.1
AFK cover, 8 shots 42.3 to 46.7 dB
streamer mode overlay, 16 shots 47.6 to 51.7 dB, mean 49.6

the Tauri side of the card focus was broken on main and is fixed in #95; this branch carries the same TS files so its references show the fixed behaviour.

to question: epaint is vendored for the glyph hook (upstream has no rasterizer extension point); it also lets trailing spaces hang past the wrap width, as CSS does, and passes a job's OpenType features to harfrust. the search clear button ships Chromium's two 28 px bitmaps under their BSD license, in assets/chromium.

Related issue

none

Tested on

  • Windows
  • macOS
  • Linux

Checklist

  • CI checks pass locally: clippy on both renderers, rustfmt, cargo test in both new crates
  • Docs or wiki updated if the change is user-facing: not shipped yet
  • No secrets, session tokens or captured account data in the diff

not verified: the glow renderer against the references, macOS and Linux builds, an update from a Tauri install in a VM, the AFK and streamer waves and the card extension's open and close in motion (scenes run with animations off), the link and chip actions inside the extension (no mock account has one).

known difference: after the AFK cover leaves, WebView2 keeps the app rastered at its obscured scale(1.01) and the text stays soft (still the case 1.8 s later); egui is sharp again at once.

more captures

Platforms tab with the platform chips and the startup select, light theme at 150 %: Tauri on top, egui below

Platforms search with no match and the caret after the query, French, light theme at 150 %: Tauri on top, egui below

descriptor preview before adding a platform from a file, light theme at 150 %: Tauri on top, egui below

Right, Right, Down moves the card focus ring to lan party, dark glass theme at 150 %: Tauri on top, egui below

the command palette after ArrowUp wrapped to its last row, dark glass theme at 150 %: Tauri on top, egui below

a JPEG avatar in the list and its preview, whose avatar shrinks to fit the note, dark glass theme at 150 %: Tauri on top, egui below

hovering the main card opens its note and CS2 level panel, dark glass theme at 150 %: Tauri on top, egui below

an armed card without avatar: blurred initials and the wrapped confirm hint, light theme at 150 %: Tauri on top, egui below

hovering a VAC-banned card opens its warnings panel, dark glass theme at 150 %: Tauri on top, egui below

the last card's note panel opens to the left near the window edge, light theme at 100 %: Tauri on top, egui below

streamer mode overlay with the pointer on Disable, dark glass theme at 150 %: Tauri on top, egui below

PIN lock while typing, dark glass theme at 150 %: Tauri on top, egui below

AFK cover with the wordmark and version strip, dark glass theme at 150 %: Tauri on top, egui below

list view with the selected account's preview, dark glass theme at 150 %: Tauri on top, egui below

list view with folder sections, light theme at 100 %: Tauri on top, egui below

forget-account confirm over the blurred grid, dark glass theme at 150 %: Tauri on top, egui below

privacy tab, light theme at 100 %: Tauri on top, egui below

workspace grid at 150 %: Tauri on top, egui below

search field with a query at 150 %: Tauri on top, egui below

worst typography line at 125 %: Tauri on top, egui below

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@klNuno klNuno changed the title chore(spike): main screen in egui, with startup bench and captures chore(spike): main screen in egui, CPU renderer, startup bench and captures Oct 11, 2026
klNuno added 26 commits October 11, 2026 13:29
@klNuno klNuno changed the title chore(spike): main screen in egui, CPU renderer, startup bench and captures feat(egui): port the front-end to egui with pixel parity against Tauri Oct 12, 2026
async function dumpDom(page, scene, outDir, step) {
const select = step.select ?? "body *";
const rows =
await page.js(`(() => Array.from(document.querySelectorAll(${JSON.stringify(select)}), (el) => {
focusVisible: el.matches(":focus-visible"),
hover: el.matches(":hover"),
rect: [r.x, r.y, r.width, r.height],
css: Object.fromEntries(${JSON.stringify(DOM_PROPS)}.map((p) => [p, cs[p]])),
/// `triggerCs2BridgeCheck(steamId)` (lines 89-115): App.svelte reacts to
/// `LoadingEvent::Cs2Check` with this.
pub fn check(&mut self, steam_id: impl Into<String>) {
self.queue.push_back(Cs2Operation::Check(steam_id.into()));
return false;
}
self.load_in_flight = true;
self.queue.push_back(Cs2Operation::Load);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants