cu-bevymon 0.15.0

A Bevy-backed Ratatui monitor for Copper.
Documentation

cu_bevymon

cu_bevymon is a Copper monitor frontend that renders the shared TUI monitor UI inside Bevy using a soft_ratatui backend uploaded into a Bevy texture.

By default, the Bevy windowed monitor uses bundled JetBrains Mono Nerd Font Mono TTF files so the Bevy rendering is much closer to the console monitor than the stock mono_8x13 backend.

It provides:

  • CuBevyMon: a CuMonitor implementation backed by the shared monitor model
  • CuBevyMonPlugin: a Bevy plugin that draws the monitor into a Bevy texture
  • CuBevyMonFontOptions: font sizing for the bundled windowed TUI renderer
  • CuBevyMonTexture and CuBevyMonPanel: the Bevy-backed monitor render surface
  • CuBevyMonSurfaceNode, CuBevyMonFocus, and CuBevyMonFocusBorder: helpers for click-to-focus split layouts
  • spawn_split_layout(...): the shared left/right split shell used by the current examples
  • CuBevyMonViewportSurface: a camera helper for syncing a 3D viewport to a Bevy UI panel

Design intent:

  • reuse the same Ratatui rendering as cu_consolemon
  • reuse the same shared LOG pane, including Copper live logs and optional stderr capture
  • integrate into existing Bevy sims like cu_rp_balancebot and cu_flight_controller
  • keep the rendering/backend split clean enough for later browser / wasm work

Recommended app structure:

  • keep Copper config backend-agnostic by pointing it at an app-local monitor alias
  • pick the actual monitor implementation in Rust with cfg(feature = "...")
  • let the Bevy host app decide layout and focus ownership

The existing flight-controller pattern is the recommended one:

// copperconfig.ron
(
    id: "monitor",
    type: "tasks::monitor::AppMonitor",
)
// src/tasks/monitor.rs
#[cfg(all(feature = "sim", not(feature = "firmware")))]
pub type AppMonitor = cu_bevymon::CuBevyMon;

#[cfg(all(feature = "terminal_sim", not(feature = "firmware")))]
pub type AppMonitor = cu_consolemon::CuConsoleMon;

#[cfg(any(feature = "firmware", not(feature = "sim")))]
pub type AppMonitor = cu_logmon::CuLogMon;

That keeps RON stable while the build target decides whether the app gets a Bevy panel, a terminal TUI, or a lighter real-target monitor.

Standard split-view pattern:

  1. Keep your sim scene camera app-owned.
  2. Recommended: render that camera to an offscreen RenderTarget::Image.
  3. Add CuBevyMonPlugin::new(model) to the Bevy app.
  4. Create a dedicated Camera2d for the split-shell UI.
  5. Call spawn_split_layout(...) with the scene camera entity and the monitor texture handle.
  6. Add app-specific overlays like loading cards, help panels, or OSD widgets as children of the returned sim_panel.
  7. Gate sim-control systems on Res<CuBevyMonFocus> while cu_bevymon routes monitor events to cu_tuimon.

Shared shell sketch:

let layout = spawn_split_layout(
    &mut commands,
    monitor_texture.0.clone(),
    CuBevyMonSplitLayoutConfig::new(scene_camera).with_ui_camera(ui_camera),
);

commands.entity(layout.sim_panel).with_children(|panel| {
    panel.spawn((
        Node {
            position_type: PositionType::Absolute,
            bottom: Val::Px(5.0),
            right: Val::Px(5.0),
            ..default()
        },
        Pickable::IGNORE,
    ));
});

The cu_bevymon_demo, cu_rp_balancebot, and cu_flight_controller examples all use that shared split shell now. The main app-specific choice is how the left-side scene camera is produced.

Render strategy guidance:

  • Use the offscreen RenderTarget::Image + ViewportNode path when the sim already has its own UI overlays, picking, or camera behavior. This is the standardized path in the current examples.
  • CuBevyMonViewportSurface still exists for simpler panel-clipped window cameras, but it is now the lower-level escape hatch, not the primary documented pattern.

Input model:

  • window focus stays with Bevy
  • logical panel focus is tracked by CuBevyMonFocus
  • cu_bevymon translates Bevy events into backend-neutral cu_tuimon::MonitorUiEvent
  • monitor bindings live in cu_tuimon, not in the Bevy adapter

Font behavior:

  • the default bundled font set is JetBrains Mono Nerd Font Mono Light / SemiBold / LightItalic
  • the default bundled font size is 24 px
  • panel resize changes how many rows and columns fit; it does not change the glyph size
  • use CuBevyMonPlugin::with_font_size(...) or CuBevyMonPlugin::with_font_options(...) to tune the Bevy-side font size
  • use CuBevyMonPlugin::with_font_options(...) for full control
  • the bundled font bytes live under assets/fonts/
  • this improves glyph coverage for the powerline tabs, symbols, arrows, and box drawing used by cu_tuimon
  • OpenType feature selection like Kitty's +zero flag is not currently exposed through this backend