Repository navigation
feat(egui): prototype Input Viewer on Rust and egui, with ADRs for the port - #346
Merged
Merged
Conversation
A native rewrite prototype in input_viewer_egui/, built to test #249's objections to leaving Electron. - Dual/single view, Multi-view, pickers over the wall, legend, shortcuts from one table, logo column and side borders, Settings (Inputs, Layout) writing settings.json in Electron's format and importing it once. - Capture via nokhwa, one session per device, health and reopen, test-mode flags (--mock, --no-signal, --screensaver-delay). - Plasma screensaver and its post-FX chain running the Electron GLSL unchanged on eframe's glow backend (shaders/extract.mjs). - --test-pattern and --hud: two 3840x2160@60 inputs render at 60 fps with no skipped frames on an M3 Pro; trilinear mipmaps fix moire at 1.8x+ downscale. - Velopack auto-update from egui-v* releases, never marked latest. Not tested against the wall's Elgato cards or on Windows yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- release-egui.yml: manual release of egui-v* tags with Velopack installers for Windows and macOS, published with make_latest false so electron-updater keeps resolving the Electron release. Pull requests touching input_viewer_egui/ get a build-only packaging check. - release.yml: find the last Electron tag with --match 'v[0-9]*', so an egui-v* tag never becomes the baseline for commit analysis. - ci.yml: cargo test and release build for input_viewer_egui on macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 ADRs in docs/adr/, reconstructed from the code, issues and PRs, each with a Porting to egui verdict and the prototype's status. The index is the port's status board and suggested order; open-questions.md lists product decisions to make, Electron defects and doc drift found on the way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Windows: the checkout is CRLF, so the perl pattern anchored on a bare
\n matched nothing, Cargo.lock kept 0.0.0 while Cargo.toml changed,
and `cargo test --locked` refused to run. Stamping moves into
packaging/set-version.sh: every pattern allows \r, and it checks the
crate's own entries afterwards instead of trusting the rewrite.
- macOS: vpk rejected 0.0.0-pr.N ("must be >= 0.0.1"). A pre-release
sorts below its release, so PR builds are now a pre-release of the
next minor, e.g. 0.1.0-pr.346.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 12, 2026
4 of 5 tasks
…hidden health.rs is now a line-for-line port of stream-health.js: the same seven statuses, thresholds and fault/dark backoff schedules, with its unit tests ported case for case (ADRs 0012, 0013). - Sampled every 2 s per device from the frame counter and the luma of a box-averaged 384x216 thumbnail; a stream error is acted on at once. - A reopen drops the stream to close the device and opens it again after a 500 ms release gap; attempts survive the reopen so the backoff backs off and resets after 60 s healthy. - As in Electron, only a failed open (or a missing, disabled or forced input) puts the NO SIGNAL board up. A dark or stalled card is reopened and stays black meanwhile, instead of showing the board as before. - Device polling, stream sync, health, screensaver timing and settings saves move from ui() to App::logic(), which eframe keeps calling while the window is hidden or covered. With them in ui(), a covered window stopped recovering its inputs entirely (ADR 0052). - --mock-fault=dark|stall|fail breaks the last mock input, to watch the policy work: verified for all three. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sson - 0012, 0013: done, with the measured --mock-fault behaviour. - 0019: the board shows for a failed open, not for a dark card -- so without reference detection a wall of dark cards shows black, never the board or a screensaver, as Electron does today. - 0052 (new, egui-only): work that must not stop runs in App::logic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
filelog.rs is a port of src/main/file-log.js with its tests: one file per local day in <config>/Input Viewer (egui)/logs, 7 days kept, 20 MB/day, 600 lines/min, 2000-character lines, synchronous appends, and a log that disables itself rather than ever failing the app (ADR 0044). - Every line now goes to stderr and the file, with levels matching Electron's console.log/warn/error and its tags where an equivalent exists ([Health], [AutoUpdater], [TestFlags], [Settings]). - [Health] lines use describeHealth()'s exact format, one per half that shows the device, so the lines labs-videowall-config documents still match: transitions, the reopen line, the opened line, the 10-minute summary, and "monitoring every 2000ms". - A startup banner with OS uptime, a GPU line (vendor / renderer / GL version, in place of gpu-report.txt), and a panic hook that puts the panic in the file. Adds chrono (local time; `time` cannot read the local offset safely in a multi-threaded process on Unix) and sysinfo (OS version and uptime). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0044 records what the egui log writes, where it differs from Electron's (the [app] source tag, the reopen line's id) and what is not ported (fps-report.txt, the detection diagnostic, __health()). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0002 and 0048 said the installers had not been built in CI; both now build, with distinct file names per platform. Publishing and updating remain untested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the wall both Elgato 4K60 Pro MK.2 cards delivered ~13 fps to the egui prototype, while Electron, on the same cards with nothing connected, negotiated 3840x2160 @ 59.94 and measured 60 fps. The cards offer 4K only as YUY2, with a ladder of frame rates down to 1 fps. Three bugs in nokhwa's Media Foundation bindings, vendored and patched (vendor/nokhwa-bindings-windows, PATCHED.md, wired in by [patch.crates-io]): - fractional rates were zeroed, so 59.94 (60000/1001) never made the list; - set_format matched a type by its range but set it as is, with its own MF_MT_FRAME_RATE -- possibly a low rung of the ladder; - the current rate was read as the denominator (60000/1001 -> "1001"). Also logs the negotiated pixel format and rate, and once per 120 frames how long a frame spends waiting for the card versus converting to RGBA, so the next wall run shows directly whether the conversion is the next limit. Type-checked for x86_64-pc-windows-msvc; not yet run on the wall. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wall's Elgato cards offer 3840x2160 only as YUY2. With the frame rate fixed they negotiate 60 fps, but converting each frame to RGBA on one CPU core took ~49 ms on the wall and still capped capture at ~12 fps (measured 2026-10-12, "per frame 20 ms waiting for the card, 49 ms converting"). - YUY2 frames now cross from the capture thread as the card's own bytes (half the size of RGBA) and are converted by a shader: uploaded as a half-width RGBA8 texture, one texel per pixel pair, then written into a full-size texture egui draws, with mipmaps (gpu_video.rs). BT.709 limited range; yuv.rs holds the same formula on the CPU, with tests. - The health check reads brightness straight from the Y bytes. - --test-pattern now emits YUY2 like the cards, converted on all cores, so it exercises the same path: two 4K60 inputs at 60 fps on an M3 Pro, colours and orientation checked in a screenshot. - Other pixel formats keep the CPU path; if the shader cannot be set up, YUY2 falls back to a CPU conversion so a picture still shows. Not yet run on the wall. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
A Rust/egui prototype of Input Viewer, plus 52 ADRs recording the Electron app's decisions so the port can go one decision at a time. The Electron app is untouched except one line in
release.yml.What's in it
input_viewer_egui/: the prototype.settings.jsonin Electron's format.stream-health.js.file-log.js.--mock,--no-signal,--test-pattern,--hud,--mock-fault.docs/adr/: the ADRs. Each has an egui verdict and the prototype's status. The index is the port's status board. open-questions.md lists decisions to make and the Electron defects (filed as bug: low-resolution capture retry requests audio with the video device id #347-release: confirm a macOS client actually auto-updates #361).release-egui.yml: egui installers via Velopack, taggedegui-v*, never marked latest, so electron-updater is unaffected.ci.yml: an egui test-and-build job.release.yml:git describe --match 'v[0-9]*', so egui tags never become the Electron release's baseline.Verified
cargo test(71) andcargo clippycleanSetup.exeand macOSSetup.pkgbuild in CI, with distinct file names per platformBefore merging
The squash title starts with
feat(...). The Electron release analysis isn't path-aware, so its next release would compute a minor bump. Merge under a non-bumping title, or pick the bump explicitly at the next Electron release.🤖 Generated with Claude Code