feat(v0.2): shturman-splash — Stage-0 splash (software-render → PNG)
P6.2: статичный брендовый splash-кадр (wordmark «Штурман» на тёмном), render_splash через shturman-render; bin с --screenshot. Без чтения шины (стартует до Power/Settings → «мгновенно»). Визуальные токены — каркас (язык v0.5). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Alexander <akotenev2003@gmail.com>
This commit is contained in:
Generated
+13
@@ -3642,6 +3642,19 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shturman-splash"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"png 0.17.16",
|
||||||
|
"shturman-common",
|
||||||
|
"shturman-render",
|
||||||
|
"slint",
|
||||||
|
"tempfile",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.8"
|
version = "1.4.8"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ members = [
|
|||||||
"crates/core/shturman-settings",
|
"crates/core/shturman-settings",
|
||||||
"crates/core/shturman-power",
|
"crates/core/shturman-power",
|
||||||
"crates/apps/shturman-render",
|
"crates/apps/shturman-render",
|
||||||
|
"crates/apps/shturman-splash",
|
||||||
"crates/apps/shturman-shell",
|
"crates/apps/shturman-shell",
|
||||||
"crates/tools/shturman-manifest-validator",
|
"crates/tools/shturman-manifest-validator",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "shturman-splash"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
shturman-render = { path = "../shturman-render" }
|
||||||
|
shturman-common = { path = "../../shturman-common" }
|
||||||
|
anyhow.workspace = true
|
||||||
|
tracing.workspace = true
|
||||||
|
slint.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile.workspace = true
|
||||||
|
png = "0.17"
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
//! `shturman-splash` (lib) — Stage-0 splash-кадр (A05). Статичный брендовый кадр (без шины → «мгновенно»).
|
||||||
|
//! Визуальные токены — каркас (язык design-system — гейт v0.5). Спека v0.2 §6.
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
slint::slint! {
|
||||||
|
export component SplashWindow inherits Window {
|
||||||
|
in property <string> brand: "Штурман";
|
||||||
|
width: 1024px;
|
||||||
|
height: 600px;
|
||||||
|
background: #0e1014;
|
||||||
|
Text {
|
||||||
|
text: root.brand;
|
||||||
|
font-size: 64px;
|
||||||
|
color: #e8eaed;
|
||||||
|
horizontal-alignment: center;
|
||||||
|
vertical-alignment: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const W: u32 = 1024;
|
||||||
|
const H: u32 = 600;
|
||||||
|
|
||||||
|
/// Headless software-render splash-кадра в PNG (без дисплея/композитора).
|
||||||
|
pub fn render_splash(path: &Path) -> anyhow::Result<()> {
|
||||||
|
shturman_render::render_to_png(|| Ok(SplashWindow::new()?), W, H, path)?;
|
||||||
|
tracing::info!(path = %path.display(), "splash записан (software-render)");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
//! `shturman-splash` (bin) — Stage-0 splash. `--screenshot <path>` → headless PNG (VM/E2E);
|
||||||
|
//! без аргументов — интерактив (dev/HW; в v0 VM используется только screenshot-режим).
|
||||||
|
|
||||||
|
use shturman_splash::render_splash;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
shturman_common::init_tracing("shturman-splash");
|
||||||
|
match parse_screenshot_arg() {
|
||||||
|
Some(path) => {
|
||||||
|
render_splash(&path)?;
|
||||||
|
println!("{}", path.display());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// интерактив придёт с живым дисплеем (v0.5); в v0 VM splash — только screenshot.
|
||||||
|
anyhow::bail!("ожидался --screenshot <path> (интерактивный splash — v0.5)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Разобрать `--screenshot <path>` / `--screenshot=<path>` (без внешних зависимостей).
|
||||||
|
fn parse_screenshot_arg() -> Option<PathBuf> {
|
||||||
|
let mut args = std::env::args().skip(1);
|
||||||
|
while let Some(a) = args.next() {
|
||||||
|
if a == "--screenshot" {
|
||||||
|
return args.next().map(PathBuf::from);
|
||||||
|
}
|
||||||
|
if let Some(p) = a.strip_prefix("--screenshot=") {
|
||||||
|
return Some(PathBuf::from(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//! Splash-кадр Stage 0: непустой брендовый PNG, тёмный фон (План 6 P6.2 / спека v0.2 §6).
|
||||||
|
|
||||||
|
use shturman_splash::render_splash;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn renders_dark_branded_splash() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let path = dir.path().join("splash.png");
|
||||||
|
render_splash(&path).expect("render_splash");
|
||||||
|
|
||||||
|
let dec = png::Decoder::new(std::fs::File::open(&path).unwrap());
|
||||||
|
let mut r = dec.read_info().unwrap();
|
||||||
|
assert_eq!((r.info().width, r.info().height), (1024, 600));
|
||||||
|
let mut buf = vec![0u8; r.output_buffer_size()];
|
||||||
|
let info = r.next_frame(&mut buf).unwrap();
|
||||||
|
let px = &buf[..info.buffer_size()];
|
||||||
|
// фон тёмный (угол) + не одноцветный (wordmark отрисован)
|
||||||
|
assert!(
|
||||||
|
px[0] < 64 && px[1] < 64 && px[2] < 64,
|
||||||
|
"splash фон не тёмный: {},{},{}",
|
||||||
|
px[0],
|
||||||
|
px[1],
|
||||||
|
px[2]
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
px.iter().any(|&b| b != px[0]),
|
||||||
|
"splash одноцветный — wordmark не отрисован"
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user