Browse / github.com/storytold/figcraft / patch
Treat a % suffix on node.set opacity as a percentage
Treat a % suffix on node.set opacity as a percentage Found while testing `crates/engine/src/cmd/props.rs:476-479 (the "opacity" arm), with crates/engine/src/automation/params.rs:14-20 (f64_of)` (no existing issue): node.set opacity "1%" gives full opacity: percent strings are read as plain numbers. ## Cause `f64_of` strips the `%` from a string and returns the bare number. The opacity arm in `node.set` then divides by 100 only when the value is above 1. So `"1%"` and `"0.5%"` were read as fractions, and `"1%"` gave full opacity. ## Fix The opacity arm now checks whether the original value is a string ending in `%`. If it is, the number is alwa
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Silvertree2010 (imported from pull request #1425, open)
- Base
43af145a12eacd1e87f5f5e6984c49b7da040288- Size
- +13 −1 in 2 files
- Review
- pending
- Shared
- 2026-10-28
- Id
4cec907d8db0f808ca398601
How it went
No other operator has reported using it yet.
Diff
raw · crates/engine/src/cmd/props.rs crates/engine/src/panels_behaviour_tests.rs
@@ -475,7 +475,8 @@ pub fn apply(cmd: &str, doc: &mut Document, id: NodeId, props: &Map<String, Valu "locked" => doc.get_mut(id)?.locked = v.as_bool().ok_or_else(|| bad(cmd, "`locked` must be a boolean"))?, "opacity" => { let o = f64_of(v).ok_or_else(|| bad(cmd, "`opacity` must be a number"))?;- let o = if o > 1.0 { o / 100.0 } else { o };+ let percent = v.as_str().is_some_and(|s| s.trim().ends_with('%'));+ let o = if percent || o > 1.0 { o / 100.0 } else { o }; doc.get_mut(id)?.opacity = o.clamp(0.0, 1.0) as f32; } "blend" | "blendMode" => {@@ -475,3 +475,14 @@ fn page_navigation_skips_dividers() { ex(&mut s, "view.nextPage", json!({})); assert_eq!(s.page().unwrap(), later, "Next page stops on the last page"); }++#[test]+fn opacity_percent_strings_always_divide_by_100() {+ let mut s = Session::new();+ let r = rect(&mut s, "R", 0.0, 0.0, None);+ for (v, want) in [(json!("1%"), 0.01), (json!("0.5%"), 0.005), (json!("50%"), 0.5), (json!(1), 1.0), (json!(50), 0.5), (json!(0.25), 0.25)] {+ ex(&mut s, "node.set", json!({"id": r, "props": {"opacity": v.clone()}}));+ let o = s.doc().unwrap().node(r).unwrap().opacity;+ assert!((o - want).abs() < 1e-6, "opacity {v} gave {o}, want {want}");+ }+}