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 layout(&self) -> Option<&dyn layout::LayoutView> {
135 None
136 }
137
138 fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
140 ModifiedView::new(self, m)
141 }
142
143 fn bifrost(
145 self,
146 blur: f32,
147 saturation: f32,
148 opacity: f32,
149 ) -> ModifiedView<Self, BifrostModifier> {
150 self.modifier(BifrostModifier {
151 blur,
152 saturation,
153 opacity,
154 })
155 }
156
157 fn gungnir(
159 self,
160 color: impl Into<String>,
161 radius: f32,
162 intensity: f32,
163 ) -> ModifiedView<Self, GungnirModifier> {
164 self.modifier(GungnirModifier {
165 color: color.into(),
166 radius,
167 intensity,
168 })
169 }
170
171 fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
173 self.modifier(MjolnirSliceModifier { angle, offset })
174 }
175
176 fn mjolnir_shatter(
178 self,
179 pieces: u32,
180 force: f32,
181 ) -> ModifiedView<Self, MjolnirShatterModifier> {
182 self.modifier(MjolnirShatterModifier { pieces, force })
183 }
184
185 fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
187 self.modifier(BifrostBridgeModifier { id: id.into() })
188 }
189
190 fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
192 self.modifier(BackgroundModifier { color })
193 }
194
195 fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
197 self.modifier(PaddingModifier { amount })
198 }
199
200 fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
202 self.modifier(OpacityModifier {
203 opacity: opacity.clamp(0.0, 1.0),
204 })
205 }
206
207 fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
209 self.modifier(ForegroundColorModifier { color })
210 }
211
212 fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
214 self.modifier(FrameModifier { width, height })
215 }
216
217 fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
219 self.modifier(ClipModifier)
220 }
221
222 fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
224 self.modifier(BorderModifier { color, width })
225 }
226
227 fn on_appear<F: Fn() + Send + Sync + 'static>(
229 self,
230 action: F,
231 ) -> ModifiedView<Self, LifecycleModifier> {
232 self.modifier(LifecycleModifier {
233 on_appear: Some(Arc::new(action)),
234 on_disappear: None,
235 })
236 }
237
238 fn on_disappear<F: Fn() + Send + Sync + 'static>(
240 self,
241 action: F,
242 ) -> ModifiedView<Self, LifecycleModifier> {
243 self.modifier(LifecycleModifier {
244 on_appear: None,
245 on_disappear: Some(Arc::new(action)),
246 })
247 }
248
249 fn erase(self) -> AnyView
251 where
252 Self: 'static,
253 {
254 AnyView::new(self)
255 }
256}
257
258pub trait ErasedView: Send {
260 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect);
261 fn name(&self) -> &'static str;
262}
263
264impl<V: View + 'static> ErasedView for V {
265 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
266 self.render(renderer, rect);
267 }
268
269 fn name(&self) -> &'static str {
270 std::any::type_name::<V>()
271 }
272}
273
274pub struct AnyView {
276 inner: Box<dyn ErasedView>,
277}
278
279impl AnyView {
280 pub fn new<V: View + 'static>(view: V) -> Self {
281 Self {
282 inner: Box::new(view),
283 }
284 }
285}
286
287impl View for AnyView {
288 type Body = Never;
289 fn body(self) -> Self::Body {
290 unreachable!()
291 }
292
293 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
294 renderer.push_vnode(rect, self.inner.name());
295 self.inner.render_erased(renderer, rect);
296 renderer.pop_vnode();
297 }
298}
299
300#[derive(Debug, Clone, PartialEq)]
304pub struct BifrostBridgeModifier {
305 pub id: String,
306}
307
308impl ViewModifier for BifrostBridgeModifier {
309 fn modify<V: View>(self, content: V) -> impl View {
310 ModifiedView::new(content, self)
311 }
312
313 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
314 renderer.register_shared_element(&self.id, rect);
316 }
317}
318
319#[derive(Debug, Clone, Copy, PartialEq)]
322pub struct MjolnirSliceModifier {
323 pub angle: f32,
324 pub offset: f32,
325}
326
327impl ViewModifier for MjolnirSliceModifier {
328 fn modify<V: View>(self, content: V) -> impl View {
329 ModifiedView::new(content, self)
330 }
331
332 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
333 renderer.push_mjolnir_slice(self.angle, self.offset);
334 }
335
336 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
337 renderer.pop_mjolnir_slice();
338 }
339}
340
341#[derive(Debug, Clone, Copy, PartialEq)]
344pub struct MjolnirShatterModifier {
345 pub pieces: u32,
346 pub force: f32,
347}
348
349impl ViewModifier for MjolnirShatterModifier {
350 fn modify<V: View>(self, content: V) -> impl View {
351 ModifiedView::new(content, self)
352 }
353
354 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
355 let pieces = self.pieces.max(1);
357 for i in 0..pieces {
358 let progress = i as f32 / pieces as f32;
359 let next_progress = (i + 1) as f32 / pieces as f32;
360
361 let angle_start = progress * 360.0;
362 let angle_end = next_progress * 360.0;
363
364 renderer.push_mjolnir_slice(angle_start, 0.0);
366 renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
367
368 let mid_angle = (angle_start + angle_end) / 2.0;
370 let rad = mid_angle.to_radians();
371 let dx = rad.cos() * self.force;
372 let dy = rad.sin() * self.force;
373
374 let shard_rect = Rect {
375 x: rect.x + dx,
376 y: rect.y + dy,
377 ..rect
378 };
379
380 view.render(renderer, shard_rect);
381
382 renderer.pop_mjolnir_slice();
383 renderer.pop_mjolnir_slice();
384 }
385 }
386}
387
388#[derive(Debug, Clone, Copy, PartialEq)]
391pub struct BifrostModifier {
392 pub blur: f32,
393 pub saturation: f32,
394 pub opacity: f32,
395}
396
397impl ViewModifier for BifrostModifier {
398 fn modify<V: View>(self, content: V) -> impl View {
399 ModifiedView::new(content, self)
400 }
401
402 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
403 renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
404 }
405}
406
407#[derive(Debug, Clone, Copy, PartialEq)]
409pub struct BackgroundModifier {
410 pub color: [f32; 4],
411}
412
413impl ViewModifier for BackgroundModifier {
414 fn modify<V: View>(self, content: V) -> impl View {
415 ModifiedView::new(content, self)
416 }
417
418 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
419 renderer.fill_rect(rect, self.color);
420 }
421}
422
423#[derive(Debug, Clone, Copy, PartialEq)]
425pub struct PaddingModifier {
426 pub amount: f32,
427}
428
429impl ViewModifier for PaddingModifier {
430 fn modify<V: View>(self, content: V) -> impl View {
431 ModifiedView::new(content, self)
432 }
433
434 fn transform_rect(&self, rect: Rect) -> Rect {
435 Rect {
436 x: rect.x + self.amount,
437 y: rect.y + self.amount,
438 width: (rect.width - 2.0 * self.amount).max(0.0),
439 height: (rect.height - 2.0 * self.amount).max(0.0),
440 }
441 }
442}
443
444#[derive(Debug, Clone, PartialEq)]
447pub struct GungnirModifier {
448 pub color: String,
449 pub radius: f32,
450 pub intensity: f32,
451}
452
453impl ViewModifier for GungnirModifier {
454 fn modify<V: View>(self, content: V) -> impl View {
455 ModifiedView::new(content, self)
456 }
457
458 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
459 renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
461 }
462}
463
464#[derive(Debug, Clone, Copy, PartialEq)]
466pub struct GungnirPulseModifier {
467 pub color: [f32; 4],
468 pub radius: f32,
469 pub speed: f32,
470}
471
472impl ViewModifier for GungnirPulseModifier {
473 fn modify<V: View>(self, content: V) -> impl View {
474 ModifiedView::new(content, self)
475 }
476
477 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
478 let time = std::time::SystemTime::now()
479 .duration_since(std::time::UNIX_EPOCH)
480 .unwrap_or_default()
481 .as_secs_f32();
482
483 let intensity = (time * self.speed).sin() * 0.5 + 0.5;
486 let mut color = self.color;
487 color[3] *= intensity;
488
489 renderer.stroke_rect(rect, color, self.radius);
491 }
492}
493
494#[derive(Debug, Clone, PartialEq)]
496pub struct SleipnirModifier<T> {
497 pub target: T,
498 pub stiffness: f32,
499 pub damping: f32,
500}
501
502impl<T: Send + Sync + 'static + Clone> ViewModifier for SleipnirModifier<T> {
503 fn modify<V: View>(self, content: V) -> impl View {
504 ModifiedView::new(content, self)
505 }
506}
507
508#[derive(Clone)]
510pub struct LifecycleModifier {
511 pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
512 pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
513}
514
515impl ViewModifier for LifecycleModifier {
516 fn modify<V: View>(self, content: V) -> impl View {
517 ModifiedView::new(content, self)
518 }
519}
520
521#[derive(Debug, Clone, Copy, PartialEq)]
524pub struct OpacityModifier {
525 pub opacity: f32,
526}
527
528impl ViewModifier for OpacityModifier {
529 fn modify<V: View>(self, content: V) -> impl View {
530 ModifiedView::new(content, self)
531 }
532
533 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
534 renderer.push_opacity(self.opacity);
535 }
536
537 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
538 renderer.pop_opacity();
539 }
540}
541
542#[derive(Debug, Clone, Copy, PartialEq)]
545pub struct ForegroundColorModifier {
546 pub color: [f32; 4],
547}
548
549impl ViewModifier for ForegroundColorModifier {
550 fn modify<V: View>(self, content: V) -> impl View {
551 ModifiedView::new(content, self)
552 }
553}
554
555#[derive(Debug, Clone, Copy, PartialEq, Eq)]
558pub struct ClipModifier;
559
560impl ViewModifier for ClipModifier {
561 fn modify<V: View>(self, content: V) -> impl View {
562 ModifiedView::new(content, self)
563 }
564
565 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
566 renderer.push_clip_rect(rect);
567 }
568
569 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
570 renderer.pop_clip_rect();
571 }
572}
573
574#[derive(Debug, Clone, Copy, PartialEq)]
576pub struct BorderModifier {
577 pub color: [f32; 4],
578 pub width: f32,
579}
580
581impl ViewModifier for BorderModifier {
582 fn modify<V: View>(self, content: V) -> impl View {
583 ModifiedView::new(content, self)
584 }
585
586 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
587 renderer.stroke_rect(rect, self.color, self.width);
588 }
589}
590
591#[doc(hidden)]
593pub enum Never {}
594
595impl View for Never {
596 type Body = Never;
597 fn body(self) -> Never {
598 unreachable!()
599 }
600}
601
602pub struct ModifiedView<V, M> {
606 view: V,
607 modifier: M,
608}
609
610impl<V: View, M: ViewModifier> ModifiedView<V, M> {
611 #[doc(hidden)]
612 pub fn new(view: V, modifier: M) -> Self {
613 Self { view, modifier }
614 }
615}
616
617impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
618 type Body = ModifiedView<V::Body, M>;
619
620 fn body(self) -> Self::Body {
621 ModifiedView {
622 view: self.view.body(),
623 modifier: self.modifier.clone(),
624 }
625 }
626
627 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
628 self.modifier.render_view(&self.view, renderer, rect);
629 }
630}
631
632pub trait ViewModifier: Send + Clone {
633 fn modify<V: View>(self, content: V) -> impl View;
634
635 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
637
638 fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
640
641 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
644 self.render(renderer, rect);
645 let child_rect = self.transform_rect(rect);
646 view.render(renderer, child_rect);
647 self.post_render(renderer, rect);
648 }
649
650 fn transform_rect(&self, rect: Rect) -> Rect {
651 rect
652 }
653}
654
655pub trait Renderer: Send {
663 fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
665 fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
666 fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
668
669 fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
671 fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
672 fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
674 fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
676
677 fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
679 fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
681
682 fn draw_texture(&mut self, texture_id: u32, rect: Rect);
685 fn draw_image(&mut self, image_name: &str, rect: Rect);
687 fn load_image(&mut self, name: &str, data: &[u8]);
689
690 fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
693 fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
695
696 fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
699
700 fn draw_linear_gradient(
703 &mut self,
704 _rect: Rect,
705 _start_color: [f32; 4],
706 _end_color: [f32; 4],
707 _angle: f32,
708 ) {
709 }
710 fn draw_radial_gradient(
712 &mut self,
713 _rect: Rect,
714 _inner_color: [f32; 4],
715 _outer_color: [f32; 4],
716 ) {
717 }
718 fn draw_drop_shadow(
720 &mut self,
721 _rect: Rect,
722 _radius: f32,
723 _color: [f32; 4],
724 _blur: f32,
725 _spread: f32,
726 ) {
727 }
728 fn stroke_dashed_rounded_rect(
730 &mut self,
731 _rect: Rect,
732 _radius: f32,
733 _color: [f32; 4],
734 _width: f32,
735 _dash: f32,
736 _gap: f32,
737 ) {
738 }
739 fn draw_9slice(
741 &mut self,
742 _image_name: &str,
743 _rect: Rect,
744 _left: f32,
745 _top: f32,
746 _right: f32,
747 _bottom: f32,
748 ) {
749 }
750
751 fn push_clip_rect(&mut self, rect: Rect);
755 fn pop_clip_rect(&mut self);
757
758 fn push_opacity(&mut self, opacity: f32);
762 fn pop_opacity(&mut self);
764
765 fn set_theme(&mut self, _theme: ColorTheme) {}
767 fn set_rage(&mut self, _rage: f32) {}
768 fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
769
770 fn bifrost(&mut self, rect: Rect, blur: f32, saturation: f32, opacity: f32);
773 fn push_mjolnir_slice(&mut self, angle: f32, offset: f32);
775 fn pop_mjolnir_slice(&mut self);
777 fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
779 fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
780 fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
782
783 fn set_aria_role(&mut self, _role: &str) {}
785 fn set_aria_label(&mut self, _label: &str) {}
786
787 fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
789
790 fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
793 fn pop_vnode(&mut self) {}
795 fn register_handler(
797 &mut self,
798 _event_type: &str,
799 _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
800 ) {
801 }
802}
803
804use bytemuck::{Pod, Zeroable};
809
810#[repr(C)]
812#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
813pub struct ColorTheme {
814 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
816 pub glass_base: [f32; 4],
817 pub glass_edge: [f32; 4],
818 pub rune_glow: [f32; 4],
819 pub ember_core: [f32; 4],
820 pub background_deep: [f32; 4],
821 pub glass_blur_strength: f32,
822 pub shatter_edge_width: f32,
823 pub neon_bloom_radius: f32,
824 pub rune_opacity: f32, pub _pad: [f32; 3], pub _pad2: f32,
828}
829
830impl ColorTheme {
831 pub fn cyberpunk_viking() -> Self {
832 Self {
833 primary_neon: [0.0, 1.0, 0.95, 1.2],
834 shatter_neon: [1.0, 0.0, 0.75, 1.5],
835 glass_base: [0.04, 0.04, 0.06, 0.82],
836 glass_edge: [0.0, 0.45, 0.55, 0.6],
837 rune_glow: [0.75, 0.98, 1.0, 0.9],
838 ember_core: [0.95, 0.12, 0.12, 1.0],
839 background_deep: [0.01, 0.01, 0.03, 1.0],
840 glass_blur_strength: 0.6,
841 shatter_edge_width: 1.8,
842 neon_bloom_radius: 0.022,
843 rune_opacity: 0.55,
844 _pad: [0.0; 3],
845 _pad2: 0.0,
846 }
847 }
848
849 pub fn vibrant_glass() -> Self {
850 Self {
851 primary_neon: [0.0, 1.0, 0.95, 1.2],
852 shatter_neon: [1.0, 0.0, 0.75, 1.5],
853 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],
856 ember_core: [1.0, 0.4, 0.1, 1.0],
857 background_deep: [0.05, 0.05, 0.1, 1.0],
858 glass_blur_strength: 0.9,
859 shatter_edge_width: 1.8,
860 neon_bloom_radius: 0.022,
861 rune_opacity: 0.55,
862 _pad: [0.0; 3],
863 _pad2: 0.0,
864 }
865 }
866}
867
868impl Default for ColorTheme {
869 fn default() -> Self {
870 Self::vibrant_glass()
871 }
872}
873
874#[repr(C)]
876#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
877pub struct SceneUniforms {
878 pub view: glam::Mat4,
879 pub proj: glam::Mat4,
880 pub time: f32,
881 pub delta_time: f32,
882 pub resolution: [f32; 2],
883 pub mouse: [f32; 2],
884 pub mouse_velocity: [f32; 2],
885 pub shatter_origin: [f32; 2],
886 pub shatter_time: f32,
887 pub shatter_force: f32,
888 pub berzerker_rage: f32,
889 pub scroll_offset: f32,
890 pub _pad: [f32; 2],
892}
893
894impl SceneUniforms {
895 pub fn new(width: f32, height: f32) -> Self {
896 Self {
897 view: glam::Mat4::IDENTITY,
898 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
899 time: 0.0,
900 delta_time: 0.016,
901 resolution: [width, height],
902 mouse: [0.5, 0.5],
903 mouse_velocity: [0.0, 0.0],
904 shatter_origin: [0.5, 0.5],
905 shatter_time: -100.0,
906 shatter_force: 0.0,
907 berzerker_rage: 0.0,
908 scroll_offset: 0.0,
909 _pad: [0.0; 2],
910 }
911 }
912}
913
914#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
916pub struct Mesh {
917 pub vertices: Vec<[f32; 3]>,
918 pub normals: Vec<[f32; 3]>,
919 pub indices: Vec<u32>,
920}
921
922impl Mesh {
923 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
924 let mut cursor = std::io::Cursor::new(data);
925 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
926 Ok((Vec::new(), Default::default()))
927 })?;
928
929 let mut meshes = Vec::new();
930 for m in models {
931 let mesh = m.mesh;
932 let vertices: Vec<[f32; 3]> = mesh
933 .positions
934 .chunks(3)
935 .map(|c| [c[0], c[1], c[2]])
936 .collect();
937 let normals = if mesh.normals.is_empty() {
938 vec![[0.0, 0.0, 1.0]; vertices.len()]
939 } else {
940 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
941 };
942 meshes.push(Mesh {
943 vertices,
944 normals,
945 indices: mesh.indices,
946 });
947 }
948 Ok(meshes)
949 }
950
951 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
952 let mut cursor = std::io::Cursor::new(data);
953 let stl = stl_io::read_stl(&mut cursor)?;
954
955 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
956 let mut indices = Vec::new();
957 for face in stl.faces {
958 indices.push(face.vertices[0] as u32);
959 indices.push(face.vertices[1] as u32);
960 indices.push(face.vertices[2] as u32);
961 }
962
963 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
964
965 Ok(Mesh {
966 vertices,
967 normals,
968 indices,
969 })
970 }
971}
972
973pub trait FrameRenderer<E = ()>: Renderer {
976 fn begin_frame(&mut self) -> E;
977 fn end_frame(&mut self, encoder: E);
978}
979
980use std::sync::Arc;
981
982#[derive(Clone)]
984pub struct State<T: Clone + Send + Sync + 'static> {
985 value: Arc<std::sync::RwLock<T>>,
986 subscribers: Arc<std::sync::RwLock<Vec<Box<dyn FnMut(&T) + Send + Sync>>>>,
987}
988
989impl<T: Clone + Send + Sync + 'static> State<T> {
990 pub fn new(value: T) -> Self {
992 Self {
993 value: Arc::new(std::sync::RwLock::new(value)),
994 subscribers: Arc::new(std::sync::RwLock::new(Vec::new())),
995 }
996 }
997
998 pub fn get(&self) -> T {
1000 self.value.read().unwrap().clone()
1001 }
1002
1003 pub fn set(&self, value: T) {
1005 *self.value.write().unwrap() = value;
1006 let mut subscribers = self.subscribers.write().unwrap();
1008 for subscriber in subscribers.iter_mut() {
1009 subscriber(&self.get());
1010 }
1011 }
1012
1013 pub fn subscribe<F: FnMut(&T) + Send + Sync + 'static>(&self, callback: F) {
1015 self.subscribers.write().unwrap().push(Box::new(callback));
1016 }
1017}
1018
1019#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
1023pub struct ComponentErrorState {
1024 pub has_error: bool,
1025 pub error_message: Option<String>,
1026 pub error_location: Option<String>,
1027}
1028
1029impl ComponentErrorState {
1030 pub fn clear() -> Self {
1032 Self::default()
1033 }
1034
1035 pub fn error(message: impl Into<String>, location: impl Into<String>) -> Self {
1037 Self {
1038 has_error: true,
1039 error_message: Some(message.into()),
1040 error_location: Some(location.into()),
1041 }
1042 }
1043}
1044
1045#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
1047pub struct KnowledgeFragment {
1048 pub id: String,
1050 pub summary: String,
1052 pub source: String,
1054 pub created_at: u64,
1056 pub accessed_count: u32,
1058 pub content: Option<String>,
1060}
1061
1062#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1065pub struct KnowledgeState {
1066 #[serde(skip)]
1068 pub component_states: std::collections::HashMap<u64, Arc<dyn std::any::Any + Send + Sync>>,
1069
1070 pub fragments: HashMap<String, KnowledgeFragment>,
1072
1073 pub last_query_results: Vec<String>,
1075}
1076
1077use crate::runtime::NodeStateSnapshot;
1078use std::sync::OnceLock;
1079
1080pub static SYSTEM_STATE: OnceLock<Arc<std::sync::RwLock<KnowledgeState>>> = OnceLock::new();
1082
1083pub fn get_system_state() -> Arc<std::sync::RwLock<KnowledgeState>> {
1085 SYSTEM_STATE
1086 .get_or_init(|| Arc::new(std::sync::RwLock::new(KnowledgeState::default())))
1087 .clone()
1088}
1089
1090impl KnowledgeState {
1091 pub fn new() -> Self {
1093 Self::default()
1094 }
1095
1096 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
1098 self.component_states
1099 .insert(id, Arc::new(std::sync::RwLock::new(state)));
1100 }
1101
1102 pub fn get_component_state<T: 'static + Send + Sync>(
1104 &self,
1105 id: u64,
1106 ) -> Option<Arc<std::sync::RwLock<T>>> {
1107 let lock = self.component_states.get(&id)?;
1108 lock.clone().downcast::<std::sync::RwLock<T>>().ok()
1109 }
1110
1111 pub fn remember(&mut self, fragment: KnowledgeFragment) {
1113 self.fragments.insert(fragment.id.clone(), fragment);
1114 }
1115
1116 pub fn process_query(&mut self, query: &str) {
1118 let query_lower = query.to_lowercase();
1119 let mut results: Vec<(f32, String)> = self
1120 .fragments
1121 .iter()
1122 .map(|(id, frag)| {
1123 let mut score = 0.0;
1124 if frag.summary.to_lowercase().contains(&query_lower) {
1125 score += 1.0;
1126 }
1127 if frag.source.to_lowercase().contains(&query_lower) {
1128 score += 0.5;
1129 }
1130 (score, id.clone())
1131 })
1132 .filter(|(score, _)| *score > 0.0)
1133 .collect();
1134
1135 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
1137
1138 self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
1139 }
1140
1141 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
1143 let mut snapshots = Vec::new();
1144
1145 for (_id, frag) in &self.fragments {
1147 if let Ok(val) = serde_json::to_value(frag) {
1148 snapshots.push(NodeStateSnapshot { id: 0, state: val });
1149 }
1150 }
1151
1152 snapshots
1153 }
1154}
1155
1156#[derive(Clone)]
1158pub struct Binding<T: Clone + Send + Sync + 'static> {
1159 state: Arc<std::sync::RwLock<T>>,
1160}
1161
1162impl<T: Clone + Send + Sync + 'static> Binding<T> {
1163 pub fn from_state(state: &State<T>) -> Self {
1165 Self {
1166 state: state.value.clone(),
1167 }
1168 }
1169
1170 pub fn get(&self) -> T {
1172 self.state.read().unwrap().clone()
1173 }
1174
1175 pub fn set(&self, value: T) {
1177 *self.state.write().unwrap() = value;
1178 }
1179}
1180
1181use std::any::TypeId;
1182use std::sync::Mutex;
1183
1184pub(crate) static ENVIRONMENT: OnceLock<
1186 Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
1187> = OnceLock::new();
1188
1189pub trait EnvKey: 'static + Send + Sync {
1193 type Value: Clone + Send + Sync + 'static;
1195
1196 fn default_value() -> Self::Value;
1198}
1199
1200pub struct YggdrasilKey;
1202
1203impl EnvKey for YggdrasilKey {
1204 type Value = YggdrasilTokens;
1205 fn default_value() -> Self::Value {
1206 default_tokens()
1207 }
1208}
1209
1210pub struct AssetKey;
1212
1213impl EnvKey for AssetKey {
1214 type Value = Arc<dyn AssetManager>;
1215 fn default_value() -> Self::Value {
1216 Arc::new(DefaultAssetManager::new())
1217 }
1218}
1219
1220#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1222pub enum Appearance {
1223 Light,
1224 Dark,
1225}
1226
1227#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1229pub enum Orientation {
1230 Horizontal,
1231 Vertical,
1232}
1233
1234#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
1236pub struct Color {
1237 pub r: f32,
1238 pub g: f32,
1239 pub b: f32,
1240 pub a: f32,
1241}
1242
1243impl Color {
1244 pub const BLACK: Color = Color {
1245 r: 0.0,
1246 g: 0.0,
1247 b: 0.0,
1248 a: 1.0,
1249 };
1250 pub const WHITE: Color = Color {
1251 r: 1.0,
1252 g: 1.0,
1253 b: 1.0,
1254 a: 1.0,
1255 };
1256 pub const TRANSPARENT: Color = Color {
1257 r: 0.0,
1258 g: 0.0,
1259 b: 0.0,
1260 a: 0.0,
1261 };
1262 pub const RED: Color = Color {
1263 r: 1.0,
1264 g: 0.0,
1265 b: 0.0,
1266 a: 1.0,
1267 };
1268 pub const GREEN: Color = Color {
1269 r: 0.0,
1270 g: 1.0,
1271 b: 0.0,
1272 a: 1.0,
1273 };
1274 pub const BLUE: Color = Color {
1275 r: 0.0,
1276 g: 0.0,
1277 b: 1.0,
1278 a: 1.0,
1279 };
1280 pub const CYAN: Color = Color {
1281 r: 0.0,
1282 g: 1.0,
1283 b: 1.0,
1284 a: 1.0,
1285 };
1286 pub const YELLOW: Color = Color {
1287 r: 1.0,
1288 g: 1.0,
1289 b: 0.0,
1290 a: 1.0,
1291 };
1292 pub const MAGENTA: Color = Color {
1293 r: 1.0,
1294 g: 0.0,
1295 b: 1.0,
1296 a: 1.0,
1297 };
1298 pub const GRAY: Color = Color {
1299 r: 0.5,
1300 g: 0.5,
1301 b: 0.5,
1302 a: 1.0,
1303 };
1304
1305 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
1307 Self { r, g, b, a }
1308 }
1309
1310 pub fn as_array(&self) -> [f32; 4] {
1312 [self.r, self.g, self.b, self.a]
1313 }
1314}
1315
1316impl View for Color {
1317 type Body = Never;
1318 fn body(self) -> Self::Body {
1319 unreachable!()
1320 }
1321
1322 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1323 renderer.fill_rect(rect, self.as_array());
1324 }
1325}
1326
1327pub struct AppearanceKey;
1329
1330impl EnvKey for AppearanceKey {
1331 type Value = Appearance;
1332 fn default_value() -> Self::Value {
1333 Appearance::Dark }
1335}
1336
1337pub struct StyleResolver;
1339
1340impl StyleResolver {
1341 pub fn color(key: &str) -> String {
1343 let tokens = Environment::<YggdrasilKey>::new().get();
1344 let appearance = Environment::<AppearanceKey>::new().get();
1345 let is_dark = appearance == Appearance::Dark;
1346
1347 tokens
1348 .get_color(key, is_dark)
1349 .unwrap_or_else(|| "#FF00FF".to_string()) }
1351
1352 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
1354 let tokens = Environment::<YggdrasilKey>::new().get();
1355 let appearance = Environment::<AppearanceKey>::new().get();
1356 let is_dark = appearance == Appearance::Dark;
1357
1358 tokens.get(category, key, is_dark)
1359 }
1360}
1361
1362pub fn default_tokens() -> YggdrasilTokens {
1364 let mut tokens = YggdrasilTokens::new();
1365
1366 tokens.color.insert(
1368 "background".to_string(),
1369 TokenValue::Single {
1370 value: "#000000".to_string(), },
1372 );
1373
1374 tokens.color.insert(
1375 "primary".to_string(),
1376 TokenValue::Single {
1377 value: "#00FFFF".to_string(), },
1379 );
1380
1381 tokens.color.insert(
1382 "secondary".to_string(),
1383 TokenValue::Single {
1384 value: "#FF00FF".to_string(), },
1386 );
1387
1388 tokens.color.insert(
1389 "surface".to_string(),
1390 TokenValue::Adaptive {
1391 light: "#FFFFFF".to_string(),
1392 dark: "#121212".to_string(),
1393 },
1394 );
1395
1396 tokens.color.insert(
1397 "text".to_string(),
1398 TokenValue::Adaptive {
1399 light: "#000000".to_string(),
1400 dark: "#FFFFFF".to_string(),
1401 },
1402 );
1403
1404 tokens.bifrost.insert(
1406 "blur".to_string(),
1407 TokenValue::Single {
1408 value: "25.0".to_string(),
1409 },
1410 );
1411 tokens.bifrost.insert(
1412 "saturation".to_string(),
1413 TokenValue::Single {
1414 value: "1.2".to_string(),
1415 },
1416 );
1417 tokens.bifrost.insert(
1418 "opacity".to_string(),
1419 TokenValue::Single {
1420 value: "0.65".to_string(),
1421 },
1422 );
1423
1424 tokens.gungnir.insert(
1426 "intensity".to_string(),
1427 TokenValue::Single {
1428 value: "1.0".to_string(),
1429 },
1430 );
1431 tokens.gungnir.insert(
1432 "radius".to_string(),
1433 TokenValue::Single {
1434 value: "15.0".to_string(),
1435 },
1436 );
1437
1438 tokens.mjolnir.insert(
1440 "clip_angle".to_string(),
1441 TokenValue::Single {
1442 value: "12.0".to_string(),
1443 },
1444 );
1445 tokens.mjolnir.insert(
1446 "border_width".to_string(),
1447 TokenValue::Single {
1448 value: "2.0".to_string(),
1449 },
1450 );
1451
1452 tokens.anim.insert(
1454 "stiffness".to_string(),
1455 TokenValue::Single {
1456 value: "170.0".to_string(),
1457 },
1458 );
1459 tokens.anim.insert(
1460 "damping".to_string(),
1461 TokenValue::Single {
1462 value: "26.0".to_string(),
1463 },
1464 );
1465 tokens.anim.insert(
1466 "mass".to_string(),
1467 TokenValue::Single {
1468 value: "1.0".to_string(),
1469 },
1470 );
1471
1472 tokens.accessibility.insert(
1474 "reduce_motion".to_string(),
1475 TokenValue::Single {
1476 value: "false".to_string(),
1477 },
1478 );
1479
1480 tokens
1481}
1482
1483pub struct Environment<K: EnvKey> {
1485 _marker: std::marker::PhantomData<K>,
1486}
1487
1488impl<K: EnvKey> Environment<K> {
1489 pub fn new() -> Self {
1491 Self {
1492 _marker: std::marker::PhantomData,
1493 }
1494 }
1495
1496 pub fn get(&self) -> K::Value {
1498 if let Some(env_store) = ENVIRONMENT.get() {
1499 let env_lock = env_store.lock().unwrap();
1500 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
1501 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
1502 return typed_val.clone();
1503 }
1504 }
1505 }
1506 K::default_value()
1507 }
1508}
1509
1510pub mod env {
1512
1513 pub fn insert<K: super::EnvKey>(value: K::Value) {
1515 if let Some(store) = super::ENVIRONMENT.get() {
1516 let mut env_map = store.lock().unwrap();
1517 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
1518 }
1519 }
1520
1521 pub fn remove<K: super::EnvKey>() {
1523 if let Some(store) = super::ENVIRONMENT.get() {
1524 let mut env_map = store.lock().unwrap();
1525 env_map.remove(&std::any::TypeId::of::<K>());
1526 }
1527 }
1528}
1529
1530#[derive(Debug, Clone, Copy, PartialEq)]
1534pub struct Size {
1535 pub width: f32,
1536 pub height: f32,
1537}
1538
1539#[derive(Debug, Clone, Copy, PartialEq)]
1541pub struct EdgeInsets {
1542 pub top: f32,
1543 pub leading: f32,
1544 pub bottom: f32,
1545 pub trailing: f32,
1546}
1547
1548impl EdgeInsets {
1549 pub fn all(value: f32) -> Self {
1551 Self {
1552 top: value,
1553 leading: value,
1554 bottom: value,
1555 trailing: value,
1556 }
1557 }
1558
1559 pub fn vertical(value: f32) -> Self {
1561 Self {
1562 top: value,
1563 leading: 0.0,
1564 bottom: value,
1565 trailing: 0.0,
1566 }
1567 }
1568
1569 pub fn horizontal(value: f32) -> Self {
1571 Self {
1572 top: 0.0,
1573 leading: value,
1574 bottom: 0.0,
1575 trailing: value,
1576 }
1577 }
1578}
1579
1580#[derive(Debug, Clone, Copy, PartialEq)]
1582pub struct FrameModifier {
1583 pub width: Option<f32>,
1584 pub height: Option<f32>,
1585}
1586
1587impl FrameModifier {
1588 pub fn new() -> Self {
1589 Self {
1590 width: None,
1591 height: None,
1592 }
1593 }
1594
1595 pub fn width(mut self, width: f32) -> Self {
1596 self.width = Some(width);
1597 self
1598 }
1599
1600 pub fn height(mut self, height: f32) -> Self {
1601 self.height = Some(height);
1602 self
1603 }
1604
1605 pub fn size(mut self, width: f32, height: f32) -> Self {
1606 self.width = Some(width);
1607 self.height = Some(height);
1608 self
1609 }
1610}
1611
1612impl ViewModifier for FrameModifier {
1613 fn modify<V: View>(self, content: V) -> impl View {
1614 ModifiedView::new(content, self)
1615 }
1616}
1617
1618#[derive(Debug, Clone, Copy, PartialEq)]
1620pub struct OffsetModifier {
1621 pub x: f32,
1622 pub y: f32,
1623}
1624
1625impl OffsetModifier {
1626 pub fn new(x: f32, y: f32) -> Self {
1627 Self { x, y }
1628 }
1629}
1630
1631impl ViewModifier for OffsetModifier {
1632 fn modify<V: View>(self, content: V) -> impl View {
1633 ModifiedView::new(content, self)
1634 }
1635}
1636
1637#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1639pub struct ZIndexModifier {
1640 pub z_index: i32,
1641}
1642
1643impl ZIndexModifier {
1644 pub fn new(z_index: i32) -> Self {
1645 Self { z_index }
1646 }
1647}
1648
1649impl ViewModifier for ZIndexModifier {
1650 fn modify<V: View>(self, content: V) -> impl View {
1651 ModifiedView::new(content, self)
1652 }
1653}
1654
1655#[derive(Debug, Clone, Copy, PartialEq)]
1657pub struct LayoutConstraints {
1658 pub min_width: Option<f32>,
1659 pub max_width: Option<f32>,
1660 pub min_height: Option<f32>,
1661 pub max_height: Option<f32>,
1662}
1663
1664impl Default for LayoutConstraints {
1665 fn default() -> Self {
1666 Self {
1667 min_width: None,
1668 max_width: None,
1669 min_height: None,
1670 max_height: None,
1671 }
1672 }
1673}
1674
1675#[derive(Debug, Clone, Copy, PartialEq)]
1677pub struct LayoutModifier {
1678 pub constraints: LayoutConstraints,
1679}
1680
1681impl LayoutModifier {
1682 pub fn new(constraints: LayoutConstraints) -> Self {
1683 Self { constraints }
1684 }
1685}
1686
1687impl ViewModifier for LayoutModifier {
1688 fn modify<V: View>(self, content: V) -> impl View {
1689 ModifiedView::new(content, self)
1690 }
1691}
1692
1693#[derive(Debug, Clone, Copy, PartialEq)]
1695pub struct FlexModifier {
1696 pub flex: f32,
1697}
1698
1699impl FlexModifier {
1700 pub fn new(flex: f32) -> Self {
1701 Self { flex }
1702 }
1703}
1704
1705impl ViewModifier for FlexModifier {
1706 fn modify<V: View>(self, content: V) -> impl View {
1707 ModifiedView::new(content, self)
1708 }
1709}
1710
1711pub mod layout {
1713 use super::*;
1714
1715 pub struct LayoutCache;
1717
1718 impl LayoutCache {
1719 pub fn new() -> Self {
1720 Self
1721 }
1722
1723 pub fn clear(&mut self) {
1724 }
1726 }
1727
1728 #[derive(Debug, Clone, Copy, PartialEq)]
1730 pub struct SizeProposal {
1731 pub width: Option<f32>,
1732 pub height: Option<f32>,
1733 }
1734
1735 impl SizeProposal {
1736 pub fn unspecified() -> Self {
1737 Self {
1738 width: None,
1739 height: None,
1740 }
1741 }
1742
1743 pub fn width(width: f32) -> Self {
1744 Self {
1745 width: Some(width),
1746 height: None,
1747 }
1748 }
1749
1750 pub fn height(height: f32) -> Self {
1751 Self {
1752 width: None,
1753 height: Some(height),
1754 }
1755 }
1756
1757 pub fn tight(width: f32, height: f32) -> Self {
1758 Self {
1759 width: Some(width),
1760 height: Some(height),
1761 }
1762 }
1763 }
1764
1765 pub trait LayoutView: Send {
1767 fn size_that_fits(
1769 &self,
1770 proposal: SizeProposal,
1771 subviews: &[&dyn LayoutView],
1772 cache: &mut LayoutCache,
1773 ) -> Size;
1774
1775 fn place_subviews(
1777 &self,
1778 bounds: Rect,
1779 subviews: &mut [&mut dyn LayoutView],
1780 cache: &mut LayoutCache,
1781 );
1782 }
1783
1784 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
1786 pub struct Rect {
1787 pub x: f32,
1788 pub y: f32,
1789 pub width: f32,
1790 pub height: f32,
1791 }
1792
1793 impl Rect {
1794 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
1795 Self {
1796 x,
1797 y,
1798 width,
1799 height,
1800 }
1801 }
1802
1803 pub fn zero() -> Self {
1804 Self {
1805 x: 0.0,
1806 y: 0.0,
1807 width: 0.0,
1808 height: 0.0,
1809 }
1810 }
1811
1812 pub fn size(&self) -> Size {
1813 Size {
1814 width: self.width,
1815 height: self.height,
1816 }
1817 }
1818
1819 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
1821 if n == 0 {
1822 return vec![];
1823 }
1824 let item_width = self.width / n as f32;
1825 (0..n)
1826 .map(|i| Rect {
1827 x: self.x + i as f32 * item_width,
1828 y: self.y,
1829 width: item_width,
1830 height: self.height,
1831 })
1832 .collect()
1833 }
1834
1835 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
1837 if n == 0 {
1838 return vec![];
1839 }
1840 let item_height = self.height / n as f32;
1841 (0..n)
1842 .map(|i| Rect {
1843 x: self.x,
1844 y: self.y + i as f32 * item_height,
1845 width: self.width,
1846 height: item_height,
1847 })
1848 .collect()
1849 }
1850 }
1851}
1852
1853pub use layout::{LayoutCache, LayoutView, Rect, SizeProposal};
1855pub mod runtime;
1858pub mod scene_graph;
1859
1860pub use scene_graph::{NodeId, bifrost_registry};
1861
1862#[derive(Debug, Clone, PartialEq)]
1864pub enum AssetState<T> {
1865 Loading,
1866 Ready(T),
1867 Error(String),
1868}
1869
1870pub trait AssetManager: Send + Sync {
1872 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
1874
1875 fn preload_image(&self, url: &str);
1877}
1878
1879#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1881pub enum Event {
1882 PointerDown { x: f32, y: f32 },
1883 PointerUp { x: f32, y: f32 },
1884 PointerMove { x: f32, y: f32 },
1885 KeyDown { key: String },
1886 KeyUp { key: String },
1887}
1888
1889#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1891pub enum EventResponse {
1892 Handled,
1893 Ignored,
1894}
1895
1896pub struct DefaultAssetManager {
1898 cache: Arc<std::sync::RwLock<HashMap<String, AssetState<Arc<Vec<u8>>>>>>,
1899}
1900
1901impl DefaultAssetManager {
1902 pub fn new() -> Self {
1903 Self {
1904 cache: Arc::new(std::sync::RwLock::new(HashMap::new())),
1905 }
1906 }
1907}
1908
1909impl AssetManager for DefaultAssetManager {
1910 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
1911 let mut cache = self.cache.write().unwrap();
1912 if let Some(state) = cache.get(url) {
1913 return state.clone();
1914 }
1915
1916 cache.insert(url.to_string(), AssetState::Loading);
1919 AssetState::Loading
1920 }
1921
1922 fn preload_image(&self, _url: &str) {
1923 }
1925}
1926
1927#[cfg(test)]
1928mod phase1_test;