feat(kiosk): graphics tiers + Settings knob; network map kiosk mode
Demo images / Build & push demo images (push) Successful in 3m51s
Demo images / Build & push demo images (push) Successful in 3m51s
The animated federation map froze the framework-pt 4K TV: the launcher held every machine to the HD 5500-era choppy-audio flags (single raster thread, GpuRasterization banned) while the map wrote SVG attrs at 60fps. - Launcher: two flag tiers. legacy = the proven conservative set; modern (Intel gen8+, 'NNth Gen' models, AMD Ryzen) = default raster threads + GPU rasterization. Classified from /proc/cpuinfo (11 model strings covered by tests in-session); KIOSK_GRAPHICS=performance|quality in kiosk-display.conf overrides; headless unchanged. Reaches deployed kiosks via the include_str! self-heal, same as the vsync fix. - system.kiosk-display.get/set: carries a 'graphics' field alongside 'preset'; setting one no longer clobbers the other. - Settings → Display: Graphics picker (Auto / Compatibility / Quality). - NetworkMap3D: kiosks default to the 2D projection (remembered toggle still works) and tick at half rate with carried-over deltas — same spin speed, half the paint cost. - Changelog: curated Unreleased notes for all of the above + the gate frame-embedding fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
6672d978f7
commit
9243babcdb
@@ -1268,7 +1268,14 @@ impl RpcHandler {
|
||||
} else {
|
||||
"auto"
|
||||
};
|
||||
Ok(serde_json::json!({ "has_kiosk": has_kiosk, "preset": preset }))
|
||||
let graphics = if conf.contains("KIOSK_GRAPHICS=performance") {
|
||||
"performance"
|
||||
} else if conf.contains("KIOSK_GRAPHICS=quality") {
|
||||
"quality"
|
||||
} else {
|
||||
"auto"
|
||||
};
|
||||
Ok(serde_json::json!({ "has_kiosk": has_kiosk, "preset": preset, "graphics": graphics }))
|
||||
}
|
||||
|
||||
/// system.kiosk-display.set — Write the kiosk display preset and restart
|
||||
@@ -1279,24 +1286,56 @@ impl RpcHandler {
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.ok_or_else(|| anyhow::anyhow!("Missing params"))?;
|
||||
let preset = params
|
||||
.get("preset")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing preset"))?;
|
||||
let preset = params.get("preset").and_then(|v| v.as_str());
|
||||
let graphics = params.get("graphics").and_then(|v| v.as_str());
|
||||
if preset.is_none() && graphics.is_none() {
|
||||
anyhow::bail!("Missing preset or graphics");
|
||||
}
|
||||
|
||||
let conf = match preset {
|
||||
// The conf carries two independent settings (display scale preset +
|
||||
// graphics tier). A set of one must not clobber the other, so the
|
||||
// half not being changed is carried over from the file as-is.
|
||||
let existing = tokio::fs::read_to_string(KIOSK_DISPLAY_CONF)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
let display_part = match preset {
|
||||
// Resolution-derived default: 4K -> 2.0 (1920-wide layout),
|
||||
// 1080p TV -> 1.5, laptop panels -> 1.0.
|
||||
"auto" => String::new(),
|
||||
Some("auto") => String::new(),
|
||||
// Biggest UI: every panel targets a 1280-wide layout.
|
||||
"large" => "ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH=1280\n".to_string(),
|
||||
Some("large") => "ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH=1280\n".to_string(),
|
||||
// Full-HD layout on any panel that can carry it.
|
||||
"balanced" => "ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH=1920\n".to_string(),
|
||||
Some("balanced") => "ARCHIPELAGO_KIOSK_TARGET_CSS_WIDTH=1920\n".to_string(),
|
||||
// No scaling: native CSS viewport, most content, smallest UI.
|
||||
"native" => "ARCHIPELAGO_KIOSK_SCALE=1\n".to_string(),
|
||||
other => anyhow::bail!("Unknown display preset: {other}"),
|
||||
Some("native") => "ARCHIPELAGO_KIOSK_SCALE=1\n".to_string(),
|
||||
Some(other) => anyhow::bail!("Unknown display preset: {other}"),
|
||||
None => existing
|
||||
.lines()
|
||||
.filter(|l| l.starts_with("ARCHIPELAGO_KIOSK_"))
|
||||
.map(|l| format!("{l}\n"))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let graphics_part = match graphics {
|
||||
// Auto: the launcher classifies the hardware itself (CPU/iGPU
|
||||
// generation) — legacy boxes keep the choppy-audio-safe flags,
|
||||
// modern iGPUs get GPU rasterization.
|
||||
Some("auto") => String::new(),
|
||||
// Force the conservative legacy flag set (troubleshooting).
|
||||
Some("performance") => "KIOSK_GRAPHICS=performance\n".to_string(),
|
||||
// Force the modern flag set even on unclassified hardware.
|
||||
Some("quality") => "KIOSK_GRAPHICS=quality\n".to_string(),
|
||||
Some(other) => anyhow::bail!("Unknown graphics mode: {other}"),
|
||||
None => existing
|
||||
.lines()
|
||||
.find(|l| l.starts_with("KIOSK_GRAPHICS="))
|
||||
.map(|l| format!("{l}\n"))
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
let conf = format!("{display_part}{graphics_part}");
|
||||
|
||||
host_sudo(&["/usr/bin/mkdir", "-p", "/etc/archipelago"]).await?;
|
||||
if conf.is_empty() {
|
||||
let _ = host_sudo(&["/usr/bin/rm", "-f", KIOSK_DISPLAY_CONF]).await;
|
||||
@@ -1332,8 +1371,8 @@ impl RpcHandler {
|
||||
])
|
||||
.await;
|
||||
|
||||
info!(preset, "Kiosk display preset applied");
|
||||
Ok(serde_json::json!({ "preset": preset, "applied": true }))
|
||||
info!(?preset, ?graphics, "Kiosk display settings applied");
|
||||
Ok(serde_json::json!({ "preset": preset, "graphics": graphics, "applied": true }))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user