From 9a7e5d1a1634a927895cd2c1d116523e322dfe82 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sat, 31 Oct 2026 15:37:18 +0100 Subject: [PATCH] Apply paint opacity to CSS gradient stops in code export (#1750) Found while testing crates/engine/src/dev/codegen/css.rs:121 (css_decls, the PaintKind::Gradient arm calling css_gradient at :255) Co-authored-by: Claude Haiku 5.5 --- crates/engine/src/dev/codegen.rs | 12 ++++++++++++ crates/engine/src/dev/codegen/css.rs | 11 ++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/dev/codegen.rs b/crates/engine/src/dev/codegen.rs index 55786d52d..925acdd0a 100644 --- a/crates/engine/src/dev/codegen.rs +++ b/crates/engine/src/dev/codegen.rs @@ -494,6 +494,18 @@ mod tests { f } + #[test] + fn css_gradient_folds_in_paint_opacity() { + let mut s = Session::new(); + let f = id_of(&s.execute("frame.create", &json!({"x": 0, "y": 0, "width": 200, "height": 100})).unwrap()["id"]).unwrap(); + let mut p = figcraft_color::Paint::gradient(figcraft_color::Gradient::default_for(figcraft_color::GradientKind::Linear, Color::BLACK)); + p.opacity = 0.5; + s.doc_mut().unwrap().get_mut(f).unwrap().fills = vec![p]; + let css = code_for(s.doc().unwrap(), f, CodeLang::Css); + assert!(css.contains("rgba(0, 0, 0, 0.50) 0%"), "{css}"); + assert!(!css.contains("#000000 0%"), "{css}"); + } + #[test] fn swiftui_and_compose_for_an_auto_layout_card() { let mut s = Session::new(); diff --git a/crates/engine/src/dev/codegen/css.rs b/crates/engine/src/dev/codegen/css.rs index 0e07f0bf1..087eb7905 100644 --- a/crates/engine/src/dev/codegen/css.rs +++ b/crates/engine/src/dev/codegen/css.rs @@ -120,7 +120,7 @@ pub(crate) fn css_decls(doc: &Document, n: &Node, t: &mut Tokens, hug: (bool, bo // A variable binds the first paint's colour. put(key, if i == 0 { tok(doc, n, &["fill"], c, t) } else { c }); } - PaintKind::Gradient(g) => put("background", css_gradient(g, n.width, n.height)), + PaintKind::Gradient(g) => put("background", css_gradient(g, n.width, n.height, p.opacity)), PaintKind::Image(_) => put("background", "url(image.png) center / cover".into()), PaintKind::Pattern(_) => put("background", "url(pattern.png) repeat".into()), } @@ -307,8 +307,13 @@ fn decoration_decls(s: &figcraft_doc::TextStyle, put: &mut impl FnMut(&str, Stri /// A gradient fill on a `w`×`h` box as a CSS background: linear along its handles' direction /// (CSS angles: 0deg up, 90deg right), radial with its handles' radii, angular as a conic /// gradient from its start direction. -fn css_gradient(g: &figcraft_color::Gradient, w: f64, h: f64) -> String { - let stops = g.sorted_stops().iter().map(|s| format!("{} {}%", s.color.to_css(), (s.position * 100.0).round())).collect::>().join(", "); +fn css_gradient(g: &figcraft_color::Gradient, w: f64, h: f64, opacity: f32) -> String { + let stops = g + .sorted_stops() + .iter() + .map(|s| format!("{} {}%", s.color.with_alpha(s.color.a * opacity).to_css(), (s.position * 100.0).round())) + .collect::>() + .join(", "); let (dx, dy) = ((g.to.0 - g.from.0) * w, (g.to.1 - g.from.1) * h); let angle = if dx == 0.0 && dy == 0.0 { 180.0 } else { dx.atan2(-dy).to_degrees().rem_euclid(360.0) }; let pct = |v: f64| format!("{}%", num(v * 100.0));