UI scenarios: named views (save the view from the browser, change it, restore it); targets written ahead of their features, ignored until they land: sheet metal Fold, configurations, motion study, autosave and recovery. Harness: note steps, named-view and camera checks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-08 11:04:35 +00:00
1 parent 829c4a2811
commit 2a54c83bf8
7 files changed
+271 -1

No files matched your search

+18
View File
@@ -18,6 +18,7 @@
//! into `$SOLVECRAFT_SCENARIO_SHOTS` when that is set; `{"debug": 1}`
//! prints the UI state
//! - AT may also be `{"plane": "XY"}`: the middle of an origin plane's square
//! - `{"note": "…"}`: a comment
//! - `{"expect": {…}}`: checks, see [`check`]; `{"until": {…}}` waits (frames) until they pass
//!
//! The same files drive the live app over the control channel for screenshots.
@@ -226,6 +227,8 @@ impl Harness {
self.call("ui.drag", json!({"x0": x0, "y0": y0, "x1": x1, "y1": y1, "steps": steps, "shift": flag("shift")}))
} else if let Some(m) = s.get("call").and_then(Value::as_str) {
self.call(m, s.get("params").cloned().unwrap_or(json!({})))
} else if s.get("note").is_some() {
return Ok(());
} else if let Some(name) = s.get("shot").and_then(Value::as_str) {
// With SOLVECRAFT_SCENARIO_SHOTS set: a render of the model as the camera sees it.
if let Ok(dir) = std::env::var("SOLVECRAFT_SCENARIO_SHOTS") {
@@ -428,6 +431,21 @@ pub fn check(h: &mut Harness, e: &Value) -> Result<(), String> {
return Err(format!("section view: want {v}"));
}
}
"camera_matches" => {
// The camera is at the saved named view (yaw, pitch, target).
let n = v.as_str().unwrap_or_default();
let nv = h.app.session.doc.named_views.iter().find(|x| x.name == n).ok_or_else(|| format!("no named view {n}"))?;
let c = &h.app.cam;
if (c.yaw - nv.yaw).abs() > 1e-6 || (c.pitch - nv.pitch).abs() > 1e-6 || c.target.dist(nv.target) > 1e-6 {
return Err(format!("camera is not at view {n}: yaw {} pitch {}, view yaw {} pitch {}", c.yaw, c.pitch, nv.yaw, nv.pitch));
}
}
"named_views" => {
let n = h.app.session.doc.named_views.len();
if v.as_u64() != Some(n as u64) {
return Err(format!("named views: got {n}, want {v}"));
}
}
"home" => {
if ui["home"] != *v {
return Err(format!("start page open: got {}, want {v}", ui["home"]));