1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 04:40:03 -04:00
Files
egui/crates/egui_inspection
Lucas Meurer 33c85bd62a Untangle logic-only frames: one frame entry point, one output type
Same fixes as the previous commits (run no egui pass at all when
nothing will be shown), but the mechanisms are shared instead of
duplicated:

* `Context::run_frame(input, show_ui, f)` is the one entry point for
  integrations: one `FramePhase::Logic` (always, outside any pass),
  then one `FramePhase::Ui` per pass (none when `show_ui` is false).
  `Context::run_logic` is now a thin wrapper around it, and the
  logic-outside-of-pass sequencing lives in egui, not in each backend.

* egui itself buffers the input of pass-less frames
  (`ViewportState::pending_raw_input`) and prepends it to the next
  pass. This replaces `EpiIntegration::pending_raw_input` and the web
  backend's `input.raw.append`, so an integration cannot lose input.

* `FullOutput` is now `{ platform_output, viewport_commands,
  pass_output: Option<PassOutput> }`, and `LogicOutput` is gone.
  One-shot viewport commands (imperative) are separated from
  `ViewportOutput` (which viewports should exist - declarative), so
  each backend has exactly one command-handling path, shared by frames
  with and without a pass. `pass_output: None` encodes "no pass ran:
  paint nothing, leave the viewports alone" in the type.

* The glow/wgpu `!show_ui` early-return blocks are gone: a hidden root
  viewport flows through the same tail as a visible one, with the
  paint and viewport-structure steps gated on `pass_output`.

Behavioral fixes that fall out:

* `App::logic` now sees the current window state in visible frames
  too (it was one frame stale outside the hidden path).
* Auto-save keeps working while a window is minimized or occluded.
* Commands sent to a freshly created viewport apply in the same frame.
* The Wayland resize workaround now also covers commands from
  pass-less frames.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 19:09:17 +02:00
..

egui_inspection

Latest version Documentation

Inspection for egui apps.

egui_inspection defines a wire protocol and an [egui::Plugin] (InspectionPlugin) that serves it. An external inspector — such as the egui_mcp MCP server — connects and can:

  • read the app's AccessKit tree (GetTree),
  • inject input events (HandleEvents — clicks, typing, scrolling, …),
  • capture a screenshot on request (Screenshot),
  • resize the window (Resize).

The protocol is strictly request → response, which maps cleanly onto both a TCP socket and a unary RPC (so the same machinery can be tunnelled over another transport).

Screenshots need a visible window. Reading the tree and injecting input work even while the app is in the background, but capturing a screenshot requires a rendered frame — which the OS won't produce for a fully-occluded or minimized window (notably on macOS, where the GPU surface isn't available). Bring the window to the foreground to capture it; the Screenshot request times out otherwise.

What it's for

egui_inspection is the shared foundation for tools that observe or drive an egui app from the outside. Anything that speaks the protocol (over TCP, or another transport) can be a consumer:

  • egui_mcp — an MCP server that exposes the app to AI agents and other tooling: query the widget tree, click / type / scroll, take screenshots.
  • An egui inspector GUI (planned) — a visual debugger that connects to a running app to browse its widget tree and drive it interactively.
  • Test inspection & frame streaming (planned) — attach to egui_kittest tests, and stream frames for live mirroring of an app's window.

Enabling it in an eframe app

Enable eframe's inspection feature, then set the EGUI_INSPECTION env var at runtime. It's either truthy, falsy, or a bind address:

EGUI_INSPECTION=1 cargo run --features inspection            # binds 127.0.0.1:5719
EGUI_INSPECTION=0.0.0.0:5719 cargo run --features inspection # reachable across devices

When the variable is unset or falsy (0 / false), inspection is completely off (production-safe).

⚠️ Binding a non-loopback address exposes full control of the app — and its screenshots — to anyone who can reach the port, with no authentication. A warning is logged when you do so. Prefer loopback + an SSH tunnel for remote debugging.

Using the plugin directly

# let ctx = egui::Context::default();
ctx.add_plugin(egui_inspection::InspectionPlugin::new(Some("my app".to_owned())));
egui_inspection::serve(&ctx, "127.0.0.1:5719").unwrap();