feat(browser): add opt-in FPS counter overlay

feat(browser): add opt-in FPS counter overlay

#402 in DioxusLabs/blitz — merged 2026-04-27

Summary

  • Adds an opt-in FPS counter overlay to the Blitz browser UI (apps/browser), gated behind a --show-fps CLI flag.
  • Frame timing is measured via a dioxus_native::CustomPaintSource whose render method fires once per real paint — i.e. the wall-clock delta between successive RedrawRequested events, so the displayed FPS reflects actual paint cadence.
  • All changes are localized to apps/browser/; no engine packages were modified.

Addresses the "FPS counter" checklist item in #363.

Design

  • apps/browser/src/fps_overlay.rs (new) — FpsStats (60-frame ring of frame durations), FpsPaintSource (impl CustomPaintSource, records Instant::now() deltas in render(), resets on suspend()), and FpsOverlay (Dioxus component that registers the source via use_wgpu, polls the stats every 250ms, and renders a 1×1 tick canvas plus the visible HUD).
  • apps/browser/src/main.rs — parses --show-fps from std::env::args() and threads a ShowFps newtype through dioxus_native::launch_cfg's context vector. The overlay component is conditionally mounted in the chrome.
  • apps/browser/assets/browser.css.fps-overlay (fixed top-right, semi-transparent black, green monospace) and .fps-tick (1×1 invisible canvas that drives the per-frame tick). Note: the tick canvas uses opacity: 0.01 rather than 0 because blitz-paint's renderer short-circuits elements with opacity: 0, which would otherwise prevent CustomPaintSource::render from firing.
  • apps/browser/Cargo.toml — adds tokio = { workspace = true, features = ["time"] } for the 250ms polling task (already in the workspace lockfile).

Test plan

  • cargo build -p browser — clean build.
  • cargo run -p browser — overlay does NOT appear (no flag).
  • cargo run -p browser -- --show-fps — overlay appears top-right, below the urlbar.
  • Load an animated page (e.g. anything with CSS animation) — FPS rises to a steady value.
  • Load a static page — FPS settles to ~0 within ~1s.
  • Existing Alt+D / Alt+H devtools toggles still work.

🤖 Generated with Claude Code

Last updated 2026-05-14