1use material_color_utilities::{
8 dynamiccolor::{DynamicSchemeBuilder, MaterialDynamicColors, SpecVersion, Variant},
9 hct::Hct,
10};
11use tessera_ui::{
12 CallbackWith, Color, Dp, RenderSlot, provide_context, remember, tessera, use_context,
13};
14
15use crate::shape_def::{RoundedCorner, Shape};
16
17const DEFAULT_SEED_ARGB: u32 = 0xFF6750A4;
18
19#[derive(Clone, PartialEq, Copy, Debug)]
22pub struct ContentColor {
23 pub current: Color,
26}
27
28impl Default for ContentColor {
29 fn default() -> Self {
30 ContentColor {
31 current: Color::BLACK,
32 }
33 }
34}
35
36pub struct MaterialAlpha;
38
39impl MaterialAlpha {
40 pub const HOVER: f32 = 0.08;
42 pub const PRESSED: f32 = 0.1;
44 pub const FOCUSED: f32 = 0.1;
46 pub const DRAGGED: f32 = 0.16;
48 pub const DISABLED_CONTAINER: f32 = 0.12;
50 pub const DISABLED_CONTENT: f32 = 0.38;
52}
53
54#[derive(Clone, PartialEq, Copy, Debug)]
56pub struct TextSelectionColors {
57 pub handle: Color,
59 pub background: Color,
61}
62
63impl TextSelectionColors {
64 pub fn from_scheme(scheme: &MaterialColorScheme) -> Self {
66 Self {
67 handle: scheme.primary,
68 background: scheme.primary.with_alpha(0.35),
69 }
70 }
71}
72
73pub fn content_color_for(background: Color, scheme: &MaterialColorScheme) -> Option<Color> {
78 scheme.content_color_for(background)
79}
80
81#[derive(Clone, PartialEq, Copy, Debug)]
83pub struct TextStyle {
84 pub font_size: Dp,
86 pub line_height: Option<Dp>,
88 pub font_weight: u16,
90 pub letter_spacing: Dp,
92 pub font_family: Option<&'static str>,
94}
95
96impl Default for TextStyle {
97 fn default() -> Self {
98 Self {
99 font_size: Dp(16.0),
100 line_height: Some(Dp(24.0)),
101 font_weight: 400,
102 letter_spacing: Dp(0.0),
103 font_family: None,
104 }
105 }
106}
107
108#[derive(Clone, PartialEq, Copy, Debug)]
110pub struct MaterialTypography {
111 pub display_large: TextStyle,
113 pub display_medium: TextStyle,
115 pub display_small: TextStyle,
117 pub headline_large: TextStyle,
119 pub headline_medium: TextStyle,
121 pub headline_small: TextStyle,
123 pub title_large: TextStyle,
125 pub title_medium: TextStyle,
127 pub title_small: TextStyle,
129 pub body_large: TextStyle,
131 pub body_medium: TextStyle,
133 pub body_small: TextStyle,
135 pub label_large: TextStyle,
137 pub label_medium: TextStyle,
139 pub label_small: TextStyle,
141}
142
143impl Default for MaterialTypography {
144 fn default() -> Self {
145 Self {
146 display_large: TextStyle {
147 font_size: Dp(57.0),
148 line_height: Some(Dp(64.0)),
149 font_weight: 400,
150 letter_spacing: Dp(-0.2),
151 font_family: None,
152 },
153 display_medium: TextStyle {
154 font_size: Dp(45.0),
155 line_height: Some(Dp(52.0)),
156 font_weight: 400,
157 letter_spacing: Dp(0.0),
158 font_family: None,
159 },
160 display_small: TextStyle {
161 font_size: Dp(36.0),
162 line_height: Some(Dp(44.0)),
163 font_weight: 400,
164 letter_spacing: Dp(0.0),
165 font_family: None,
166 },
167 headline_large: TextStyle {
168 font_size: Dp(32.0),
169 line_height: Some(Dp(40.0)),
170 font_weight: 400,
171 letter_spacing: Dp(0.0),
172 font_family: None,
173 },
174 headline_medium: TextStyle {
175 font_size: Dp(28.0),
176 line_height: Some(Dp(36.0)),
177 font_weight: 400,
178 letter_spacing: Dp(0.0),
179 font_family: None,
180 },
181 headline_small: TextStyle {
182 font_size: Dp(24.0),
183 line_height: Some(Dp(32.0)),
184 font_weight: 400,
185 letter_spacing: Dp(0.0),
186 font_family: None,
187 },
188 title_large: TextStyle {
189 font_size: Dp(22.0),
190 line_height: Some(Dp(28.0)),
191 font_weight: 400,
192 letter_spacing: Dp(0.0),
193 font_family: None,
194 },
195 title_medium: TextStyle {
196 font_size: Dp(16.0),
197 line_height: Some(Dp(24.0)),
198 font_weight: 500,
199 letter_spacing: Dp(0.2),
200 font_family: None,
201 },
202 title_small: TextStyle {
203 font_size: Dp(14.0),
204 line_height: Some(Dp(20.0)),
205 font_weight: 500,
206 letter_spacing: Dp(0.1),
207 font_family: None,
208 },
209 body_large: TextStyle {
210 font_size: Dp(16.0),
211 line_height: Some(Dp(24.0)),
212 font_weight: 400,
213 letter_spacing: Dp(0.5),
214 font_family: None,
215 },
216 body_medium: TextStyle {
217 font_size: Dp(14.0),
218 line_height: Some(Dp(20.0)),
219 font_weight: 400,
220 letter_spacing: Dp(0.2),
221 font_family: None,
222 },
223 body_small: TextStyle {
224 font_size: Dp(12.0),
225 line_height: Some(Dp(16.0)),
226 font_weight: 400,
227 letter_spacing: Dp(0.4),
228 font_family: None,
229 },
230 label_large: TextStyle {
231 font_size: Dp(14.0),
232 line_height: Some(Dp(20.0)),
233 font_weight: 500,
234 letter_spacing: Dp(0.1),
235 font_family: None,
236 },
237 label_medium: TextStyle {
238 font_size: Dp(12.0),
239 line_height: Some(Dp(16.0)),
240 font_weight: 500,
241 letter_spacing: Dp(0.5),
242 font_family: None,
243 },
244 label_small: TextStyle {
245 font_size: Dp(11.0),
246 line_height: Some(Dp(16.0)),
247 font_weight: 500,
248 letter_spacing: Dp(0.5),
249 font_family: None,
250 },
251 }
252 }
253}
254
255impl MaterialTypography {
256 pub fn emphasized(&self) -> Self {
258 let mut scale = *self;
259 for style in [
260 &mut scale.display_large,
261 &mut scale.display_medium,
262 &mut scale.display_small,
263 &mut scale.headline_large,
264 &mut scale.headline_medium,
265 &mut scale.headline_small,
266 &mut scale.title_large,
267 &mut scale.body_large,
268 &mut scale.body_medium,
269 &mut scale.body_small,
270 ] {
271 style.font_weight = 500;
272 }
273 for style in [
274 &mut scale.title_medium,
275 &mut scale.title_small,
276 &mut scale.label_large,
277 &mut scale.label_medium,
278 &mut scale.label_small,
279 ] {
280 style.font_weight = 700;
281 }
282 scale.display_large.letter_spacing = Dp(0.0);
283 scale.body_large.letter_spacing = Dp(0.15);
284 scale.body_medium.letter_spacing = Dp(0.25);
285 scale.title_medium.letter_spacing = Dp(0.15);
286 scale
287 }
288}
289
290#[derive(Clone, PartialEq, Copy, Debug)]
292pub struct MaterialShapes {
293 pub extra_small: Shape,
295 pub small: Shape,
297 pub medium: Shape,
299 pub large: Shape,
301 pub large_increased: Shape,
303 pub extra_large: Shape,
305}
306
307impl Default for MaterialShapes {
308 fn default() -> Self {
309 let rounded = |radius| {
310 let corner = RoundedCorner::manual(Dp(radius), 2.0);
311 Shape::RoundedRectangle {
312 top_left: corner,
313 top_right: corner,
314 bottom_left: corner,
315 bottom_right: corner,
316 }
317 };
318 Self {
319 extra_small: rounded(4.0),
320 small: rounded(8.0),
321 medium: rounded(12.0),
322 large: rounded(16.0),
323 large_increased: rounded(20.0),
324 extra_large: rounded(28.0),
325 }
326 }
327}
328
329#[derive(Clone, PartialEq, Debug, Default)]
332pub struct MaterialTheme {
333 pub color_scheme: MaterialColorScheme,
335 pub typography: MaterialTypography,
337 pub shapes: MaterialShapes,
339}
340
341impl MaterialTheme {
342 pub fn from_color_scheme(color_scheme: MaterialColorScheme) -> Self {
345 Self {
346 color_scheme,
347 ..Self::default()
348 }
349 }
350
351 pub fn from_seed(seed: Color, is_dark: bool) -> Self {
353 Self::from_color_scheme(scheme_from_seed(seed, is_dark))
354 }
355}
356
357#[tessera]
398pub fn material_theme(theme: Option<CallbackWith<(), MaterialTheme>>, child: Option<RenderSlot>) {
399 let theme = theme.unwrap_or_else(|| CallbackWith::new(|()| MaterialTheme::default()));
400 let child = child.unwrap_or_else(RenderSlot::empty);
401 let value = theme.call(());
402 let next = (value.clone(), child);
403 let data = remember(|| next.clone());
404 let pending = remember(|| None::<MaterialTheme>);
405 if data.with(|current| current.0 != next.0) {
406 pending.set(Some(next.0.clone()));
407 }
408 if data.with(|current| current != &next) {
409 data.set(next);
410 }
411 let content = RenderSlot::new(move || {
412 if pending.with(Option::is_some) {
413 let value = pending
414 .with_mut(Option::take)
415 .expect("pending theme update");
416 use_context::<MaterialTheme>()
417 .expect("Material theme must be provided")
418 .set(value);
419 }
420 let child = data.with(|(_, child)| *child);
421 child.render();
422 });
423 provide_context(move || value, move || content.render());
424}
425
426#[derive(Clone, PartialEq, Debug)]
432pub struct MaterialColorScheme {
433 pub is_dark: bool,
435 pub primary: Color,
437 pub on_primary: Color,
439 pub primary_container: Color,
441 pub on_primary_container: Color,
443 pub secondary: Color,
445 pub on_secondary: Color,
447 pub secondary_container: Color,
449 pub on_secondary_container: Color,
451 pub tertiary: Color,
453 pub on_tertiary: Color,
455 pub tertiary_container: Color,
457 pub on_tertiary_container: Color,
459 pub error: Color,
461 pub on_error: Color,
463 pub error_container: Color,
465 pub on_error_container: Color,
467 pub background: Color,
469 pub on_background: Color,
471 pub surface: Color,
473 pub on_surface: Color,
475 pub surface_variant: Color,
477 pub on_surface_variant: Color,
479 pub outline: Color,
481 pub outline_variant: Color,
483 pub shadow: Color,
485 pub scrim: Color,
487 pub surface_tint: Color,
489 pub surface_bright: Color,
491 pub surface_dim: Color,
493 pub inverse_surface: Color,
495 pub inverse_on_surface: Color,
497 pub inverse_primary: Color,
499 pub surface_container: Color,
501 pub surface_container_high: Color,
503 pub surface_container_highest: Color,
505 pub surface_container_low: Color,
507 pub surface_container_lowest: Color,
509 pub primary_fixed: Color,
512 pub primary_fixed_dim: Color,
515 pub on_primary_fixed: Color,
517 pub on_primary_fixed_variant: Color,
519 pub secondary_fixed: Color,
522 pub secondary_fixed_dim: Color,
525 pub on_secondary_fixed: Color,
527 pub on_secondary_fixed_variant: Color,
529 pub tertiary_fixed: Color,
532 pub tertiary_fixed_dim: Color,
535 pub on_tertiary_fixed: Color,
537 pub on_tertiary_fixed_variant: Color,
539}
540
541impl MaterialColorScheme {
542 pub fn light_from_seed(seed: Color) -> Self {
544 scheme_from_seed(seed, false)
545 }
546
547 pub fn dark_from_seed(seed: Color) -> Self {
549 scheme_from_seed(seed, true)
550 }
551
552 pub fn content_color_for(&self, background: Color) -> Option<Color> {
558 if background == self.primary {
559 Some(self.on_primary)
560 } else if background == self.secondary {
561 Some(self.on_secondary)
562 } else if background == self.tertiary {
563 Some(self.on_tertiary)
564 } else if background == self.background {
565 Some(self.on_background)
566 } else if background == self.error {
567 Some(self.on_error)
568 } else if background == self.primary_container {
569 Some(self.on_primary_container)
570 } else if background == self.secondary_container {
571 Some(self.on_secondary_container)
572 } else if background == self.tertiary_container {
573 Some(self.on_tertiary_container)
574 } else if background == self.error_container {
575 Some(self.on_error_container)
576 } else if background == self.inverse_surface {
577 Some(self.inverse_on_surface)
578 } else if background == self.surface {
579 Some(self.on_surface)
580 } else if background == self.surface_variant {
581 Some(self.on_surface_variant)
582 } else if background == self.surface_bright
583 || background == self.surface_container
584 || background == self.surface_container_high
585 || background == self.surface_container_highest
586 || background == self.surface_container_low
587 || background == self.surface_container_lowest
588 || background == self.surface_dim
589 {
590 Some(self.on_surface)
591 } else if background == self.primary_fixed || background == self.primary_fixed_dim {
592 Some(self.on_primary_fixed)
593 } else if background == self.secondary_fixed || background == self.secondary_fixed_dim {
594 Some(self.on_secondary_fixed)
595 } else if background == self.tertiary_fixed || background == self.tertiary_fixed_dim {
596 Some(self.on_tertiary_fixed)
597 } else {
598 None
599 }
600 }
601
602 pub fn surface_color_at_elevation(&self, elevation: Dp) -> Color {
604 if elevation.0 == 0.0 {
605 return self.surface;
606 }
607 let alpha = ((4.5 * (elevation.0 + 1.0).ln()) + 2.0) / 100.0;
608 self.surface.blend_over(self.surface_tint, alpha as f32)
609 }
610
611 pub fn surface_color_at_elevation_for(&self, background: Color, elevation: Dp) -> Color {
614 if background == self.surface {
615 self.surface_color_at_elevation(elevation)
616 } else {
617 background
618 }
619 }
620}
621
622impl Default for MaterialColorScheme {
623 fn default() -> Self {
624 MaterialColorScheme::light_from_seed(argb_to_color(DEFAULT_SEED_ARGB))
625 }
626}
627
628fn scheme_from_seed(seed: Color, is_dark: bool) -> MaterialColorScheme {
629 let scheme = DynamicSchemeBuilder::default()
630 .source_color_hct(Hct::from_int(color_to_argb(seed)))
631 .variant(Variant::TonalSpot)
632 .spec_version(SpecVersion::Spec2025)
633 .is_dark(is_dark)
634 .build();
635 let dynamic_colors = MaterialDynamicColors::new();
636
637 MaterialColorScheme {
638 is_dark,
639 primary: argb_to_color(dynamic_colors.primary().get_argb(&scheme)),
640 on_primary: argb_to_color(dynamic_colors.on_primary().get_argb(&scheme)),
641 primary_container: argb_to_color(dynamic_colors.primary_container().get_argb(&scheme)),
642 on_primary_container: argb_to_color(
643 dynamic_colors.on_primary_container().get_argb(&scheme),
644 ),
645 secondary: argb_to_color(dynamic_colors.secondary().get_argb(&scheme)),
646 on_secondary: argb_to_color(dynamic_colors.on_secondary().get_argb(&scheme)),
647 secondary_container: argb_to_color(dynamic_colors.secondary_container().get_argb(&scheme)),
648 on_secondary_container: argb_to_color(
649 dynamic_colors.on_secondary_container().get_argb(&scheme),
650 ),
651 tertiary: argb_to_color(dynamic_colors.tertiary().get_argb(&scheme)),
652 on_tertiary: argb_to_color(dynamic_colors.on_tertiary().get_argb(&scheme)),
653 tertiary_container: argb_to_color(dynamic_colors.tertiary_container().get_argb(&scheme)),
654 on_tertiary_container: argb_to_color(
655 dynamic_colors.on_tertiary_container().get_argb(&scheme),
656 ),
657 error: argb_to_color(dynamic_colors.error().get_argb(&scheme)),
658 on_error: argb_to_color(dynamic_colors.on_error().get_argb(&scheme)),
659 error_container: argb_to_color(dynamic_colors.error_container().get_argb(&scheme)),
660 on_error_container: argb_to_color(dynamic_colors.on_error_container().get_argb(&scheme)),
661 background: argb_to_color(dynamic_colors.background().get_argb(&scheme)),
662 on_background: argb_to_color(dynamic_colors.on_background().get_argb(&scheme)),
663 surface: argb_to_color(dynamic_colors.surface().get_argb(&scheme)),
664 on_surface: argb_to_color(dynamic_colors.on_surface().get_argb(&scheme)),
665 surface_variant: argb_to_color(dynamic_colors.surface_variant().get_argb(&scheme)),
666 on_surface_variant: argb_to_color(dynamic_colors.on_surface_variant().get_argb(&scheme)),
667 outline: argb_to_color(dynamic_colors.outline().get_argb(&scheme)),
668 outline_variant: argb_to_color(dynamic_colors.outline_variant().get_argb(&scheme)),
669 shadow: argb_to_color(dynamic_colors.shadow().get_argb(&scheme)),
670 scrim: argb_to_color(dynamic_colors.scrim().get_argb(&scheme)),
671 surface_tint: argb_to_color(dynamic_colors.surface_tint().get_argb(&scheme)),
672 inverse_surface: argb_to_color(dynamic_colors.inverse_surface().get_argb(&scheme)),
673 inverse_on_surface: argb_to_color(dynamic_colors.inverse_on_surface().get_argb(&scheme)),
674 inverse_primary: argb_to_color(dynamic_colors.inverse_primary().get_argb(&scheme)),
675 surface_bright: argb_to_color(dynamic_colors.surface_bright().get_argb(&scheme)),
676 surface_dim: argb_to_color(dynamic_colors.surface_dim().get_argb(&scheme)),
677 surface_container: argb_to_color(dynamic_colors.surface_container().get_argb(&scheme)),
678 surface_container_high: argb_to_color(
679 dynamic_colors.surface_container_high().get_argb(&scheme),
680 ),
681 surface_container_highest: argb_to_color(
682 dynamic_colors.surface_container_highest().get_argb(&scheme),
683 ),
684 surface_container_low: argb_to_color(
685 dynamic_colors.surface_container_low().get_argb(&scheme),
686 ),
687 surface_container_lowest: argb_to_color(
688 dynamic_colors.surface_container_lowest().get_argb(&scheme),
689 ),
690 primary_fixed: argb_to_color(dynamic_colors.primary_fixed().get_argb(&scheme)),
691 primary_fixed_dim: argb_to_color(dynamic_colors.primary_fixed_dim().get_argb(&scheme)),
692 on_primary_fixed: argb_to_color(dynamic_colors.on_primary_fixed().get_argb(&scheme)),
693 on_primary_fixed_variant: argb_to_color(
694 dynamic_colors.on_primary_fixed_variant().get_argb(&scheme),
695 ),
696 secondary_fixed: argb_to_color(dynamic_colors.secondary_fixed().get_argb(&scheme)),
697 secondary_fixed_dim: argb_to_color(dynamic_colors.secondary_fixed_dim().get_argb(&scheme)),
698 on_secondary_fixed: argb_to_color(dynamic_colors.on_secondary_fixed().get_argb(&scheme)),
699 on_secondary_fixed_variant: argb_to_color(
700 dynamic_colors
701 .on_secondary_fixed_variant()
702 .get_argb(&scheme),
703 ),
704 tertiary_fixed: argb_to_color(dynamic_colors.tertiary_fixed().get_argb(&scheme)),
705 tertiary_fixed_dim: argb_to_color(dynamic_colors.tertiary_fixed_dim().get_argb(&scheme)),
706 on_tertiary_fixed: argb_to_color(dynamic_colors.on_tertiary_fixed().get_argb(&scheme)),
707 on_tertiary_fixed_variant: argb_to_color(
708 dynamic_colors.on_tertiary_fixed_variant().get_argb(&scheme),
709 ),
710 }
711}
712
713fn linear_to_srgb_channel(v: f32) -> f32 {
714 let v = v.clamp(0.0, 1.0);
715 if v <= 0.003_130_8 {
716 v * 12.92
717 } else {
718 1.055 * v.powf(1.0 / 2.4) - 0.055
719 }
720}
721
722fn srgb_to_linear_channel(v: f32) -> f32 {
723 let v = v.clamp(0.0, 1.0);
724 if v <= 0.04045 {
725 v / 12.92
726 } else {
727 ((v + 0.055) / 1.055).powf(2.4)
728 }
729}
730
731fn color_to_argb(color: Color) -> u32 {
732 let r = (linear_to_srgb_channel(color.r) * 255.0 + 0.5) as u32;
733 let g = (linear_to_srgb_channel(color.g) * 255.0 + 0.5) as u32;
734 let b = (linear_to_srgb_channel(color.b) * 255.0 + 0.5) as u32;
735 let a = (color.a.clamp(0.0, 1.0) * 255.0 + 0.5) as u32;
736 (a << 24) | (r << 16) | (g << 8) | b
737}
738
739fn argb_to_color(argb: u32) -> Color {
740 let a = ((argb >> 24) & 0xFF) as f32 / 255.0;
741 let r_srgb = ((argb >> 16) & 0xFF) as f32 / 255.0;
742 let g_srgb = ((argb >> 8) & 0xFF) as f32 / 255.0;
743 let b_srgb = (argb & 0xFF) as f32 / 255.0;
744 Color::new(
745 srgb_to_linear_channel(r_srgb),
746 srgb_to_linear_channel(g_srgb),
747 srgb_to_linear_channel(b_srgb),
748 a,
749 )
750}
751
752#[cfg(test)]
753mod tests {
754 use tessera_ui::Color;
755
756 use super::MaterialColorScheme;
757
758 fn assert_reference_roles(scheme: MaterialColorScheme, expected: [[f32; 3]; 12]) {
759 let actual = [
760 ("primary", scheme.primary),
761 ("on_primary", scheme.on_primary),
762 ("primary_container", scheme.primary_container),
763 ("on_primary_container", scheme.on_primary_container),
764 ("secondary", scheme.secondary),
765 ("secondary_container", scheme.secondary_container),
766 ("on_secondary_container", scheme.on_secondary_container),
767 ("tertiary", scheme.tertiary),
768 ("surface", scheme.surface),
769 ("surface_container_low", scheme.surface_container_low),
770 ("on_surface", scheme.on_surface),
771 ("outline", scheme.outline),
772 ];
773 for ((role, actual), expected) in actual.into_iter().zip(expected) {
774 for (actual, expected) in [actual.r, actual.g, actual.b].into_iter().zip(expected) {
775 assert!(
776 (actual - expected).abs() < 0.000_001,
777 "{role}: expected {expected}, got {actual}"
778 );
779 }
780 assert_eq!(actual.a, 1.0, "{role} must be opaque");
781 }
782 }
783
784 #[test]
785 fn default_light_roles_match_material_2025_reference() {
786 assert_reference_roles(
787 MaterialColorScheme::default(),
788 [
789 [0.130136477, 0.095307467, 0.250158285],
790 [0.982250550, 0.930110858, 1.000000000],
791 [0.658374817, 0.545724461, 0.982250550],
792 [0.066625939, 0.045186204, 0.149959790],
793 [0.122138772, 0.107023103, 0.165132195],
794 [0.806952258, 0.730460740, 0.938685728],
795 [0.090841711, 0.078187422, 0.124771818],
796 [0.198069320, 0.084376212, 0.162029376],
797 [0.982250550, 0.930110858, 0.991102097],
798 [0.938685728, 0.879622397, 0.955973353],
799 [0.034339807, 0.030713444, 0.042311411],
800 [0.205078736, 0.191201683, 0.226965874],
801 ],
802 );
803 }
804
805 #[test]
806 fn seeded_dark_roles_match_material_2025_reference() {
807 assert_reference_roles(
808 MaterialColorScheme::dark_from_seed(Color::from_rgb(
809 0.135633335,
810 0.080219820,
811 0.371237695,
812 )),
813 [
814 [0.610495571, 0.527115126, 0.838799012],
815 [0.057805430, 0.042311411, 0.114435374],
816 [0.095307467, 0.074213568, 0.168269400],
817 [0.814846572, 0.730460740, 1.000000000],
818 [0.597201788, 0.539479489, 0.708375780],
819 [0.048171824, 0.039546235, 0.072271851],
820 [0.552011402, 0.496932995, 0.658374817],
821 [1.000000000, 0.623960392, 0.863157213],
822 [0.004776953, 0.004024717, 0.006048833],
823 [0.006995410, 0.006048833, 0.009134059],
824 [0.822785754, 0.768151147, 0.863157213],
825 [0.187820772, 0.171441101, 0.208636870],
826 ],
827 );
828 }
829}