Add bread-screenshots + bread-capture: foundation for UI screenshot tooling

New bread-screenshots crate captures a layer-shell surface (by namespace+pid,
to disambiguate from an already-running instance) or the whole focused
output via grim, using bread-utils::hypr/proc. bread-utils::Monitor gains a
scale field and logical_size() so output geometry accounts for HiDPI/
transform, matching breadshot's proven math. bread-utils::hypr gains
find_layer() over hyprctl layers -j.

bread-capture is a small orchestrator that drives an app's --screenshot mode
and collects the resulting PNGs; hardcoded to breadbar's two views for now.
This commit is contained in:
Breadway 2026-07-23 14:15:49 +08:00
parent 77bca8a1cf
commit 007082374d
7 changed files with 301 additions and 1 deletions

58
bread-capture/src/main.rs Normal file
View file

@ -0,0 +1,58 @@
//! Orchestrator for the bread ecosystem's UI screenshot tooling.
//!
//! Drives each target app's `--screenshot <view> --output <path>` mode (see
//! `bread-screenshots` for what that mode does inside the app) and reports
//! pass/fail per view. Foundation-phase scope: one target (breadbar), a
//! hardcoded view list, and a flat output directory — no versioned
//! `screenshots/vX.Y.Z/latest` structure or manifest file yet, since those
//! only earn their complexity once more apps are wired up.
use anyhow::Result;
use clap::Parser;
use std::path::PathBuf;
use std::time::Duration;
const CAPTURE_TIMEOUT: Duration = Duration::from_secs(10);
/// (view name, output filename)
const BREADBAR_TARGETS: &[(&str, &str)] = &[
("bar", "breadbar-bar.png"),
("control-panel", "breadbar-control-panel.png"),
];
#[derive(Parser)]
struct Cli {
/// Path to the breadbar binary (resolved via $PATH if not a path).
#[arg(long, default_value = "breadbar")]
app_path: String,
/// Directory to write captured PNGs into.
#[arg(long, default_value = "./screenshots")]
out_dir: PathBuf,
}
fn main() -> Result<()> {
let cli = Cli::parse();
let mut failed = false;
for (view, filename) in BREADBAR_TARGETS {
let out_path = cli.out_dir.join(filename);
let out_str = out_path.to_string_lossy();
let result = bread_utils::proc::run(
&cli.app_path,
&["--screenshot", view, "--output", &out_str],
CAPTURE_TIMEOUT,
);
if result.success {
println!("ok breadbar/{view} -> {}", out_path.display());
} else {
failed = true;
println!("FAIL breadbar/{view}: {}", result.stderr.trim());
}
}
if failed {
std::process::exit(1);
}
Ok(())
}