Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/rustmotion-components/src/legacy_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ mod tests {
let canvas = surface.canvas();
let dispatcher = LegacyPaintDispatcher::new(&built.components);
let frame = PaintFrame {
light: Default::default(),
time: 0.0,
scenario_time: 0.0,
frame_index: 0,
Expand Down Expand Up @@ -236,6 +237,7 @@ mod tests {
let canvas = surface.canvas();
let dispatcher = LegacyPaintDispatcher::new(&built.components);
let frame = PaintFrame {
light: Default::default(),
time: 0.0,
scenario_time: 0.0,
frame_index: 0,
Expand Down Expand Up @@ -335,6 +337,7 @@ mod tests {
let canvas = surface.canvas();
let dispatcher = LegacyPaintDispatcher::new(&built.components);
let frame = PaintFrame {
light: Default::default(),
time: 0.0,
scenario_time: 0.0,
frame_index: 0,
Expand Down Expand Up @@ -434,6 +437,7 @@ mod tests {
canvas.clear(skia_safe::Color::BLACK);
let dispatcher = LegacyPaintDispatcher::new(&built.components);
let frame = PaintFrame {
light: Default::default(),
time,
scenario_time: time,
frame_index: 0,
Expand Down Expand Up @@ -503,6 +507,7 @@ mod tests {
..Default::default()
};
let frame = PaintFrame {
light: Default::default(),
time: 0.0,
scenario_time: 0.0,
frame_index: 0,
Expand Down
1 change: 1 addition & 0 deletions crates/rustmotion-components/tests/audit_ws_i.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ fn paint_card_with_child(card_json: serde_json::Value) -> PaintedScene {
canvas.clear(skia_safe::Color::BLACK);
let dispatcher = LegacyPaintDispatcher::for_scene(&built);
let frame = PaintFrame {
light: Default::default(),
time: 0.0,
scenario_time: 0.0,
frame_index: 0,
Expand Down
1 change: 1 addition & 0 deletions crates/rustmotion-components/tests/caption_presets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ fn render_caption_at(json: serde_json::Value, time: f64, y: f32) -> Vec<u8> {
);
let dispatcher = LegacyPaintDispatcher::for_scene(&built);
let frame = PaintFrame {
light: Default::default(),
time,
scenario_time: time,
frame_index: (time * 30.0) as u32,
Expand Down
1 change: 1 addition & 0 deletions crates/rustmotion-components/tests/degenerate_inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ fn paint(json: serde_json::Value, time: f64) {
);
let dispatcher = LegacyPaintDispatcher::for_scene(&built);
let frame = PaintFrame {
light: Default::default(),
time,
scenario_time: time,
frame_index: (time * 30.0) as u32,
Expand Down
1 change: 1 addition & 0 deletions crates/rustmotion-components/tests/relative_font_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ fn render(json: serde_json::Value) -> Vec<u8> {
);
let dispatcher = LegacyPaintDispatcher::for_scene(&built);
let frame = PaintFrame {
light: Default::default(),
time: 0.5,
scenario_time: 0.5,
frame_index: 15,
Expand Down
1 change: 1 addition & 0 deletions crates/rustmotion-components/tests/text_autofit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ fn render_at(content: &str, autofit: bool, time: f64) -> Vec<u8> {
);
let dispatcher = LegacyPaintDispatcher::for_scene(&built);
let frame = PaintFrame {
light: Default::default(),
time,
scenario_time: time,
frame_index: (time * 30.0) as u32,
Expand Down
64 changes: 64 additions & 0 deletions crates/rustmotion-core/src/css/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,15 @@ pub struct CssStyle {
pub opacity: Option<f32>,
pub mix_blend_mode: Option<BlendMode>,
pub clip_path: Option<ClipPath>,
/// Glossy surface treatment: a highlight on the lit side, a specular
/// edge along it, and a soft shade opposite. All three are derived from
/// the scene's `light`, so several materials in one scene agree about
/// where the light is.
///
/// Follows the node's **box**, clipped by `border-radius` and by
/// `clip-path` when set — not by a `shape` component's own geometry,
/// which paints itself. Give the box the silhouette.
pub material: Option<Material>,
/// Gradient-colored border painted instead of `border` when present.
/// `{ "colors": [...], "width": 2, "angle": 0 }` — angle follows the same
/// convention as `background` linear gradients.
Expand Down Expand Up @@ -261,6 +270,7 @@ struct CssStyleWire {
opacity: Option<f32>,
mix_blend_mode: Option<BlendMode>,
clip_path: Option<ClipPath>,
material: Option<Material>,
gradient_border: Option<GradientBorder>,

backdrop_blur: Option<f32>,
Expand Down Expand Up @@ -1325,6 +1335,60 @@ pub enum BlendMode {
PlusLighter,
}

/// `style.material`, as either a bare preset name or an object tuning it.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum Material {
/// `"material": "glossy"`.
Preset(MaterialPreset),
/// `"material": { "preset": "glossy", "intensity": 0.6 }`.
Tuned {
#[serde(default)]
preset: MaterialPreset,
/// Scales all three layers together. `1.0` is the calibrated look,
/// `0.0` paints nothing. Multiplied by the scene light's own
/// `intensity`.
#[serde(default = "default_material_intensity")]
intensity: f32,
},
}

/// Which surface a `material` imitates.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum MaterialPreset {
/// A lit plastic or glass tile: bright highlight, hard specular edge,
/// soft shade opposite.
#[default]
Glossy,
/// The same light read as brushed metal: a tighter, dimmer highlight
/// and a stronger edge.
Metal,
/// Light with no specular return — shade only, no highlight and no
/// edge. Sits a flat surface next to glossy ones without looking unlit.
Matte,
}

fn default_material_intensity() -> f32 {
1.0
}

impl Material {
pub fn preset(&self) -> MaterialPreset {
match self {
Material::Preset(p) => *p,
Material::Tuned { preset, .. } => *preset,
}
}

pub fn intensity(&self) -> f32 {
match self {
Material::Preset(_) => 1.0,
Material::Tuned { intensity, .. } => *intensity,
}
}
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "kebab-case")]
pub enum ClipPath {
Expand Down
Loading
Loading