1use serde::{Deserialize, Serialize};
35use std::collections::HashMap;
36use std::str::FromStr;
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40#[serde(untagged)]
41pub enum TokenValue {
42 Single { value: String },
44 Adaptive { light: String, dark: String },
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct YggdrasilTokens {
51 pub color: HashMap<String, TokenValue>,
52 pub font: HashMap<String, TokenValue>,
53 pub spacing: HashMap<String, TokenValue>,
54 pub radius: HashMap<String, TokenValue>,
55 pub shadow: HashMap<String, TokenValue>,
56 pub border: HashMap<String, TokenValue>,
57 pub anim: HashMap<String, TokenValue>,
58 pub bifrost: HashMap<String, TokenValue>,
59 pub gungnir: HashMap<String, TokenValue>,
60 pub mjolnir: HashMap<String, TokenValue>,
61 pub accessibility: HashMap<String, TokenValue>,
62}
63
64impl YggdrasilTokens {
65 pub fn new() -> Self {
66 Self {
67 color: HashMap::new(),
68 font: HashMap::new(),
69 spacing: HashMap::new(),
70 radius: HashMap::new(),
71 shadow: HashMap::new(),
72 border: HashMap::new(),
73 anim: HashMap::new(),
74 bifrost: HashMap::new(),
75 gungnir: HashMap::new(),
76 mjolnir: HashMap::new(),
77 accessibility: HashMap::new(),
78 }
79 }
80
81 pub fn get_color(&self, key: &str, is_dark: bool) -> Option<String> {
83 self.color.get(key).and_then(|token| match token {
84 TokenValue::Single { value } => Some(value.clone()),
85 TokenValue::Adaptive { light, dark } => {
86 if is_dark {
87 Some(dark.clone())
88 } else {
89 Some(light.clone())
90 }
91 }
92 })
93 }
94
95 pub fn get<T: FromStr>(&self, category: &str, key: &str, is_dark: bool) -> Option<T> {
97 let map = match category {
98 "color" => &self.color,
99 "font" => &self.font,
100 "spacing" => &self.spacing,
101 "radius" => &self.radius,
102 "shadow" => &self.shadow,
103 "border" => &self.border,
104 "anim" => &self.anim,
105 "bifrost" => &self.bifrost,
106 "gungnir" => &self.gungnir,
107 "mjolnir" => &self.mjolnir,
108 "accessibility" => &self.accessibility,
109 _ => return None,
110 };
111
112 map.get(key).and_then(|token| match token {
113 TokenValue::Single { value } => value.parse().ok(),
114 TokenValue::Adaptive { light, dark } => {
115 let value = if is_dark { dark } else { light };
116 value.parse().ok()
117 }
118 })
119 }
120}
121
122pub trait View: Sized + Send {
123 type Body: View;
126
127 fn body(self) -> Self::Body;
128
129 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
132
133 fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
136 Size::ZERO
137 }
138
139 fn layout(&self) -> Option<&dyn layout::LayoutView> {
141 None
142 }
143
144 fn flex_weight(&self) -> f32 {
146 0.0
147 }
148
149 fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
151 ModifiedView::new(self, m)
152 }
153
154 fn bifrost(
156 self,
157 blur: f32,
158 saturation: f32,
159 opacity: f32,
160 ) -> ModifiedView<Self, BifrostModifier> {
161 self.modifier(BifrostModifier {
162 blur,
163 saturation,
164 opacity,
165 })
166 }
167
168 fn gungnir(
170 self,
171 color: impl Into<String>,
172 radius: f32,
173 intensity: f32,
174 ) -> ModifiedView<Self, GungnirModifier> {
175 self.modifier(GungnirModifier {
176 color: color.into(),
177 radius,
178 intensity,
179 })
180 }
181
182 fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
184 self.modifier(MjolnirSliceModifier { angle, offset })
185 }
186
187 fn mjolnir_shatter(
189 self,
190 pieces: u32,
191 force: f32,
192 ) -> ModifiedView<Self, MjolnirShatterModifier> {
193 self.modifier(MjolnirShatterModifier { pieces, force })
194 }
195
196 fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
198 self.modifier(BifrostBridgeModifier { id: id.into() })
199 }
200
201 fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
203 self.modifier(BackgroundModifier { color })
204 }
205
206 fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
208 self.modifier(PaddingModifier { amount })
209 }
210
211 fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
213 self.modifier(OpacityModifier {
214 opacity: opacity.clamp(0.0, 1.0),
215 })
216 }
217
218 fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
220 self.modifier(ForegroundColorModifier { color })
221 }
222
223 fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
225 self.modifier(FrameModifier { width, height })
226 }
227
228 fn flex(self, weight: f32) -> ModifiedView<Self, FlexModifier> {
230 self.modifier(FlexModifier { weight })
231 }
232
233 fn safe_area_padding(self) -> ModifiedView<Self, SafeAreaModifier> {
235 self.modifier(SafeAreaModifier { ignores: false })
236 }
237
238 fn ignores_safe_area(self) -> ModifiedView<Self, SafeAreaModifier> {
240 self.modifier(SafeAreaModifier { ignores: true })
241 }
242
243 fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
245 self.modifier(ClipModifier)
246 }
247
248 fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
250 self.modifier(BorderModifier { color, width })
251 }
252
253 fn elevation(self, level: f32) -> ModifiedView<Self, ElevationModifier> {
255 self.modifier(ElevationModifier { level })
256 }
257
258 fn on_appear<F: Fn() + Send + Sync + 'static>(
260 self,
261 action: F,
262 ) -> ModifiedView<Self, LifecycleModifier> {
263 self.modifier(LifecycleModifier {
264 on_appear: Some(Arc::new(action)),
265 on_disappear: None,
266 })
267 }
268
269 fn on_disappear<F: Fn() + Send + Sync + 'static>(
271 self,
272 action: F,
273 ) -> ModifiedView<Self, LifecycleModifier> {
274 self.modifier(LifecycleModifier {
275 on_appear: None,
276 on_disappear: Some(Arc::new(action)),
277 })
278 }
279
280 fn on_click<F: Fn() + Send + Sync + 'static>(
282 self,
283 action: F,
284 ) -> ModifiedView<Self, OnClickModifier> {
285 self.modifier(OnClickModifier {
286 action: Arc::new(action),
287 })
288 }
289
290 fn on_pointer_enter<F: Fn() + Send + Sync + 'static>(
292 self,
293 action: F,
294 ) -> ModifiedView<Self, OnPointerEnterModifier> {
295 self.modifier(OnPointerEnterModifier {
296 action: Arc::new(action),
297 })
298 }
299
300 fn on_pointer_leave<F: Fn() + Send + Sync + 'static>(
302 self,
303 action: F,
304 ) -> ModifiedView<Self, OnPointerLeaveModifier> {
305 self.modifier(OnPointerLeaveModifier {
306 action: Arc::new(action),
307 })
308 }
309
310 fn on_pointer_move<F: Fn(f32, f32) + Send + Sync + 'static>(
312 self,
313 action: F,
314 ) -> ModifiedView<Self, OnPointerMoveModifier> {
315 self.modifier(OnPointerMoveModifier {
316 action: Arc::new(action),
317 })
318 }
319
320 fn on_pointer_down<F: Fn() + Send + Sync + 'static>(
322 self,
323 action: F,
324 ) -> ModifiedView<Self, OnPointerDownModifier> {
325 self.modifier(OnPointerDownModifier {
326 action: Arc::new(action),
327 })
328 }
329
330 fn on_pointer_up<F: Fn() + Send + Sync + 'static>(
332 self,
333 action: F,
334 ) -> ModifiedView<Self, OnPointerUpModifier> {
335 self.modifier(OnPointerUpModifier {
336 action: Arc::new(action),
337 })
338 }
339
340 fn erase(self) -> AnyView
342 where
343 Self: 'static,
344 {
345 AnyView::new(self)
346 }
347}
348
349pub trait ErasedView: Send {
351 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect);
352 fn name(&self) -> &'static str;
353 fn flex_weight_erased(&self) -> f32;
354}
355
356impl<V: View + 'static> ErasedView for V {
357 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
358 self.render(renderer, rect);
359 }
360
361 fn name(&self) -> &'static str {
362 std::any::type_name::<V>()
363 }
364
365 fn flex_weight_erased(&self) -> f32 {
366 self.flex_weight()
367 }
368}
369
370pub struct AnyView {
372 inner: Box<dyn ErasedView>,
373}
374
375impl AnyView {
376 pub fn new<V: View + 'static>(view: V) -> Self {
377 Self {
378 inner: Box::new(view),
379 }
380 }
381}
382
383impl View for AnyView {
384 type Body = Never;
385 fn body(self) -> Self::Body {
386 unreachable!()
387 }
388
389 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
390 renderer.push_vnode(rect, self.inner.name());
391 self.inner.render_erased(renderer, rect);
392 renderer.pop_vnode();
393 }
394
395 fn flex_weight(&self) -> f32 {
396 self.inner.flex_weight_erased()
397 }
398}
399
400#[derive(Debug, Clone, PartialEq)]
404pub struct BifrostBridgeModifier {
405 pub id: String,
406}
407
408impl ViewModifier for BifrostBridgeModifier {
409 fn modify<V: View>(self, content: V) -> impl View {
410 ModifiedView::new(content, self)
411 }
412
413 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
414 renderer.register_shared_element(&self.id, rect);
416 }
417}
418
419#[derive(Debug, Clone, Copy, PartialEq)]
422pub struct MjolnirSliceModifier {
423 pub angle: f32,
424 pub offset: f32,
425}
426
427impl ViewModifier for MjolnirSliceModifier {
428 fn modify<V: View>(self, content: V) -> impl View {
429 ModifiedView::new(content, self)
430 }
431
432 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
433 renderer.push_mjolnir_slice(self.angle, self.offset);
434 }
435
436 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
437 renderer.pop_mjolnir_slice();
438 }
439}
440
441#[derive(Debug, Clone, Copy, PartialEq)]
444pub struct MjolnirShatterModifier {
445 pub pieces: u32,
446 pub force: f32,
447}
448
449impl ViewModifier for MjolnirShatterModifier {
450 fn modify<V: View>(self, content: V) -> impl View {
451 ModifiedView::new(content, self)
452 }
453
454 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
455 let pieces = self.pieces.max(1);
457 for i in 0..pieces {
458 let progress = i as f32 / pieces as f32;
459 let next_progress = (i + 1) as f32 / pieces as f32;
460
461 let angle_start = progress * 360.0;
462 let angle_end = next_progress * 360.0;
463
464 renderer.push_mjolnir_slice(angle_start, 0.0);
466 renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
467
468 let mid_angle = (angle_start + angle_end) / 2.0;
470 let rad = mid_angle.to_radians();
471 let dx = rad.cos() * self.force;
472 let dy = rad.sin() * self.force;
473
474 let shard_rect = Rect {
475 x: rect.x + dx,
476 y: rect.y + dy,
477 ..rect
478 };
479
480 view.render(renderer, shard_rect);
481
482 renderer.pop_mjolnir_slice();
483 renderer.pop_mjolnir_slice();
484 }
485 }
486}
487
488#[derive(Debug, Clone, Copy, PartialEq)]
491pub struct BifrostModifier {
492 pub blur: f32,
493 pub saturation: f32,
494 pub opacity: f32,
495}
496
497impl ViewModifier for BifrostModifier {
498 fn modify<V: View>(self, content: V) -> impl View {
499 ModifiedView::new(content, self)
500 }
501
502 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
503 renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
504 }
505}
506
507#[derive(Debug, Clone, Copy, PartialEq)]
509pub struct BackgroundModifier {
510 pub color: [f32; 4],
511}
512
513impl ViewModifier for BackgroundModifier {
514 fn modify<V: View>(self, content: V) -> impl View {
515 ModifiedView::new(content, self)
516 }
517
518 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
519 renderer.fill_rect(rect, self.color);
520 }
521}
522
523#[derive(Debug, Clone, Copy, PartialEq)]
525pub struct PaddingModifier {
526 pub amount: f32,
527}
528
529impl ViewModifier for PaddingModifier {
530 fn modify<V: View>(self, content: V) -> impl View {
531 ModifiedView::new(content, self)
532 }
533
534 fn transform_rect(&self, rect: Rect) -> Rect {
535 Rect {
536 x: rect.x + self.amount,
537 y: rect.y + self.amount,
538 width: (rect.width - 2.0 * self.amount).max(0.0),
539 height: (rect.height - 2.0 * self.amount).max(0.0),
540 }
541 }
542
543 fn transform_proposal(&self, mut proposal: SizeProposal) -> SizeProposal {
544 if let Some(w) = proposal.width {
545 proposal.width = Some((w - 2.0 * self.amount).max(0.0));
546 }
547 if let Some(h) = proposal.height {
548 proposal.height = Some((h - 2.0 * self.amount).max(0.0));
549 }
550 proposal
551 }
552
553 fn transform_size(&self, mut size: Size) -> Size {
554 size.width += 2.0 * self.amount;
555 size.height += 2.0 * self.amount;
556 size
557 }
558}
559
560#[derive(Debug, Clone, PartialEq)]
563pub struct GungnirModifier {
564 pub color: String,
565 pub radius: f32,
566 pub intensity: f32,
567}
568
569impl ViewModifier for GungnirModifier {
570 fn modify<V: View>(self, content: V) -> impl View {
571 ModifiedView::new(content, self)
572 }
573
574 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
575 renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
577 }
578}
579
580#[derive(Debug, Clone, Copy, PartialEq)]
582pub struct GungnirPulseModifier {
583 pub color: [f32; 4],
584 pub radius: f32,
585 pub speed: f32,
586}
587
588impl ViewModifier for GungnirPulseModifier {
589 fn modify<V: View>(self, content: V) -> impl View {
590 ModifiedView::new(content, self)
591 }
592
593 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
594 let time = std::time::SystemTime::now()
595 .duration_since(std::time::UNIX_EPOCH)
596 .unwrap_or_default()
597 .as_secs_f32();
598
599 let intensity = (time * self.speed).sin() * 0.5 + 0.5;
602 let mut color = self.color;
603 color[3] *= intensity;
604
605 renderer.stroke_rect(rect, color, self.radius);
607 }
608}
609
610#[derive(Debug, Clone, PartialEq)]
612pub struct SleipnirModifier<T> {
613 pub target: T,
614 pub stiffness: f32,
615 pub damping: f32,
616}
617
618impl<T: Send + Sync + 'static + Clone> ViewModifier for SleipnirModifier<T> {
619 fn modify<V: View>(self, content: V) -> impl View {
620 ModifiedView::new(content, self)
621 }
622}
623
624#[derive(Clone)]
626pub struct LifecycleModifier {
627 pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
628 pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
629}
630
631impl ViewModifier for LifecycleModifier {
632 fn modify<V: View>(self, content: V) -> impl View {
633 ModifiedView::new(content, self)
634 }
635}
636
637#[derive(Debug, Clone, Copy, PartialEq)]
640pub struct OpacityModifier {
641 pub opacity: f32,
642}
643
644impl ViewModifier for OpacityModifier {
645 fn modify<V: View>(self, content: V) -> impl View {
646 ModifiedView::new(content, self)
647 }
648
649 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
650 renderer.push_opacity(self.opacity);
651 }
652
653 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
654 renderer.pop_opacity();
655 }
656}
657
658#[derive(Clone)]
660pub struct OnClickModifier {
661 pub action: Arc<dyn Fn() + Send + Sync>,
662}
663
664impl ViewModifier for OnClickModifier {
665 fn modify<V: View>(self, content: V) -> impl View {
666 ModifiedView::new(content, self)
667 }
668
669 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
670 let action = self.action.clone();
671 renderer.register_handler(
672 "pointerclick",
673 std::sync::Arc::new(move |event| {
674 if let Event::PointerClick { .. } = event {
675 (action)();
676 }
677 }),
678 );
679 }
680}
681
682#[derive(Clone)]
684pub struct OnPointerEnterModifier {
685 pub action: Arc<dyn Fn() + Send + Sync>,
686}
687
688impl ViewModifier for OnPointerEnterModifier {
689 fn modify<V: View>(self, content: V) -> impl View {
690 ModifiedView::new(content, self)
691 }
692
693 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
694 let action = self.action.clone();
695 renderer.register_handler(
696 "pointerenter",
697 std::sync::Arc::new(move |event| {
698 if let Event::PointerEnter = event {
699 (action)();
700 }
701 }),
702 );
703 }
704}
705
706#[derive(Clone)]
708pub struct OnPointerLeaveModifier {
709 pub action: Arc<dyn Fn() + Send + Sync>,
710}
711
712impl ViewModifier for OnPointerLeaveModifier {
713 fn modify<V: View>(self, content: V) -> impl View {
714 ModifiedView::new(content, self)
715 }
716
717 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
718 let action = self.action.clone();
719 renderer.register_handler(
720 "pointerleave",
721 std::sync::Arc::new(move |event| {
722 if let Event::PointerLeave = event {
723 (action)();
724 }
725 }),
726 );
727 }
728}
729
730#[derive(Clone)]
732pub struct OnPointerMoveModifier {
733 pub action: Arc<dyn Fn(f32, f32) + Send + Sync>,
734}
735
736impl ViewModifier for OnPointerMoveModifier {
737 fn modify<V: View>(self, content: V) -> impl View {
738 ModifiedView::new(content, self)
739 }
740
741 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
742 let action = self.action.clone();
743 renderer.register_handler(
744 "pointermove",
745 std::sync::Arc::new(move |event| {
746 if let Event::PointerMove { x, y } = event {
747 (action)(x, y);
748 }
749 }),
750 );
751 }
752}
753
754#[derive(Clone)]
756pub struct OnPointerDownModifier {
757 pub action: Arc<dyn Fn() + Send + Sync>,
758}
759
760impl ViewModifier for OnPointerDownModifier {
761 fn modify<V: View>(self, content: V) -> impl View {
762 ModifiedView::new(content, self)
763 }
764
765 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
766 let action = self.action.clone();
767 renderer.register_handler(
768 "pointerdown",
769 std::sync::Arc::new(move |event| {
770 if let Event::PointerDown { .. } = event {
771 (action)();
772 }
773 }),
774 );
775 }
776}
777
778#[derive(Clone)]
780pub struct OnPointerUpModifier {
781 pub action: Arc<dyn Fn() + Send + Sync>,
782}
783
784impl ViewModifier for OnPointerUpModifier {
785 fn modify<V: View>(self, content: V) -> impl View {
786 ModifiedView::new(content, self)
787 }
788
789 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
790 let action = self.action.clone();
791 renderer.register_handler(
792 "pointerup",
793 std::sync::Arc::new(move |event| {
794 if let Event::PointerUp { .. } = event {
795 (action)();
796 }
797 }),
798 );
799 }
800}
801
802#[derive(Debug, Clone, Copy, PartialEq)]
805pub struct ForegroundColorModifier {
806 pub color: [f32; 4],
807}
808
809impl ViewModifier for ForegroundColorModifier {
810 fn modify<V: View>(self, content: V) -> impl View {
811 ModifiedView::new(content, self)
812 }
813}
814
815#[derive(Debug, Clone, Copy, PartialEq, Eq)]
818pub struct ClipModifier;
819
820impl ViewModifier for ClipModifier {
821 fn modify<V: View>(self, content: V) -> impl View {
822 ModifiedView::new(content, self)
823 }
824
825 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
826 renderer.push_clip_rect(rect);
827 }
828
829 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
830 renderer.pop_clip_rect();
831 }
832}
833
834#[derive(Debug, Clone, Copy, PartialEq)]
836pub struct BorderModifier {
837 pub color: [f32; 4],
838 pub width: f32,
839}
840
841impl ViewModifier for BorderModifier {
842 fn modify<V: View>(self, content: V) -> impl View {
843 ModifiedView::new(content, self)
844 }
845
846 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
847 renderer.stroke_rect(rect, self.color, self.width);
848 }
849}
850
851#[doc(hidden)]
853pub enum Never {}
854
855impl View for Never {
856 type Body = Never;
857 fn body(self) -> Never {
858 unreachable!()
859 }
860}
861
862pub struct ModifiedView<V, M> {
866 view: V,
867 modifier: M,
868}
869
870impl<V: View, M: ViewModifier> ModifiedView<V, M> {
871 #[doc(hidden)]
872 pub fn new(view: V, modifier: M) -> Self {
873 Self { view, modifier }
874 }
875}
876
877impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
878 type Body = ModifiedView<V::Body, M>;
879
880 fn body(self) -> Self::Body {
881 ModifiedView {
882 view: self.view.body(),
883 modifier: self.modifier.clone(),
884 }
885 }
886
887 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
888 self.modifier.render_view(&self.view, renderer, rect);
889 }
890
891 fn intrinsic_size(&self, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
892 self.modifier.measure_view(&self.view, renderer, proposal)
893 }
894
895 fn flex_weight(&self) -> f32 {
896 self.modifier.child_flex_weight(&self.view)
897 }
898}
899
900pub trait ViewModifier: Send + Clone {
901 fn modify<V: View>(self, content: V) -> impl View;
902
903 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
905
906 fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
908
909 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
912 self.render(renderer, rect);
913 let child_rect = self.transform_rect(rect);
914 view.render(renderer, child_rect);
915 self.post_render(renderer, rect);
916 }
917
918 fn transform_rect(&self, rect: Rect) -> Rect {
919 rect
920 }
921
922 fn transform_proposal(&self, proposal: SizeProposal) -> SizeProposal {
924 proposal
925 }
926
927 fn transform_size(&self, size: Size) -> Size {
929 size
930 }
931
932 fn measure_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
934 let child_proposal = self.transform_proposal(proposal);
935 let child_size = view.intrinsic_size(renderer, child_proposal);
936 self.transform_size(child_size)
937 }
938
939 fn child_flex_weight<V: View>(&self, view: &V) -> f32 {
941 view.flex_weight()
942 }
943}
944
945#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
947pub struct TelemetryData {
948 pub frame_time_ms: f32,
949 pub draw_calls: u32,
950 pub vertices: u32,
951 pub vram_usage_mb: f32,
952}
953
954pub trait Renderer: Send {
962 fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
964 fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
965 fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
967
968 fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
970 fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
971 fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
973 fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
975
976 fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
978 fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
980
981 fn draw_texture(&mut self, texture_id: u32, rect: Rect);
984 fn draw_image(&mut self, image_name: &str, rect: Rect);
986 fn load_image(&mut self, name: &str, data: &[u8]);
988
989 fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
992 fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
994
995 fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
998
999 fn draw_linear_gradient(
1002 &mut self,
1003 _rect: Rect,
1004 _start_color: [f32; 4],
1005 _end_color: [f32; 4],
1006 _angle: f32,
1007 ) {
1008 }
1009 fn draw_radial_gradient(
1011 &mut self,
1012 _rect: Rect,
1013 _inner_color: [f32; 4],
1014 _outer_color: [f32; 4],
1015 ) {
1016 }
1017 fn draw_drop_shadow(
1019 &mut self,
1020 _rect: Rect,
1021 _radius: f32,
1022 _color: [f32; 4],
1023 _blur: f32,
1024 _spread: f32,
1025 ) {
1026 }
1027 fn stroke_dashed_rounded_rect(
1029 &mut self,
1030 _rect: Rect,
1031 _radius: f32,
1032 _color: [f32; 4],
1033 _width: f32,
1034 _dash: f32,
1035 _gap: f32,
1036 ) {
1037 }
1038 fn draw_9slice(
1040 &mut self,
1041 _image_name: &str,
1042 _rect: Rect,
1043 _left: f32,
1044 _top: f32,
1045 _right: f32,
1046 _bottom: f32,
1047 ) {
1048 }
1049
1050 fn push_clip_rect(&mut self, rect: Rect);
1054 fn pop_clip_rect(&mut self);
1056
1057 fn push_opacity(&mut self, opacity: f32);
1061 fn pop_opacity(&mut self);
1063
1064 fn set_theme(&mut self, _theme: ColorTheme) {}
1066 fn set_rage(&mut self, _rage: f32) {}
1067 fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
1068
1069 fn bifrost(&mut self, rect: Rect, blur: f32, saturation: f32, opacity: f32);
1072 fn push_mjolnir_slice(&mut self, angle: f32, offset: f32);
1074 fn pop_mjolnir_slice(&mut self);
1076 fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1078 fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1079 fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
1081
1082 fn set_aria_role(&mut self, _role: &str) {}
1084 fn set_aria_label(&mut self, _label: &str) {}
1085
1086 fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
1088
1089 fn set_key(&mut self, _key: &str) {}
1091
1092 fn get_telemetry(&self) -> TelemetryData {
1095 TelemetryData::default()
1096 }
1097
1098 fn push_shadow(&mut self, _radius: f32, _color: [f32; 4], _offset: [f32; 2]) {}
1101 fn pop_shadow(&mut self) {}
1103
1104 fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
1107 fn pop_vnode(&mut self) {}
1109 fn register_handler(
1111 &mut self,
1112 _event_type: &str,
1113 _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
1114 ) {
1115 }
1116
1117 fn set_z_index(&mut self, _z: f32) {}
1121 fn get_z_index(&self) -> f32 {
1123 0.0
1124 }
1125
1126 fn load_svg(&mut self, _name: &str, _svg_data: &[u8]) {}
1129 fn draw_svg(&mut self, _name: &str, _rect: Rect) {}
1131}
1132
1133use bytemuck::{Pod, Zeroable};
1138
1139#[repr(C)]
1141#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1142pub struct ColorTheme {
1143 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
1145 pub glass_base: [f32; 4],
1146 pub glass_edge: [f32; 4],
1147 pub rune_glow: [f32; 4],
1148 pub ember_core: [f32; 4],
1149 pub background_deep: [f32; 4],
1150 pub glass_blur_strength: f32,
1151 pub shatter_edge_width: f32,
1152 pub neon_bloom_radius: f32,
1153 pub rune_opacity: f32, pub _pad: [f32; 3], pub _pad2: f32,
1157}
1158
1159impl ColorTheme {
1160 pub fn cyberpunk_viking() -> Self {
1161 Self {
1162 primary_neon: [0.0, 1.0, 0.95, 1.2],
1163 shatter_neon: [1.0, 0.0, 0.75, 1.5],
1164 glass_base: [0.04, 0.04, 0.06, 0.82],
1165 glass_edge: [0.0, 0.45, 0.55, 0.6],
1166 rune_glow: [0.75, 0.98, 1.0, 0.9],
1167 ember_core: [0.95, 0.12, 0.12, 1.0],
1168 background_deep: [0.01, 0.01, 0.03, 1.0],
1169 glass_blur_strength: 0.6,
1170 shatter_edge_width: 1.8,
1171 neon_bloom_radius: 0.022,
1172 rune_opacity: 0.55,
1173 _pad: [0.0; 3],
1174 _pad2: 0.0,
1175 }
1176 }
1177
1178 pub fn vibrant_glass() -> Self {
1179 Self {
1180 primary_neon: [0.0, 1.0, 0.95, 1.2],
1181 shatter_neon: [1.0, 0.0, 0.75, 1.5],
1182 glass_base: [0.55, 0.6, 0.7, 0.08], glass_edge: [0.7, 0.85, 1.0, 0.45], rune_glow: [0.75, 0.98, 1.0, 0.9],
1185 ember_core: [1.0, 0.4, 0.1, 1.0],
1186 background_deep: [0.05, 0.05, 0.1, 1.0],
1187 glass_blur_strength: 0.9,
1188 shatter_edge_width: 1.8,
1189 neon_bloom_radius: 0.022,
1190 rune_opacity: 0.55,
1191 _pad: [0.0; 3],
1192 _pad2: 0.0,
1193 }
1194 }
1195}
1196
1197impl Default for ColorTheme {
1198 fn default() -> Self {
1199 Self::vibrant_glass()
1200 }
1201}
1202
1203#[repr(C)]
1205#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1206pub struct SceneUniforms {
1207 pub view: glam::Mat4,
1208 pub proj: glam::Mat4,
1209 pub time: f32,
1210 pub delta_time: f32,
1211 pub resolution: [f32; 2],
1212 pub mouse: [f32; 2],
1213 pub mouse_velocity: [f32; 2],
1214 pub shatter_origin: [f32; 2],
1215 pub shatter_time: f32,
1216 pub shatter_force: f32,
1217 pub berzerker_rage: f32,
1218 pub scroll_offset: f32,
1219 pub scale_factor: f32,
1220 pub _pad: [f32; 1],
1222}
1223
1224impl SceneUniforms {
1225 pub fn new(width: f32, height: f32) -> Self {
1226 Self {
1227 view: glam::Mat4::IDENTITY,
1228 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
1229 time: 0.0,
1230 delta_time: 0.016,
1231 resolution: [width, height],
1232 mouse: [0.5, 0.5],
1233 mouse_velocity: [0.0, 0.0],
1234 shatter_origin: [0.5, 0.5],
1235 shatter_time: -100.0,
1236 shatter_force: 0.0,
1237 berzerker_rage: 0.0,
1238 scroll_offset: 0.0,
1239 scale_factor: 1.0,
1240 _pad: [0.0; 1],
1241 }
1242 }
1243}
1244
1245#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1247pub struct Mesh {
1248 pub vertices: Vec<[f32; 3]>,
1249 pub normals: Vec<[f32; 3]>,
1250 pub indices: Vec<u32>,
1251}
1252
1253impl Mesh {
1254 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
1255 let mut cursor = std::io::Cursor::new(data);
1256 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
1257 Ok((Vec::new(), Default::default()))
1258 })?;
1259
1260 let mut meshes = Vec::new();
1261 for m in models {
1262 let mesh = m.mesh;
1263 let vertices: Vec<[f32; 3]> = mesh
1264 .positions
1265 .chunks(3)
1266 .map(|c| [c[0], c[1], c[2]])
1267 .collect();
1268 let normals = if mesh.normals.is_empty() {
1269 vec![[0.0, 0.0, 1.0]; vertices.len()]
1270 } else {
1271 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
1272 };
1273 meshes.push(Mesh {
1274 vertices,
1275 normals,
1276 indices: mesh.indices,
1277 });
1278 }
1279 Ok(meshes)
1280 }
1281
1282 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
1283 let mut cursor = std::io::Cursor::new(data);
1284 let stl = stl_io::read_stl(&mut cursor)?;
1285
1286 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
1287 let mut indices = Vec::new();
1288 for face in stl.faces {
1289 indices.push(face.vertices[0] as u32);
1290 indices.push(face.vertices[1] as u32);
1291 indices.push(face.vertices[2] as u32);
1292 }
1293
1294 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
1295
1296 Ok(Mesh {
1297 vertices,
1298 normals,
1299 indices,
1300 })
1301 }
1302}
1303
1304pub trait FrameRenderer<E = ()>: Renderer {
1307 fn begin_frame(&mut self) -> E;
1308 fn end_frame(&mut self, encoder: E);
1309}
1310
1311use std::sync::Arc;
1312
1313#[derive(Clone)]
1315pub struct State<T: Clone + Send + Sync + 'static> {
1316 value: Arc<std::sync::RwLock<T>>,
1317 subscribers: Arc<std::sync::RwLock<Vec<Box<dyn Fn(&T) + Send + Sync>>>>,
1318 version: Arc<std::sync::atomic::AtomicU64>,
1319}
1320
1321impl<T: Clone + Send + Sync + 'static> State<T> {
1322 pub fn new(value: T) -> Self {
1324 Self {
1325 value: Arc::new(std::sync::RwLock::new(value)),
1326 subscribers: Arc::new(std::sync::RwLock::new(Vec::new())),
1327 version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
1328 }
1329 }
1330
1331 pub fn get(&self) -> T {
1333 self.value.read().unwrap().clone()
1334 }
1335
1336 pub fn set(&self, value: T) {
1338 *self.value.write().unwrap() = value;
1339 self.version.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
1340 let subscribers = self.subscribers.read().unwrap();
1342 for subscriber in subscribers.iter() {
1343 subscriber(&self.get());
1344 }
1345 }
1346
1347 pub fn version(&self) -> u64 {
1349 self.version.load(std::sync::atomic::Ordering::SeqCst)
1350 }
1351
1352 pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
1354 self.subscribers.write().unwrap().push(Box::new(callback));
1355 }
1356}
1357
1358#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
1362pub struct ComponentErrorState {
1363 pub has_error: bool,
1364 pub error_message: Option<String>,
1365 pub error_location: Option<String>,
1366}
1367
1368impl ComponentErrorState {
1369 pub fn clear() -> Self {
1371 Self::default()
1372 }
1373
1374 pub fn error(message: impl Into<String>, location: impl Into<String>) -> Self {
1376 Self {
1377 has_error: true,
1378 error_message: Some(message.into()),
1379 error_location: Some(location.into()),
1380 }
1381 }
1382}
1383
1384#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
1386pub struct KnowledgeFragment {
1387 pub id: String,
1389 pub summary: String,
1391 pub source: String,
1393 pub created_at: u64,
1395 pub accessed_count: u32,
1397 pub content: Option<String>,
1399}
1400
1401#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1404pub struct KnowledgeState {
1405 #[serde(skip)]
1407 pub component_states: std::collections::HashMap<u64, Arc<dyn std::any::Any + Send + Sync>>,
1408
1409 pub fragments: HashMap<String, KnowledgeFragment>,
1411
1412 pub last_query_results: Vec<String>,
1414}
1415
1416use crate::runtime::NodeStateSnapshot;
1417use std::sync::OnceLock;
1418
1419pub static SYSTEM_STATE: OnceLock<Arc<std::sync::RwLock<KnowledgeState>>> = OnceLock::new();
1421
1422pub fn get_system_state() -> Arc<std::sync::RwLock<KnowledgeState>> {
1424 SYSTEM_STATE
1425 .get_or_init(|| Arc::new(std::sync::RwLock::new(KnowledgeState::default())))
1426 .clone()
1427}
1428
1429impl KnowledgeState {
1430 pub fn new() -> Self {
1432 Self::default()
1433 }
1434
1435 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
1437 self.component_states
1438 .insert(id, Arc::new(std::sync::RwLock::new(state)));
1439 }
1440
1441 pub fn get_component_state<T: 'static + Send + Sync>(
1443 &self,
1444 id: u64,
1445 ) -> Option<Arc<std::sync::RwLock<T>>> {
1446 let lock = self.component_states.get(&id)?;
1447 lock.clone().downcast::<std::sync::RwLock<T>>().ok()
1448 }
1449
1450 pub fn remember(&mut self, fragment: KnowledgeFragment) {
1452 self.fragments.insert(fragment.id.clone(), fragment);
1453 }
1454
1455 pub fn process_query(&mut self, query: &str) {
1457 let query_lower = query.to_lowercase();
1458 let mut results: Vec<(f32, String)> = self
1459 .fragments
1460 .iter()
1461 .map(|(id, frag)| {
1462 let mut score = 0.0;
1463 if frag.summary.to_lowercase().contains(&query_lower) {
1464 score += 1.0;
1465 }
1466 if frag.source.to_lowercase().contains(&query_lower) {
1467 score += 0.5;
1468 }
1469 (score, id.clone())
1470 })
1471 .filter(|(score, _)| *score > 0.0)
1472 .collect();
1473
1474 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
1476
1477 self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
1478 }
1479
1480 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
1482 let mut snapshots = Vec::new();
1483
1484 for (_id, frag) in &self.fragments {
1486 if let Ok(val) = serde_json::to_value(frag) {
1487 snapshots.push(NodeStateSnapshot { id: 0, state: val });
1488 }
1489 }
1490
1491 snapshots
1492 }
1493}
1494
1495#[derive(Clone)]
1497pub struct Binding<T: Clone + Send + Sync + 'static> {
1498 state: Arc<std::sync::RwLock<T>>,
1499 version: Arc<std::sync::atomic::AtomicU64>,
1500}
1501
1502impl<T: Clone + Send + Sync + 'static> Binding<T> {
1503 pub fn from_state(state: &State<T>) -> Self {
1505 Self {
1506 state: state.value.clone(),
1507 version: state.version.clone(),
1508 }
1509 }
1510
1511 pub fn get(&self) -> T {
1513 self.state.read().unwrap().clone()
1514 }
1515
1516 pub fn set(&self, value: T) {
1518 *self.state.write().unwrap() = value;
1519 self.version.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
1520 }
1521
1522 pub fn version(&self) -> u64 {
1524 self.version.load(std::sync::atomic::Ordering::SeqCst)
1525 }
1526}
1527
1528use std::any::TypeId;
1529use std::sync::Mutex;
1530
1531pub(crate) static ENVIRONMENT: OnceLock<
1533 Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
1534> = OnceLock::new();
1535
1536pub trait EnvKey: 'static + Send + Sync {
1540 type Value: Clone + Send + Sync + 'static;
1542
1543 fn default_value() -> Self::Value;
1545}
1546
1547pub struct YggdrasilKey;
1549
1550impl EnvKey for YggdrasilKey {
1551 type Value = YggdrasilTokens;
1552 fn default_value() -> Self::Value {
1553 default_tokens()
1554 }
1555}
1556
1557pub struct AssetKey;
1559
1560impl EnvKey for AssetKey {
1561 type Value = Arc<dyn AssetManager>;
1562 fn default_value() -> Self::Value {
1563 Arc::new(DefaultAssetManager::new())
1564 }
1565}
1566
1567#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1569pub enum Appearance {
1570 Light,
1571 Dark,
1572}
1573
1574#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1576pub enum Orientation {
1577 Horizontal,
1578 Vertical,
1579}
1580
1581#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
1583pub enum Alignment {
1584 #[default]
1585 Center,
1586 Leading,
1587 Trailing,
1588 Top,
1589 Bottom,
1590}
1591
1592#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
1594pub enum Distribution {
1595 #[default]
1596 Fill,
1597 Center,
1598 Leading,
1599 Trailing,
1600 SpaceBetween,
1601 SpaceAround,
1602 SpaceEvenly,
1603}
1604
1605#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
1607pub struct Color {
1608 pub r: f32,
1609 pub g: f32,
1610 pub b: f32,
1611 pub a: f32,
1612}
1613
1614impl Color {
1615 pub const BLACK: Color = Color {
1616 r: 0.0,
1617 g: 0.0,
1618 b: 0.0,
1619 a: 1.0,
1620 };
1621 pub const WHITE: Color = Color {
1622 r: 1.0,
1623 g: 1.0,
1624 b: 1.0,
1625 a: 1.0,
1626 };
1627 pub const TRANSPARENT: Color = Color {
1628 r: 0.0,
1629 g: 0.0,
1630 b: 0.0,
1631 a: 0.0,
1632 };
1633 pub const RED: Color = Color {
1634 r: 1.0,
1635 g: 0.0,
1636 b: 0.0,
1637 a: 1.0,
1638 };
1639 pub const GREEN: Color = Color {
1640 r: 0.0,
1641 g: 1.0,
1642 b: 0.0,
1643 a: 1.0,
1644 };
1645 pub const BLUE: Color = Color {
1646 r: 0.0,
1647 g: 0.0,
1648 b: 1.0,
1649 a: 1.0,
1650 };
1651
1652 pub fn relative_luminance(&self) -> f32 {
1654 fn res(c: f32) -> f32 {
1655 if c <= 0.03928 {
1656 c / 12.92
1657 } else {
1658 ((c + 0.055) / 1.055).powf(2.4)
1659 }
1660 }
1661 0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
1662 }
1663
1664 pub fn contrast_ratio(&self, other: &Color) -> f32 {
1666 let l1 = self.relative_luminance();
1667 let l2 = other.relative_luminance();
1668 if l1 > l2 {
1669 (l1 + 0.05) / (l2 + 0.05)
1670 } else {
1671 (l2 + 0.05) / (l1 + 0.05)
1672 }
1673 }
1674
1675 pub const CYAN: Color = Color {
1676 r: 0.0,
1677 g: 1.0,
1678 b: 1.0,
1679 a: 1.0,
1680 };
1681 pub const YELLOW: Color = Color {
1682 r: 1.0,
1683 g: 1.0,
1684 b: 0.0,
1685 a: 1.0,
1686 };
1687 pub const MAGENTA: Color = Color {
1688 r: 1.0,
1689 g: 0.0,
1690 b: 1.0,
1691 a: 1.0,
1692 };
1693 pub const GRAY: Color = Color {
1694 r: 0.5,
1695 g: 0.5,
1696 b: 0.5,
1697 a: 1.0,
1698 };
1699
1700 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
1702 Self { r, g, b, a }
1703 }
1704
1705 pub fn as_array(&self) -> [f32; 4] {
1707 [self.r, self.g, self.b, self.a]
1708 }
1709}
1710
1711impl View for Color {
1712 type Body = Never;
1713 fn body(self) -> Self::Body {
1714 unreachable!()
1715 }
1716
1717 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1718 renderer.fill_rect(rect, self.as_array());
1719 }
1720}
1721
1722pub struct AppearanceKey;
1724
1725impl EnvKey for AppearanceKey {
1726 type Value = Appearance;
1727 fn default_value() -> Self::Value {
1728 Appearance::Dark }
1730}
1731
1732pub struct StyleResolver;
1734
1735impl StyleResolver {
1736 pub fn color(key: &str) -> String {
1738 let tokens = Environment::<YggdrasilKey>::new().get();
1739 let appearance = Environment::<AppearanceKey>::new().get();
1740 let is_dark = appearance == Appearance::Dark;
1741
1742 tokens
1743 .get_color(key, is_dark)
1744 .unwrap_or_else(|| "#FF00FF".to_string()) }
1746
1747 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
1749 let tokens = Environment::<YggdrasilKey>::new().get();
1750 let appearance = Environment::<AppearanceKey>::new().get();
1751 let is_dark = appearance == Appearance::Dark;
1752
1753 tokens.get(category, key, is_dark)
1754 }
1755}
1756
1757pub fn default_tokens() -> YggdrasilTokens {
1759 let mut tokens = YggdrasilTokens::new();
1760
1761 tokens.color.insert(
1763 "background".to_string(),
1764 TokenValue::Single {
1765 value: "#000000".to_string(), },
1767 );
1768
1769 tokens.color.insert(
1770 "primary".to_string(),
1771 TokenValue::Single {
1772 value: "#00FFFF".to_string(), },
1774 );
1775
1776 tokens.color.insert(
1777 "secondary".to_string(),
1778 TokenValue::Single {
1779 value: "#FF00FF".to_string(), },
1781 );
1782
1783 tokens.color.insert(
1784 "surface".to_string(),
1785 TokenValue::Adaptive {
1786 light: "#FFFFFF".to_string(),
1787 dark: "#121212".to_string(),
1788 },
1789 );
1790
1791 tokens.color.insert(
1792 "text".to_string(),
1793 TokenValue::Adaptive {
1794 light: "#000000".to_string(),
1795 dark: "#FFFFFF".to_string(),
1796 },
1797 );
1798
1799 tokens.bifrost.insert(
1801 "blur".to_string(),
1802 TokenValue::Single {
1803 value: "25.0".to_string(),
1804 },
1805 );
1806 tokens.bifrost.insert(
1807 "saturation".to_string(),
1808 TokenValue::Single {
1809 value: "1.2".to_string(),
1810 },
1811 );
1812 tokens.bifrost.insert(
1813 "opacity".to_string(),
1814 TokenValue::Single {
1815 value: "0.65".to_string(),
1816 },
1817 );
1818
1819 tokens.gungnir.insert(
1821 "intensity".to_string(),
1822 TokenValue::Single {
1823 value: "1.0".to_string(),
1824 },
1825 );
1826 tokens.gungnir.insert(
1827 "radius".to_string(),
1828 TokenValue::Single {
1829 value: "15.0".to_string(),
1830 },
1831 );
1832
1833 tokens.mjolnir.insert(
1835 "clip_angle".to_string(),
1836 TokenValue::Single {
1837 value: "12.0".to_string(),
1838 },
1839 );
1840 tokens.mjolnir.insert(
1841 "border_width".to_string(),
1842 TokenValue::Single {
1843 value: "2.0".to_string(),
1844 },
1845 );
1846
1847 tokens.anim.insert(
1849 "stiffness".to_string(),
1850 TokenValue::Single {
1851 value: "170.0".to_string(),
1852 },
1853 );
1854 tokens.anim.insert(
1855 "damping".to_string(),
1856 TokenValue::Single {
1857 value: "26.0".to_string(),
1858 },
1859 );
1860 tokens.anim.insert(
1861 "mass".to_string(),
1862 TokenValue::Single {
1863 value: "1.0".to_string(),
1864 },
1865 );
1866
1867 tokens.accessibility.insert(
1869 "reduce_motion".to_string(),
1870 TokenValue::Single {
1871 value: "false".to_string(),
1872 },
1873 );
1874
1875 tokens
1876}
1877
1878pub struct Environment<K: EnvKey> {
1880 _marker: std::marker::PhantomData<K>,
1881}
1882
1883impl<K: EnvKey> Environment<K> {
1884 pub fn new() -> Self {
1886 Self {
1887 _marker: std::marker::PhantomData,
1888 }
1889 }
1890
1891 pub fn get(&self) -> K::Value {
1893 if let Some(env_store) = ENVIRONMENT.get() {
1894 let env_lock = env_store.lock().unwrap();
1895 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
1896 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
1897 return typed_val.clone();
1898 }
1899 }
1900 }
1901 K::default_value()
1902 }
1903}
1904
1905pub mod env {
1907
1908 pub fn insert<K: super::EnvKey>(value: K::Value) {
1910 if let Some(store) = super::ENVIRONMENT.get() {
1911 let mut env_map = store.lock().unwrap();
1912 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
1913 }
1914 }
1915
1916 pub fn remove<K: super::EnvKey>() {
1918 if let Some(store) = super::ENVIRONMENT.get() {
1919 let mut env_map = store.lock().unwrap();
1920 env_map.remove(&std::any::TypeId::of::<K>());
1921 }
1922 }
1923}
1924
1925#[derive(Debug, Clone, Copy, PartialEq)]
1929pub struct Size {
1930 pub width: f32,
1931 pub height: f32,
1932}
1933
1934impl Size {
1935 pub const ZERO: Self = Self { width: 0.0, height: 0.0 };
1936
1937 pub fn new(width: f32, height: f32) -> Self {
1938 Self { width, height }
1939 }
1940}
1941
1942#[derive(Debug, Clone, Copy, PartialEq)]
1944pub struct EdgeInsets {
1945 pub top: f32,
1946 pub leading: f32,
1947 pub bottom: f32,
1948 pub trailing: f32,
1949}
1950
1951impl EdgeInsets {
1952 pub fn all(value: f32) -> Self {
1954 Self {
1955 top: value,
1956 leading: value,
1957 bottom: value,
1958 trailing: value,
1959 }
1960 }
1961
1962 pub fn vertical(value: f32) -> Self {
1964 Self {
1965 top: value,
1966 leading: 0.0,
1967 bottom: value,
1968 trailing: 0.0,
1969 }
1970 }
1971
1972 pub fn horizontal(value: f32) -> Self {
1974 Self {
1975 top: 0.0,
1976 leading: value,
1977 bottom: 0.0,
1978 trailing: value,
1979 }
1980 }
1981}
1982
1983#[derive(Debug, Clone, Copy, PartialEq)]
1985pub struct FrameModifier {
1986 pub width: Option<f32>,
1987 pub height: Option<f32>,
1988}
1989
1990impl FrameModifier {
1991 pub fn new() -> Self {
1992 Self {
1993 width: None,
1994 height: None,
1995 }
1996 }
1997
1998 pub fn width(mut self, width: f32) -> Self {
1999 self.width = Some(width);
2000 self
2001 }
2002
2003 pub fn height(mut self, height: f32) -> Self {
2004 self.height = Some(height);
2005 self
2006 }
2007
2008 pub fn size(mut self, width: f32, height: f32) -> Self {
2009 self.width = Some(width);
2010 self.height = Some(height);
2011 self
2012 }
2013}
2014
2015impl ViewModifier for FrameModifier {
2016 fn modify<V: View>(self, content: V) -> impl View {
2017 ModifiedView::new(content, self)
2018 }
2019}
2020
2021#[derive(Debug, Clone, Copy, PartialEq)]
2023pub struct FlexModifier {
2024 pub weight: f32,
2025}
2026
2027impl ViewModifier for FlexModifier {
2028 fn modify<V: View>(self, content: V) -> impl View {
2029 ModifiedView::new(content, self)
2030 }
2031
2032 fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
2033 self.weight
2034 }
2035}
2036
2037#[derive(Debug, Clone, Copy, PartialEq)]
2039pub struct OffsetModifier {
2040 pub x: f32,
2041 pub y: f32,
2042}
2043
2044impl OffsetModifier {
2045 pub fn new(x: f32, y: f32) -> Self {
2046 Self { x, y }
2047 }
2048}
2049
2050impl ViewModifier for OffsetModifier {
2051 fn modify<V: View>(self, content: V) -> impl View {
2052 ModifiedView::new(content, self)
2053 }
2054}
2055
2056#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2058pub struct ZIndexModifier {
2059 pub z_index: i32,
2060}
2061
2062impl ZIndexModifier {
2063 pub fn new(z_index: i32) -> Self {
2064 Self { z_index }
2065 }
2066}
2067
2068impl ViewModifier for ZIndexModifier {
2069 fn modify<V: View>(self, content: V) -> impl View {
2070 ModifiedView::new(content, self)
2071 }
2072}
2073
2074#[derive(Debug, Clone, Copy, PartialEq)]
2076pub struct LayoutConstraints {
2077 pub min_width: Option<f32>,
2078 pub max_width: Option<f32>,
2079 pub min_height: Option<f32>,
2080 pub max_height: Option<f32>,
2081}
2082
2083impl Default for LayoutConstraints {
2084 fn default() -> Self {
2085 Self {
2086 min_width: None,
2087 max_width: None,
2088 min_height: None,
2089 max_height: None,
2090 }
2091 }
2092}
2093
2094#[derive(Debug, Clone, Copy, PartialEq)]
2096pub struct LayoutModifier {
2097 pub constraints: LayoutConstraints,
2098}
2099
2100impl LayoutModifier {
2101 pub fn new(constraints: LayoutConstraints) -> Self {
2102 Self { constraints }
2103 }
2104}
2105
2106impl ViewModifier for LayoutModifier {
2107 fn modify<V: View>(self, content: V) -> impl View {
2108 ModifiedView::new(content, self)
2109 }
2110}
2111
2112#[derive(Debug, Clone, Copy, PartialEq)]
2114pub struct SafeAreaModifier {
2115 pub ignores: bool,
2116}
2117
2118impl ViewModifier for SafeAreaModifier {
2119 fn modify<V: View>(self, content: V) -> impl View {
2120 ModifiedView::new(content, self)
2121 }
2122}
2123
2124#[derive(Debug, Clone, Copy, PartialEq)]
2126pub struct ElevationModifier {
2127 pub level: f32,
2128}
2129
2130impl ViewModifier for ElevationModifier {
2131 fn modify<V: View>(self, content: V) -> impl View {
2132 ModifiedView::new(content, self)
2133 }
2134
2135 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
2136 if self.level > 0.0 {
2137 let radius = self.level * 2.0;
2138 let offset_y = self.level * 0.5;
2139 let shadow_color = [0.0, 0.0, 0.0, 0.3];
2140 renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
2141 view.render(renderer, rect);
2142 renderer.pop_shadow();
2143 } else {
2144 view.render(renderer, rect);
2145 }
2146 }
2147}
2148
2149pub mod layout {
2151 use super::*;
2152
2153 pub struct LayoutCache {
2155 pub safe_area: SafeArea,
2156 size_cache: HashMap<(u64, u32, u32), Size>, }
2158
2159 impl LayoutCache {
2160 pub fn new() -> Self {
2161 Self {
2162 safe_area: SafeArea::default(),
2163 size_cache: HashMap::new(),
2164 }
2165 }
2166
2167 pub fn clear(&mut self) {
2168 self.safe_area = SafeArea::default();
2169 self.size_cache.clear();
2170 }
2171
2172 pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
2173 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2174 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2175 self.size_cache.get(&(view_hash, pw, ph)).copied()
2176 }
2177
2178 pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: Size) {
2179 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2180 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2181 self.size_cache.insert((view_hash, pw, ph), size);
2182 }
2183 }
2184
2185 #[derive(Debug, Clone, Copy, PartialEq)]
2187 pub struct SizeProposal {
2188 pub width: Option<f32>,
2189 pub height: Option<f32>,
2190 }
2191
2192 impl SizeProposal {
2193 pub fn unspecified() -> Self {
2194 Self {
2195 width: None,
2196 height: None,
2197 }
2198 }
2199
2200 pub fn width(width: f32) -> Self {
2201 Self {
2202 width: Some(width),
2203 height: None,
2204 }
2205 }
2206
2207 pub fn height(height: f32) -> Self {
2208 Self {
2209 width: None,
2210 height: Some(height),
2211 }
2212 }
2213
2214 pub fn tight(width: f32, height: f32) -> Self {
2215 Self {
2216 width: Some(width),
2217 height: Some(height),
2218 }
2219 }
2220
2221 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
2222 Self { width, height }
2223 }
2224 }
2225
2226 pub trait LayoutView: Send {
2228 fn size_that_fits(
2230 &self,
2231 proposal: SizeProposal,
2232 subviews: &[&dyn LayoutView],
2233 cache: &mut LayoutCache,
2234 ) -> Size;
2235
2236 fn place_subviews(
2238 &self,
2239 bounds: Rect,
2240 subviews: &mut [&mut dyn LayoutView],
2241 cache: &mut LayoutCache,
2242 );
2243
2244 fn flex_weight(&self) -> f32 {
2246 0.0
2247 }
2248 }
2249 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2251 pub struct EdgeInsets {
2252 pub top: f32,
2253 pub leading: f32,
2254 pub bottom: f32,
2255 pub trailing: f32,
2256 }
2257
2258 impl EdgeInsets {
2259 pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
2260 Self { top, leading, bottom, trailing }
2261 }
2262
2263 pub fn all(value: f32) -> Self {
2264 Self {
2265 top: value,
2266 leading: value,
2267 bottom: value,
2268 trailing: value,
2269 }
2270 }
2271 }
2272
2273 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2275 pub struct SafeArea {
2276 pub insets: EdgeInsets,
2277 }
2278
2279 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2281 pub struct Rect {
2282 pub x: f32,
2283 pub y: f32,
2284 pub width: f32,
2285 pub height: f32,
2286 }
2287
2288 impl Rect {
2289 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
2290 Self {
2291 x,
2292 y,
2293 width,
2294 height,
2295 }
2296 }
2297
2298 pub fn zero() -> Self {
2299 Self {
2300 x: 0.0,
2301 y: 0.0,
2302 width: 0.0,
2303 height: 0.0,
2304 }
2305 }
2306
2307 pub fn size(&self) -> Size {
2308 Size {
2309 width: self.width,
2310 height: self.height,
2311 }
2312 }
2313
2314 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
2316 if n == 0 {
2317 return vec![];
2318 }
2319 let item_width = self.width / n as f32;
2320 (0..n)
2321 .map(|i| Rect {
2322 x: self.x + i as f32 * item_width,
2323 y: self.y,
2324 width: item_width,
2325 height: self.height,
2326 })
2327 .collect()
2328 }
2329
2330 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
2332 if n == 0 {
2333 return vec![];
2334 }
2335 let item_height = self.height / n as f32;
2336 (0..n)
2337 .map(|i| Rect {
2338 x: self.x,
2339 y: self.y + i as f32 * item_height,
2340 width: self.width,
2341 height: item_height,
2342 })
2343 .collect()
2344 }
2345 }
2346}
2347
2348pub use layout::{LayoutCache, LayoutView, Rect, SizeProposal};
2350pub mod runtime;
2353pub mod scene_graph;
2354
2355pub use scene_graph::{NodeId, bifrost_registry};
2356
2357#[derive(Debug, Clone, PartialEq)]
2359pub enum AssetState<T> {
2360 Loading,
2361 Ready(T),
2362 Error(String),
2363}
2364
2365pub trait AssetManager: Send + Sync {
2367 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
2369
2370 fn preload_image(&self, url: &str);
2372}
2373
2374#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2376pub enum Event {
2377 PointerDown { x: f32, y: f32 },
2378 PointerUp { x: f32, y: f32 },
2379 PointerMove { x: f32, y: f32 },
2380 PointerClick { x: f32, y: f32 },
2381 PointerEnter,
2382 PointerLeave,
2383 KeyDown { key: String },
2384 KeyUp { key: String },
2385 Ime(String),
2387}
2388
2389impl Event {
2390 pub fn name(&self) -> &'static str {
2392 match self {
2393 Self::PointerDown { .. } => "pointerdown",
2394 Self::PointerUp { .. } => "pointerup",
2395 Self::PointerMove { .. } => "pointermove",
2396 Self::PointerClick { .. } => "pointerclick",
2397 Self::PointerEnter => "pointerenter",
2398 Self::PointerLeave => "pointerleave",
2399 Self::KeyDown { .. } => "keydown",
2400 Self::KeyUp { .. } => "keyup",
2401 Self::Ime(_) => "ime",
2402 }
2403 }
2404}
2405
2406#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2408pub enum EventResponse {
2409 Handled,
2410 Ignored,
2411}
2412
2413pub struct DefaultAssetManager {
2415 cache: Arc<std::sync::RwLock<HashMap<String, AssetState<Arc<Vec<u8>>>>>>,
2416}
2417
2418impl DefaultAssetManager {
2419 pub fn new() -> Self {
2420 Self {
2421 cache: Arc::new(std::sync::RwLock::new(HashMap::new())),
2422 }
2423 }
2424}
2425
2426impl AssetManager for DefaultAssetManager {
2427 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
2428 let mut cache = self.cache.write().unwrap();
2429 if let Some(state) = cache.get(url) {
2430 return state.clone();
2431 }
2432
2433 cache.insert(url.to_string(), AssetState::Loading);
2436 AssetState::Loading
2437 }
2438
2439 fn preload_image(&self, _url: &str) {
2440 }
2442}
2443
2444#[cfg(test)]
2445mod phase1_test;