1use serde::{Deserialize, Serialize};
35use std::collections::HashMap;
36use std::str::FromStr;
37
38pub mod error_types;
39
40pub mod security;
41
42#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
44pub struct ComponentErrorState {
45 pub has_error: bool,
46 pub error_message: Option<String>,
47 pub error_location: Option<String>,
48}
49impl ComponentErrorState {
50 pub fn clear() -> Self {
51 Self::default()
52 }
53
54 pub fn error(message: impl Into<String>, location: impl Into<String>) -> Self {
55 Self {
56 has_error: true,
57 error_message: Some(message.into()),
58 error_location: Some(location.into()),
59 }
60 }
61}
62
63#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
65pub struct KnowledgeState {
66 pub thoughts: Vec<String>,
67 pub actions: Vec<String>,
68 pub context: HashMap<String, String>,
69 pub last_query_results: Vec<KnowledgeId>,
70 #[serde(alias = "items")]
71 pub fragments: std::collections::HashMap<KnowledgeId, KnowledgeFragment>,
72 pub nodes: Vec<TemporalNode>,
74 pub edges: Vec<TemporalEdge>,
76 pub realm: Realm,
78 pub last_pointer_pos: [f32; 2],
80 pub pointer_velocity: [f32; 2],
82 pub odin_focus: Option<String>,
84 pub agent_attention: HashMap<String, f32>,
86 #[serde(skip)]
88 pub component_states: HashMap<u64, Arc<std::sync::RwLock<dyn std::any::Any + Send + Sync>>>,
89}
90
91impl KnowledgeState {
92 pub fn apply_decay(&mut self, decay_factor: f32) {
96 for node in &mut self.nodes {
97 node.weight *= decay_factor;
98 }
99
100 for state in self.component_states.values() {
102 if let Ok(mut lock) = state.write()
103 && let Some(v) = lock.downcast_mut::<f32>() {
104 *v = (*v * decay_factor).max(1.0);
105 }
106 }
107 }
108
109 pub fn reinforce(&mut self, node_ids: &[String], boost: f32) {
111 for node in &mut self.nodes {
112 if node_ids.contains(&node.id) {
113 node.weight += boost;
114 }
115 }
116 }
117
118 pub fn update_pointer(&mut self, new_pos: [f32; 2]) {
120 self.pointer_velocity = [
121 new_pos[0] - self.last_pointer_pos[0],
122 new_pos[1] - self.last_pointer_pos[1],
123 ];
124 self.last_pointer_pos = new_pos;
125 }
126}
127pub type KnowledgeId = String;
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct KnowledgeFragment {
134 pub id: String,
136 pub summary: String,
138 pub source: String,
140 pub created_at: u64,
142 pub accessed_count: u32,
144 pub content: Option<String>,
146}
147
148impl KnowledgeFragment {
149 pub fn new(id: String, summary: String, source: String) -> Self {
150 Self {
151 id,
152 summary,
153 source,
154 created_at: 0,
155 accessed_count: 0,
156 content: None,
157 }
158 }
159}
160
161#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
163pub enum MemoryLayer {
164 Episodic,
166 Semantic,
168 Procedural,
170}
171
172#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
176#[derive(Default)]
177pub enum Realm {
178 Midgard,
179 #[default]
180 Asgard,
181}
182
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct TemporalNode {
187 pub id: String,
189 pub fragment_id: KnowledgeId,
191 pub timestamp: u64,
193 pub layer: MemoryLayer,
195 pub weight: f32,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
201pub struct TemporalEdge {
202 pub source: String,
204 pub target: String,
206 pub relation: String,
208 pub weight: f32,
210}
211
212#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
213pub struct AssetKey(pub String);
214
215impl EnvKey for AssetKey {
216 type Value = Arc<dyn AssetManager>;
217 fn default_value() -> Self::Value {
218 Arc::new(DefaultAssetManager::new())
219 }
220}
221
222#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
224pub enum AssetState<T> {
225 Loading,
226 Ready(T),
227 Error(String),
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
232#[serde(untagged)]
233pub enum TokenValue {
234 Single { value: String },
236 Adaptive { light: String, dark: String },
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct YggdrasilTokens {
243 pub color: HashMap<String, TokenValue>,
244 pub font: HashMap<String, TokenValue>,
245 pub spacing: HashMap<String, TokenValue>,
246 pub radius: HashMap<String, TokenValue>,
247 pub shadow: HashMap<String, TokenValue>,
248 pub border: HashMap<String, TokenValue>,
249 pub anim: HashMap<String, TokenValue>,
250 pub bifrost: HashMap<String, TokenValue>,
251 pub gungnir: HashMap<String, TokenValue>,
252 pub mjolnir: HashMap<String, TokenValue>,
253 pub accessibility: HashMap<String, TokenValue>,
254}
255
256impl Default for YggdrasilTokens {
257 fn default() -> Self {
258 Self::new()
259 }
260}
261
262
263
264impl YggdrasilTokens {
265 pub fn new() -> Self {
266 Self {
267 color: HashMap::new(),
268 font: HashMap::new(),
269 spacing: HashMap::new(),
270 radius: HashMap::new(),
271 shadow: HashMap::new(),
272 border: HashMap::new(),
273 anim: HashMap::new(),
274 bifrost: HashMap::new(),
275 gungnir: HashMap::new(),
276 mjolnir: HashMap::new(),
277 accessibility: HashMap::new(),
278 }
279 }
280
281 pub fn get_color(&self, key: &str, is_dark: bool) -> Option<String> {
283 self.color.get(key).map(|token| match token {
284 TokenValue::Single { value } => value.clone(),
285 TokenValue::Adaptive { light, dark } => {
286 if is_dark {
287 dark.clone()
288 } else {
289 light.clone()
290 }
291 }
292 })
293 }
294
295 pub fn get<T: FromStr>(&self, category: &str, key: &str, is_dark: bool) -> Option<T> {
297 let map = match category {
298 "color" => &self.color,
299 "font" => &self.font,
300 "spacing" => &self.spacing,
301 "radius" => &self.radius,
302 "shadow" => &self.shadow,
303 "border" => &self.border,
304 "anim" => &self.anim,
305 "bifrost" => &self.bifrost,
306 "gungnir" => &self.gungnir,
307 "mjolnir" => &self.mjolnir,
308 "accessibility" => &self.accessibility,
309 _ => return None,
310 };
311
312 map.get(key).and_then(|token| match token {
313 TokenValue::Single { value } => value.parse().ok(),
314 TokenValue::Adaptive { light, dark } => {
315 let value = if is_dark { dark } else { light };
316 value.parse().ok()
317 }
318 })
319 }
320}
321
322pub trait View: Sized + Send {
323 type Body: View;
326
327 fn body(self) -> Self::Body;
328
329 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
332
333 fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
336 Size::ZERO
337 }
338
339 fn layout(&self) -> Option<&dyn layout::LayoutView> {
341 None
342 }
343
344 fn flex_weight(&self) -> f32 {
346 0.0
347 }
348
349 fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
351 ModifiedView::new(self, m)
352 }
353
354 fn bifrost(
356 self,
357 blur: f32,
358 saturation: f32,
359 opacity: f32,
360 ) -> ModifiedView<Self, BifrostModifier> {
361 self.modifier(BifrostModifier {
362 blur,
363 saturation,
364 opacity,
365 })
366 }
367
368 fn gungnir(
370 self,
371 color: impl Into<String>,
372 radius: f32,
373 intensity: f32,
374 ) -> ModifiedView<Self, GungnirModifier> {
375 self.modifier(GungnirModifier {
376 color: color.into(),
377 radius,
378 intensity,
379 })
380 }
381
382 fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
384 self.modifier(MjolnirSliceModifier { angle, offset })
385 }
386
387 fn mjolnir_shatter(
389 self,
390 pieces: u32,
391 force: f32,
392 ) -> ModifiedView<Self, MjolnirShatterModifier> {
393 self.modifier(MjolnirShatterModifier { pieces, force })
394 }
395
396 fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
398 self.modifier(BifrostBridgeModifier { id: id.into() })
399 }
400
401 fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
403 self.modifier(BackgroundModifier { color })
404 }
405
406 fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
408 self.modifier(PaddingModifier { amount })
409 }
410
411 fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
413 self.modifier(OpacityModifier {
414 opacity: opacity.clamp(0.0, 1.0),
415 })
416 }
417
418 fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
420 self.modifier(ForegroundColorModifier { color })
421 }
422
423 fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
425 self.modifier(FrameModifier { width, height })
426 }
427
428 fn flex(self, weight: f32) -> ModifiedView<Self, FlexModifier> {
430 self.modifier(FlexModifier { weight })
431 }
432
433 fn safe_area_padding(self) -> ModifiedView<Self, SafeAreaModifier> {
435 self.modifier(SafeAreaModifier { ignores: false })
436 }
437
438 fn ignores_safe_area(self) -> ModifiedView<Self, SafeAreaModifier> {
440 self.modifier(SafeAreaModifier { ignores: true })
441 }
442
443 fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
445 self.modifier(ClipModifier)
446 }
447
448 fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
450 self.modifier(BorderModifier { color, width })
451 }
452
453 fn elevation(self, level: f32) -> ModifiedView<Self, ElevationModifier> {
455 self.modifier(ElevationModifier { level })
456 }
457
458 fn magnetic(self, radius: f32, intensity: f32) -> ModifiedView<Self, MagneticModifier> {
460 self.modifier(MagneticModifier { radius, intensity })
461 }
462
463 fn mani_glow(self, color: [f32; 4], radius: f32) -> ModifiedView<Self, ManiGlowModifier> {
465 self.modifier(ManiGlowModifier { color, radius })
466 }
467
468 fn memory_layer(self, layer: MemoryLayer) -> ModifiedView<Self, BifrostLayerModifier> {
470 self.modifier(BifrostLayerModifier { layer })
471 }
472
473 fn fafnir_evolve(self, id: u64) -> ModifiedView<Self, FafnirModifier> {
475 self.modifier(FafnirModifier { id })
476 }
477
478 fn mimir_intent(self) -> ModifiedView<Self, MimirIntentModifier> {
480 self.modifier(MimirIntentModifier)
481 }
482
483 fn kvasir_vibes(self, complexity: f32) -> ModifiedView<Self, KvasirVibeModifier> {
485 self.modifier(KvasirVibeModifier { complexity })
486 }
487
488 fn odins_eye(self) -> ModifiedView<Self, OdinsEyeModifier> {
490 self.modifier(OdinsEyeModifier)
491 }
492
493 fn on_appear<F: Fn() + Send + Sync + 'static>(
495 self,
496 action: F,
497 ) -> ModifiedView<Self, LifecycleModifier> {
498 self.modifier(LifecycleModifier {
499 on_appear: Some(Arc::new(action)),
500 on_disappear: None,
501 })
502 }
503
504 fn on_disappear<F: Fn() + Send + Sync + 'static>(
506 self,
507 action: F,
508 ) -> ModifiedView<Self, LifecycleModifier> {
509 self.modifier(LifecycleModifier {
510 on_appear: None,
511 on_disappear: Some(Arc::new(action)),
512 })
513 }
514
515 fn on_click<F: Fn() + Send + Sync + 'static>(
517 self,
518 action: F,
519 ) -> ModifiedView<Self, OnClickModifier> {
520 self.modifier(OnClickModifier {
521 action: Arc::new(action),
522 })
523 }
524
525 fn on_pointer_enter<F: Fn() + Send + Sync + 'static>(
527 self,
528 action: F,
529 ) -> ModifiedView<Self, OnPointerEnterModifier> {
530 self.modifier(OnPointerEnterModifier {
531 action: Arc::new(action),
532 })
533 }
534
535 fn on_pointer_leave<F: Fn() + Send + Sync + 'static>(
537 self,
538 action: F,
539 ) -> ModifiedView<Self, OnPointerLeaveModifier> {
540 self.modifier(OnPointerLeaveModifier {
541 action: Arc::new(action),
542 })
543 }
544
545 fn on_pointer_move<F: Fn(f32, f32) + Send + Sync + 'static>(
547 self,
548 action: F,
549 ) -> ModifiedView<Self, OnPointerMoveModifier> {
550 self.modifier(OnPointerMoveModifier {
551 action: Arc::new(action),
552 })
553 }
554
555 fn on_pointer_down<F: Fn() + Send + Sync + 'static>(
557 self,
558 action: F,
559 ) -> ModifiedView<Self, OnPointerDownModifier> {
560 self.modifier(OnPointerDownModifier {
561 action: Arc::new(action),
562 })
563 }
564
565 fn on_pointer_up<F: Fn() + Send + Sync + 'static>(
567 self,
568 action: F,
569 ) -> ModifiedView<Self, OnPointerUpModifier> {
570 self.modifier(OnPointerUpModifier {
571 action: Arc::new(action),
572 })
573 }
574
575 fn erase(self) -> AnyView
577 where
578 Self: Clone + 'static,
579 {
580 AnyView::new(self)
581 }
582}
583
584pub trait ErasedView: Send {
586 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect);
587 fn name(&self) -> &'static str;
588 fn flex_weight_erased(&self) -> f32;
589 fn layout_erased(&self) -> Option<&dyn layout::LayoutView>;
590 fn clone_box(&self) -> Box<dyn ErasedView>;
591}
592
593impl<V: View + Clone + 'static> ErasedView for V {
594 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
595 self.render(renderer, rect);
596 }
597
598 fn name(&self) -> &'static str {
599 std::any::type_name::<V>()
600 }
601
602 fn flex_weight_erased(&self) -> f32 {
603 self.flex_weight()
604 }
605
606 fn layout_erased(&self) -> Option<&dyn layout::LayoutView> {
607 self.layout()
608 }
609
610 fn clone_box(&self) -> Box<dyn ErasedView> {
611 Box::new(self.clone())
612 }
613}
614
615pub struct MemoView<V, F> {
618 id: u64,
619 data_hash: u64,
620 builder: F,
621 _v: std::marker::PhantomData<V>,
622}
623
624impl<V: View, F: Fn() -> V + Send + Sync> MemoView<V, F> {
625 pub fn new(id: u64, data_hash: u64, builder: F) -> Self {
627 Self {
628 id,
629 data_hash,
630 builder,
631 _v: std::marker::PhantomData,
632 }
633 }
634}
635
636impl<V: View + 'static, F: Fn() -> V + Send + Sync + 'static> View for MemoView<V, F> {
637 type Body = Never;
638 fn body(self) -> Self::Body {
639 unreachable!("MemoView does not have a body")
640 }
641
642 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
643 renderer.memoize(self.id, self.data_hash, &|r| {
644 let view = (self.builder)();
645 view.render(r, rect);
646 });
647 }
648}
649
650pub struct AnyView {
652 inner: Box<dyn ErasedView>,
653}
654
655impl Clone for AnyView {
656 fn clone(&self) -> Self {
657 Self {
658 inner: self.inner.clone_box(),
659 }
660 }
661}
662
663impl AnyView {
664 pub fn new<V: View + Clone + 'static>(view: V) -> Self {
665 Self {
666 inner: Box::new(view),
667 }
668 }
669}
670
671impl View for AnyView {
672 type Body = Never;
673 fn body(self) -> Self::Body {
674 unreachable!()
675 }
676
677 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
678 renderer.push_vnode(rect, self.inner.name());
679 self.inner.render_erased(renderer, rect);
680 renderer.pop_vnode();
681 }
682
683 fn flex_weight(&self) -> f32 {
684 self.inner.flex_weight_erased()
685 }
686
687 fn layout(&self) -> Option<&dyn layout::LayoutView> {
688 self.inner.layout_erased()
689 }
690}
691
692#[derive(Debug, Clone, PartialEq)]
696pub struct BifrostBridgeModifier {
697 pub id: String,
698}
699
700impl ViewModifier for BifrostBridgeModifier {
701 fn modify<V: View>(self, content: V) -> impl View {
702 ModifiedView::new(content, self)
703 }
704
705 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
706 renderer.register_shared_element(&self.id, rect);
708 }
709}
710
711#[derive(Debug, Clone, Copy, PartialEq)]
714pub struct MjolnirSliceModifier {
715 pub angle: f32,
716 pub offset: f32,
717}
718
719impl ViewModifier for MjolnirSliceModifier {
720 fn modify<V: View>(self, content: V) -> impl View {
721 ModifiedView::new(content, self)
722 }
723
724 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
725 renderer.push_mjolnir_slice(self.angle, self.offset);
726 }
727
728 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
729 renderer.pop_mjolnir_slice();
730 }
731}
732
733#[derive(Debug, Clone, Copy, PartialEq)]
736pub struct MjolnirShatterModifier {
737 pub pieces: u32,
738 pub force: f32,
739}
740
741impl ViewModifier for MjolnirShatterModifier {
742 fn modify<V: View>(self, content: V) -> impl View {
743 ModifiedView::new(content, self)
744 }
745
746 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
747 let pieces = self.pieces.max(1);
749 for i in 0..pieces {
750 let progress = i as f32 / pieces as f32;
751 let next_progress = (i + 1) as f32 / pieces as f32;
752
753 let angle_start = progress * 360.0;
754 let angle_end = next_progress * 360.0;
755
756 renderer.push_mjolnir_slice(angle_start, 0.0);
758 renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
759
760 let mid_angle = (angle_start + angle_end) / 2.0;
762 let rad = mid_angle.to_radians();
763 let dx = rad.cos() * self.force;
764 let dy = rad.sin() * self.force;
765
766 let shard_rect = Rect {
767 x: rect.x + dx,
768 y: rect.y + dy,
769 ..rect
770 };
771
772 view.render(renderer, shard_rect);
773
774 renderer.pop_mjolnir_slice();
775 renderer.pop_mjolnir_slice();
776 }
777 }
778}
779
780#[derive(Debug, Clone, Copy, PartialEq)]
783pub struct BifrostModifier {
784 pub blur: f32,
785 pub saturation: f32,
786 pub opacity: f32,
787}
788
789impl ViewModifier for BifrostModifier {
790 fn modify<V: View>(self, content: V) -> impl View {
791 ModifiedView::new(content, self)
792 }
793
794 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
795 if renderer.is_over_budget() {
796 renderer.bifrost(rect, self.blur * 0.5, self.saturation, self.opacity);
798 } else {
799 renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
800 }
801 }
802}
803
804#[derive(Debug, Clone, Copy, PartialEq)]
806pub struct BackgroundModifier {
807 pub color: [f32; 4],
808}
809
810impl ViewModifier for BackgroundModifier {
811 fn modify<V: View>(self, content: V) -> impl View {
812 ModifiedView::new(content, self)
813 }
814
815 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
816 renderer.fill_rect(rect, self.color);
817 }
818}
819
820#[derive(Debug, Clone, Copy, PartialEq)]
822pub struct PaddingModifier {
823 pub amount: f32,
824}
825
826impl ViewModifier for PaddingModifier {
827 fn modify<V: View>(self, content: V) -> impl View {
828 ModifiedView::new(content, self)
829 }
830
831 fn transform_rect(&self, rect: Rect) -> Rect {
832 Rect {
833 x: rect.x + self.amount,
834 y: rect.y + self.amount,
835 width: (rect.width - 2.0 * self.amount).max(0.0),
836 height: (rect.height - 2.0 * self.amount).max(0.0),
837 }
838 }
839
840 fn transform_proposal(&self, mut proposal: SizeProposal) -> SizeProposal {
841 if let Some(w) = proposal.width {
842 proposal.width = Some((w - 2.0 * self.amount).max(0.0));
843 }
844 if let Some(h) = proposal.height {
845 proposal.height = Some((h - 2.0 * self.amount).max(0.0));
846 }
847 proposal
848 }
849
850 fn transform_size(&self, mut size: Size) -> Size {
851 size.width += 2.0 * self.amount;
852 size.height += 2.0 * self.amount;
853 size
854 }
855}
856
857#[derive(Debug, Clone, PartialEq)]
860pub struct GungnirModifier {
861 pub color: String,
862 pub radius: f32,
863 pub intensity: f32,
864}
865
866impl ViewModifier for GungnirModifier {
867 fn modify<V: View>(self, content: V) -> impl View {
868 ModifiedView::new(content, self)
869 }
870
871 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
872 renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
874 }
875}
876
877#[derive(Debug, Clone, Copy, PartialEq)]
879pub struct GungnirPulseModifier {
880 pub color: [f32; 4],
881 pub radius: f32,
882 pub speed: f32,
883}
884
885impl ViewModifier for GungnirPulseModifier {
886 fn modify<V: View>(self, content: V) -> impl View {
887 ModifiedView::new(content, self)
888 }
889
890 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
891 let time = std::time::SystemTime::now()
892 .duration_since(std::time::UNIX_EPOCH)
893 .unwrap_or_default()
894 .as_secs_f32();
895
896 let intensity = (time * self.speed).sin() * 0.5 + 0.5;
899 let mut color = self.color;
900 color[3] *= intensity;
901
902 renderer.stroke_rect(rect, color, self.radius);
904 }
905}
906
907#[derive(Debug, Clone, Copy, PartialEq)]
910pub struct MagneticModifier {
911 pub radius: f32,
912 pub intensity: f32,
913}
914
915impl ViewModifier for MagneticModifier {
916 fn modify<V: View>(self, content: V) -> impl View {
917 ModifiedView::new(content, self)
918 }
919
920 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
921 let [px, py] = renderer.get_pointer_position();
922 let center_x = rect.x + rect.width / 2.0;
923 let center_y = rect.y + rect.height / 2.0;
924
925 let dx = px - center_x;
926 let dy = py - center_y;
927 let dist = (dx * dx + dy * dy).sqrt();
928
929 let mut offset_x = 0.0;
930 let mut offset_y = 0.0;
931
932 if dist < self.radius && dist > 0.0 {
933 let force = (1.0 - dist / self.radius) * self.intensity;
934 offset_x = dx * force;
935 offset_y = dy * force;
936 }
937
938 let magnetic_rect = Rect {
939 x: rect.x + offset_x,
940 y: rect.y + offset_y,
941 ..rect
942 };
943
944 view.render(renderer, magnetic_rect);
945 }
946}
947
948#[derive(Debug, Clone, Copy, PartialEq)]
951pub struct ManiGlowModifier {
952 pub color: [f32; 4],
953 pub radius: f32,
954}
955
956impl ViewModifier for ManiGlowModifier {
957 fn modify<V: View>(self, content: V) -> impl View {
958 ModifiedView::new(content, self)
959 }
960
961 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
962 if crate::load_system_state().realm == Realm::Asgard {
963 renderer.mani_glow(rect, self.color, self.radius);
964 }
965 view.render(renderer, rect);
966 }
967}
968
969#[derive(Debug, Clone, Copy, PartialEq)]
974pub struct BifrostLayerModifier {
975 pub layer: MemoryLayer,
976}
977
978impl ViewModifier for BifrostLayerModifier {
979 fn modify<V: View>(self, content: V) -> impl View {
980 ModifiedView::new(content, self)
981 }
982
983 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
984 let realm = crate::load_system_state().realm;
985 match self.layer {
986 MemoryLayer::Episodic => {
987 if realm == Realm::Asgard {
988 renderer.bifrost(rect, 40.0, 1.2, 0.7);
989 } else {
990 renderer.fill_rect(rect, [0.1, 0.12, 0.15, 0.8]);
991 }
992 }
993 MemoryLayer::Semantic => {
994 if realm == Realm::Asgard {
995 renderer.gungnir(rect, [1.0, 0.84, 0.0, 1.0], 15.0, 0.6);
996 } else {
997 renderer.stroke_rect(rect, [0.4, 0.4, 0.4, 1.0], 1.5);
998 }
999 }
1000 MemoryLayer::Procedural => {
1001 renderer.fill_rect(rect, [0.05, 0.05, 0.07, 0.95]);
1002 let stroke_color = if realm == Realm::Asgard { [0.3, 0.3, 0.3, 1.0] } else { [0.2, 0.2, 0.2, 1.0] };
1003 renderer.stroke_rect(rect, stroke_color, 2.0);
1004 }
1005 }
1006 view.render(renderer, rect);
1007 }
1008}
1009
1010#[derive(Debug, Clone, Copy, PartialEq)]
1014pub struct FafnirModifier {
1015 pub id: u64,
1017}
1018
1019impl ViewModifier for FafnirModifier {
1020 fn modify<V: View>(self, content: V) -> impl View {
1021 ModifiedView::new(content, self)
1022 }
1023
1024 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1025 let state = crate::load_system_state();
1026 let vitality = state.get_component_state::<f32>(self.id)
1027 .map(|v| *v.read().unwrap())
1028 .unwrap_or(1.0);
1029
1030 let growth = (vitality - 1.0).clamp(0.0, 4.0);
1033 let scale = 1.0 + growth * 0.12;
1034 let glow_intensity = growth * 0.25;
1035
1036 let id = self.id;
1038 renderer.register_handler("pointermove", std::sync::Arc::new(move |_| {
1039 crate::update_system_state(|s| {
1040 let mut s = s.clone();
1041 let v = s.get_component_state::<f32>(id)
1042 .map(|v| *v.read().unwrap())
1043 .unwrap_or(1.0);
1044 s.set_component_state(id, (v + 0.05).min(5.0)); s
1046 });
1047 }));
1048
1049 if scale > 1.01 {
1050 renderer.push_transform([0.0, 0.0], [scale, scale], 0.0);
1051 }
1052
1053 if glow_intensity > 0.1 && state.realm == Realm::Asgard {
1054 renderer.gungnir(rect, [1.0, 0.84, 0.0, 1.0], 15.0 * vitality, glow_intensity);
1055 }
1056
1057 view.render(renderer, rect);
1058
1059 if scale > 1.01 {
1060 renderer.pop_transform();
1061 }
1062 }
1063}
1064
1065#[derive(Debug, Clone, Copy, PartialEq)]
1067pub struct MimirIntentModifier;
1068
1069impl ViewModifier for MimirIntentModifier {
1070 fn modify<V: View>(self, content: V) -> impl View {
1071 ModifiedView::new(content, self)
1072 }
1073
1074 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1075 let state = crate::load_system_state();
1076 let pos = state.last_pointer_pos;
1077 let vel = state.pointer_velocity;
1078
1079 let center = [rect.x + rect.width / 2.0, rect.y + rect.height / 2.0];
1081 let dx = center[0] - pos[0];
1082 let dy = center[1] - pos[1];
1083
1084 let dot = vel[0] * dx + vel[1] * dy;
1086 let speed_sq = vel[0]*vel[0] + vel[1]*vel[1];
1087 let dist_sq = dx*dx + dy*dy;
1088
1089 if dot > 0.0 && dist_sq < 250.0*250.0 && speed_sq > 0.5 && state.realm == Realm::Asgard {
1090 let intent_strength = (dot / (speed_sq.sqrt() * dist_sq.sqrt())).clamp(0.0, 1.0);
1092 renderer.stroke_rect(rect, [0.0, 0.9, 1.0, 0.3 * intent_strength], 1.5);
1093 }
1094
1095 view.render(renderer, rect);
1096 }
1097}
1098
1099#[derive(Debug, Clone, Copy, PartialEq)]
1101pub struct KvasirVibeModifier {
1102 pub complexity: f32,
1103}
1104
1105impl ViewModifier for KvasirVibeModifier {
1106 fn modify<V: View>(self, content: V) -> impl View {
1107 ModifiedView::new(content, self)
1108 }
1109
1110 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1111 if crate::load_system_state().realm == Realm::Asgard {
1112 let t = renderer.elapsed_time();
1113 let c = self.complexity.clamp(0.0, 1.0);
1114
1115 let blur = 20.0 + c * 40.0;
1118 let turbulence_x = (t * (1.0 + c * 2.0)).sin() * 8.0 * c;
1119 let turbulence_y = (t * (0.8 + c * 1.5)).cos() * 5.0 * c;
1120 renderer.bifrost(rect.offset(turbulence_x, turbulence_y), blur, 0.8 + c * 0.4, 0.25);
1121
1122 if c > 0.2 {
1124 let pulse = (t * (3.0 + c * 5.0)).sin().abs() * c;
1125 let color = [0.0, 0.9, 1.0, 0.4 * pulse]; renderer.gungnir(rect, color, 12.0 + c * 24.0, 0.6 * pulse);
1127 }
1128
1129 if c > 0.7 {
1131 let instability = (t * 15.0).cos().abs() * (c - 0.7) * 3.3;
1132 let warning_color = [1.0, 0.0, 0.4, 0.12 * instability];
1133 renderer.fill_rect(rect, warning_color);
1134 renderer.stroke_rect(rect, [1.0, 0.0, 0.2, 0.45 * instability], 1.8);
1135 }
1136 }
1137 view.render(renderer, rect);
1138 }
1139}
1140
1141#[derive(Debug, Clone, Copy, PartialEq)]
1143pub struct OdinsEyeModifier;
1144
1145impl ViewModifier for OdinsEyeModifier {
1146 fn modify<V: View>(self, content: V) -> impl View {
1147 ModifiedView::new(content, self)
1148 }
1149
1150 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1151 let state = crate::load_system_state();
1152 let t = renderer.elapsed_time();
1153
1154 view.render(renderer, rect);
1156
1157 if state.realm == Realm::Asgard {
1158 let eye_pulse = (t * 0.5).sin().abs() * 0.05;
1161 renderer.draw_radial_gradient(
1162 rect,
1163 [0.0, 0.6, 0.8, 0.08 + eye_pulse], [0.0, 0.0, 0.0, 0.0], );
1166
1167 let hugin_rect = Rect { x: rect.x + 20.0, y: rect.y + 40.0, width: 200.0, height: rect.height - 80.0 };
1169 renderer.draw_text("HUGIN: THOUGHT", hugin_rect.x, hugin_rect.y, 10.0, [0.0, 1.0, 1.0, 0.6]);
1170 for (i, thought) in state.thoughts.iter().rev().take(10).enumerate() {
1171 renderer.draw_text(thought, hugin_rect.x, hugin_rect.y + 20.0 + i as f32 * 14.0, 9.0, [1.0, 1.0, 1.0, 0.4]);
1172 }
1173
1174 let munin_rect = Rect { x: rect.x + rect.width - 220.0, y: rect.y + 40.0, width: 200.0, height: rect.height - 80.0 };
1176 renderer.draw_text("MUNIN: MEMORY", munin_rect.x, munin_rect.y, 10.0, [1.0, 0.84, 0.0, 0.6]);
1177 for (i, node) in state.nodes.iter().take(10).enumerate() {
1178 let opacity = (node.weight.min(1.0)) * 0.5;
1179 renderer.draw_text(&node.id, munin_rect.x, munin_rect.y + 20.0 + i as f32 * 14.0, 9.0, [1.0, 1.0, 1.0, opacity]);
1180 }
1181
1182 if let Some(focus_id) = &state.odin_focus {
1184 renderer.draw_text(&format!("EYE FOCUS: {}", focus_id), rect.x + rect.width / 2.0 - 50.0, rect.y + 20.0, 12.0, [0.0, 1.0, 1.0, 0.8]);
1186
1187 renderer.gungnir(Rect { x: rect.x + rect.width / 2.0 - 1.0, y: rect.y, width: 2.0, height: rect.height }, [0.0, 1.0, 1.0, 1.0], 20.0, 0.4);
1190 }
1191 }
1192 }
1193}
1194
1195#[derive(Debug, Clone, Copy, PartialEq)]
1197pub struct SleipnirParams {
1198 pub stiffness: f32,
1199 pub damping: f32,
1200 pub mass: f32,
1201}
1202
1203impl SleipnirParams {
1204 pub fn snappy() -> Self { Self { stiffness: 230.0, damping: 22.0, mass: 1.0 } }
1205 pub fn fluid() -> Self { Self { stiffness: 170.0, damping: 26.0, mass: 1.0 } }
1206 pub fn heavy() -> Self { Self { stiffness: 90.0, damping: 20.0, mass: 1.0 } }
1207 pub fn bouncy() -> Self { Self { stiffness: 190.0, damping: 14.0, mass: 1.0 } }
1208}
1209
1210impl Default for SleipnirParams {
1211 fn default() -> Self { Self::fluid() }
1212}
1213
1214#[derive(Debug, Clone, Copy, PartialEq)]
1215struct SolverState {
1216 x: f32,
1217 v: f32,
1218}
1219
1220#[derive(Debug, Clone, Copy, PartialEq)]
1223pub struct SleipnirSolver {
1224 params: SleipnirParams,
1225 target: f32,
1226 state: SolverState,
1227}
1228
1229impl SleipnirSolver {
1230 pub fn new(params: SleipnirParams, target: f32, current: f32) -> Self {
1232 Self {
1233 params,
1234 target,
1235 state: SolverState { x: current, v: 0.0 },
1236 }
1237 }
1238
1239 pub fn tick(&mut self, dt: f32) -> f32 {
1241 if dt <= 0.0 { return self.state.x; }
1242
1243 let mut remaining = dt;
1245 let step = 1.0 / 120.0;
1246
1247 while remaining > 0.0 {
1248 let d = remaining.min(step);
1249 self.step(d);
1250 remaining -= d;
1251 }
1252
1253 self.state.x
1254 }
1255
1256 fn step(&mut self, dt: f32) {
1257 let a = self.evaluate(self.state, 0.0, SolverState { x: 0.0, v: 0.0 });
1258 let b = self.evaluate(self.state, dt * 0.5, a);
1259 let c = self.evaluate(self.state, dt * 0.5, b);
1260 let d = self.evaluate(self.state, dt, c);
1261
1262 let dxdt = 1.0 / 6.0 * (a.x + 2.0 * (b.x + c.x) + d.x);
1263 let dvdt = 1.0 / 6.0 * (a.v + 2.0 * (b.v + c.v) + d.v);
1264
1265 self.state.x += dxdt * dt;
1266 self.state.v += dvdt * dt;
1267 }
1268
1269 fn evaluate(&self, initial: SolverState, dt: f32, d: SolverState) -> SolverState {
1270 let state = SolverState {
1271 x: initial.x + d.x * dt,
1272 v: initial.v + d.v * dt,
1273 };
1274 let force = -self.params.stiffness * (state.x - self.target) - self.params.damping * state.v;
1275 let mass = self.params.mass.max(0.001);
1276 SolverState { x: state.v, v: force / mass }
1277 }
1278
1279 pub fn is_settled(&self) -> bool {
1280 (self.state.x - self.target).abs() < 0.001 && self.state.v.abs() < 0.001
1281 }
1282
1283 pub fn set_target(&mut self, target: f32) {
1284 self.target = target;
1285 }
1286
1287 pub fn current_value(&self) -> f32 {
1288 self.state.x
1289 }
1290}
1291
1292#[derive(Debug, Clone, PartialEq)]
1294pub struct SleipnirModifier {
1295 pub id: u64,
1296 pub target: f32,
1297 pub params: SleipnirParams,
1298}
1299
1300impl ViewModifier for SleipnirModifier {
1301 fn modify<V: View>(self, content: V) -> impl View {
1302 ModifiedView::new(content, self)
1303 }
1304
1305 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1306 let state = load_system_state();
1307
1308 let solver_lock_opt = state.get_component_state::<SleipnirSolver>(self.id);
1310
1311 let current_val;
1312
1313 if let Some(lock) = solver_lock_opt {
1314 let mut solver = lock.write().unwrap();
1316 solver.set_target(self.target);
1317 current_val = solver.tick(renderer.delta_time());
1318
1319 if !solver.is_settled() {
1321 renderer.request_redraw();
1322 }
1323 } else {
1324 let solver = SleipnirSolver::new(
1326 self.params,
1327 self.target,
1328 self.target );
1330
1331 get_system_state().rcu(|old| {
1333 let mut new_state = (**old).clone();
1334 new_state.set_component_state(self.id, solver);
1335 new_state
1336 });
1337
1338 current_val = self.target;
1339 }
1340
1341 renderer.push_transform([0.0, current_val], [1.0, 1.0], 0.0);
1343 view.render(renderer, rect);
1344 renderer.pop_transform();
1345 }
1346}
1347
1348#[derive(Debug, Clone, Copy, PartialEq)]
1351pub struct TransformModifier {
1352 pub translation: [f32; 2],
1353 pub scale: [f32; 2],
1354 pub rotation: f32,
1355}
1356
1357impl Default for TransformModifier {
1358 fn default() -> Self {
1359 Self::new()
1360 }
1361}
1362
1363impl TransformModifier {
1364 pub fn new() -> Self {
1365 Self {
1366 translation: [0.0, 0.0],
1367 scale: [1.0, 1.0],
1368 rotation: 0.0,
1369 }
1370 }
1371
1372 pub fn translate(mut self, x: f32, y: f32) -> Self {
1373 self.translation = [x, y];
1374 self
1375 }
1376
1377 pub fn scale(mut self, x: f32, y: f32) -> Self {
1378 self.scale = [x, y];
1379 self
1380 }
1381
1382 pub fn rotate(mut self, radians: f32) -> Self {
1383 self.rotation = radians;
1384 self
1385 }
1386}
1387
1388impl ViewModifier for TransformModifier {
1389 fn modify<V: View>(self, content: V) -> impl View {
1390 ModifiedView::new(content, self)
1391 }
1392
1393 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1394 renderer.push_transform(self.translation, self.scale, self.rotation);
1395 view.render(renderer, rect);
1396 renderer.pop_transform();
1397 }
1398}
1399
1400#[derive(Clone)]
1403pub struct LifecycleModifier {
1404 pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
1405 pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
1406}
1407
1408impl ViewModifier for LifecycleModifier {
1409 fn modify<V: View>(self, content: V) -> impl View {
1410 ModifiedView::new(content, self)
1411 }
1412}
1413
1414#[derive(Debug, Clone, Copy, PartialEq)]
1417pub struct OpacityModifier {
1418 pub opacity: f32,
1419}
1420
1421impl ViewModifier for OpacityModifier {
1422 fn modify<V: View>(self, content: V) -> impl View {
1423 ModifiedView::new(content, self)
1424 }
1425
1426 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1427 renderer.push_opacity(self.opacity);
1428 }
1429
1430 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1431 renderer.pop_opacity();
1432 }
1433}
1434
1435#[derive(Clone)]
1437pub struct OnClickModifier {
1438 pub action: Arc<dyn Fn() + Send + Sync>,
1439}
1440
1441impl ViewModifier for OnClickModifier {
1442 fn modify<V: View>(self, content: V) -> impl View {
1443 ModifiedView::new(content, self)
1444 }
1445
1446 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1447 let action = self.action.clone();
1448 renderer.register_handler(
1449 "pointerclick",
1450 std::sync::Arc::new(move |event| {
1451 if let Event::PointerClick { .. } = event {
1452 (action)();
1453 }
1454 }),
1455 );
1456 }
1457}
1458
1459#[derive(Clone)]
1461pub struct OnPointerEnterModifier {
1462 pub action: Arc<dyn Fn() + Send + Sync>,
1463}
1464
1465impl ViewModifier for OnPointerEnterModifier {
1466 fn modify<V: View>(self, content: V) -> impl View {
1467 ModifiedView::new(content, self)
1468 }
1469
1470 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1471 let action = self.action.clone();
1472 renderer.register_handler(
1473 "pointerenter",
1474 std::sync::Arc::new(move |event| {
1475 if let Event::PointerEnter = event {
1476 (action)();
1477 }
1478 }),
1479 );
1480 }
1481}
1482
1483#[derive(Clone)]
1485pub struct OnPointerLeaveModifier {
1486 pub action: Arc<dyn Fn() + Send + Sync>,
1487}
1488
1489impl ViewModifier for OnPointerLeaveModifier {
1490 fn modify<V: View>(self, content: V) -> impl View {
1491 ModifiedView::new(content, self)
1492 }
1493
1494 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1495 let action = self.action.clone();
1496 renderer.register_handler(
1497 "pointerleave",
1498 std::sync::Arc::new(move |event| {
1499 if let Event::PointerLeave = event {
1500 (action)();
1501 }
1502 }),
1503 );
1504 }
1505}
1506
1507#[derive(Clone)]
1509pub struct OnPointerMoveModifier {
1510 pub action: Arc<dyn Fn(f32, f32) + Send + Sync>,
1511}
1512
1513impl ViewModifier for OnPointerMoveModifier {
1514 fn modify<V: View>(self, content: V) -> impl View {
1515 ModifiedView::new(content, self)
1516 }
1517
1518 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1519 let action = self.action.clone();
1520 renderer.register_handler(
1521 "pointermove",
1522 std::sync::Arc::new(move |event| {
1523 if let Event::PointerMove { x, y } = event {
1524 (action)(x, y);
1525 }
1526 }),
1527 );
1528 }
1529}
1530
1531#[derive(Clone)]
1533pub struct OnPointerDownModifier {
1534 pub action: Arc<dyn Fn() + Send + Sync>,
1535}
1536
1537impl ViewModifier for OnPointerDownModifier {
1538 fn modify<V: View>(self, content: V) -> impl View {
1539 ModifiedView::new(content, self)
1540 }
1541
1542 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1543 let action = self.action.clone();
1544 renderer.register_handler(
1545 "pointerdown",
1546 std::sync::Arc::new(move |event| {
1547 if let Event::PointerDown { .. } = event {
1548 (action)();
1549 }
1550 }),
1551 );
1552 }
1553}
1554
1555#[derive(Clone)]
1557pub struct OnPointerUpModifier {
1558 pub action: Arc<dyn Fn() + Send + Sync>,
1559}
1560
1561impl ViewModifier for OnPointerUpModifier {
1562 fn modify<V: View>(self, content: V) -> impl View {
1563 ModifiedView::new(content, self)
1564 }
1565
1566 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1567 let action = self.action.clone();
1568 renderer.register_handler(
1569 "pointerup",
1570 std::sync::Arc::new(move |event| {
1571 if let Event::PointerUp { .. } = event {
1572 (action)();
1573 }
1574 }),
1575 );
1576 }
1577}
1578
1579#[derive(Debug, Clone, Copy, PartialEq)]
1582pub struct ForegroundColorModifier {
1583 pub color: [f32; 4],
1584}
1585
1586impl ViewModifier for ForegroundColorModifier {
1587 fn modify<V: View>(self, content: V) -> impl View {
1588 ModifiedView::new(content, self)
1589 }
1590}
1591
1592#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1595pub struct ClipModifier;
1596
1597impl ViewModifier for ClipModifier {
1598 fn modify<V: View>(self, content: V) -> impl View {
1599 ModifiedView::new(content, self)
1600 }
1601
1602 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1603 renderer.push_clip_rect(rect);
1604 }
1605
1606 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1607 renderer.pop_clip_rect();
1608 }
1609}
1610
1611#[derive(Debug, Clone, Copy, PartialEq)]
1613pub struct BorderModifier {
1614 pub color: [f32; 4],
1615 pub width: f32,
1616}
1617
1618impl ViewModifier for BorderModifier {
1619 fn modify<V: View>(self, content: V) -> impl View {
1620 ModifiedView::new(content, self)
1621 }
1622
1623 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1624 renderer.stroke_rect(rect, self.color, self.width);
1625 }
1626}
1627
1628#[doc(hidden)]
1630pub enum Never {}
1631
1632impl View for Never {
1633 type Body = Never;
1634 fn body(self) -> Never {
1635 unreachable!()
1636 }
1637}
1638
1639#[derive(Debug, Clone, Copy, Default)]
1641pub struct EmptyView;
1642
1643impl View for EmptyView {
1644 type Body = Never;
1645 fn body(self) -> Self::Body { unreachable!() }
1646 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1647 fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
1648 Size { width: 0.0, height: 0.0 }
1649 }
1650}
1651
1652#[derive(Clone)]
1656pub struct ModifiedView<V, M> {
1657 view: V,
1658 modifier: M,
1659}
1660
1661impl<V: View, M: ViewModifier> ModifiedView<V, M> {
1662 #[doc(hidden)]
1663 pub fn new(view: V, modifier: M) -> Self {
1664 Self { view, modifier }
1665 }
1666}
1667
1668impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
1669 type Body = ModifiedView<V::Body, M>;
1670
1671 fn body(self) -> Self::Body {
1672 ModifiedView {
1673 view: self.view.body(),
1674 modifier: self.modifier.clone(),
1675 }
1676 }
1677
1678 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1679 self.modifier.render_view(&self.view, renderer, rect);
1680 }
1681
1682 fn intrinsic_size(&self, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1683 self.modifier.measure_view(&self.view, renderer, proposal)
1684 }
1685
1686 fn flex_weight(&self) -> f32 {
1687 self.modifier.child_flex_weight(&self.view)
1688 }
1689
1690 fn layout(&self) -> Option<&dyn layout::LayoutView> {
1691 self.modifier.layout().or_else(|| self.view.layout())
1692 }
1693}
1694
1695pub trait ViewModifier: Send + Clone {
1696 fn modify<V: View>(self, content: V) -> impl View;
1697
1698 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1700
1701 fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1703
1704 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1707 self.render(renderer, rect);
1708 let child_rect = self.transform_rect(rect);
1709 view.render(renderer, child_rect);
1710 self.post_render(renderer, rect);
1711 }
1712
1713 fn transform_rect(&self, rect: Rect) -> Rect {
1714 rect
1715 }
1716
1717 fn transform_proposal(&self, proposal: SizeProposal) -> SizeProposal {
1719 proposal
1720 }
1721
1722 fn transform_size(&self, size: Size) -> Size {
1724 size
1725 }
1726
1727 fn measure_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1729 let child_proposal = self.transform_proposal(proposal);
1730 let child_size = view.intrinsic_size(renderer, child_proposal);
1731 self.transform_size(child_size)
1732 }
1733
1734 fn child_flex_weight<V: View>(&self, view: &V) -> f32 {
1736 view.flex_weight()
1737 }
1738
1739 fn layout(&self) -> Option<&dyn layout::LayoutView> {
1740 None
1741 }
1742}
1743
1744#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1746pub struct TelemetryData {
1747 pub frame_time_ms: f32,
1748 pub p99_frame_time_ms: f32,
1750 pub frame_jitter_ms: f32,
1752 pub hardware_stall_detected: bool,
1754
1755 pub input_time_ms: f32,
1757 pub state_flush_time_ms: f32,
1758 pub layout_time_ms: f32,
1759 pub draw_time_ms: f32,
1760 pub gpu_submit_time_ms: f32,
1761
1762 pub draw_calls: u32,
1763 pub vertices: u32,
1764
1765 pub berserker_rage: f32,
1767
1768 pub vram_usage_mb: f32,
1770 pub vram_textures_mb: f32,
1771 pub vram_buffers_mb: f32,
1772 pub vram_pipelines_mb: f32,
1773 pub vram_exhausted: bool,
1775}
1776
1777#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1779pub struct FrameBudget {
1780 pub target_ms: f32,
1782 pub allow_degradation: bool,
1785}
1786
1787impl Default for FrameBudget {
1788 fn default() -> Self {
1789 Self {
1790 target_ms: 16.0,
1791 allow_degradation: true,
1792 }
1793 }
1794}
1795
1796pub trait ElapsedTime {
1805 fn elapsed_time(&self) -> f32;
1807
1808 fn delta_time(&self) -> f32;
1810}
1811
1812pub trait Renderer: ElapsedTime + Send {
1820 fn request_redraw(&mut self) {}
1823
1824 fn is_over_budget(&self) -> bool {
1827 false
1828 }
1829
1830 fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
1832 fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
1833 fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
1835
1836 fn draw_3d_cube(&mut self, _rect: Rect, _color: [f32; 4], _rotation: [f32; 3]) {}
1839
1840 fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1842 fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
1843 fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1845 fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
1847 fn fill_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4]) {}
1849 fn stroke_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4], _stroke_width: f32) {}
1851
1852 fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
1854 fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
1856
1857 fn draw_texture(&mut self, _texture_id: u32, _rect: Rect) {}
1860 fn draw_image(&mut self, _image_name: &str, _rect: Rect) {}
1862 fn load_image(&mut self, _name: &str, _data: &[u8]) {}
1864 fn prewarm_vram(&mut self, _assets: Vec<(String, Vec<u8>)>) {}
1867
1868 fn get_pointer_position(&self) -> [f32; 2] {
1870 [0.0, 0.0]
1871 }
1872
1873 fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
1876 fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
1878
1879 fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
1882
1883 fn draw_linear_gradient(
1886 &mut self,
1887 _rect: Rect,
1888 _start_color: [f32; 4],
1889 _end_color: [f32; 4],
1890 _angle: f32,
1891 ) {
1892 }
1893 fn draw_radial_gradient(
1895 &mut self,
1896 _rect: Rect,
1897 _inner_color: [f32; 4],
1898 _outer_color: [f32; 4],
1899 ) {
1900 }
1901 fn draw_drop_shadow(
1903 &mut self,
1904 _rect: Rect,
1905 _radius: f32,
1906 _color: [f32; 4],
1907 _blur: f32,
1908 _spread: f32,
1909 ) {
1910 }
1911 fn stroke_dashed_rounded_rect(
1913 &mut self,
1914 _rect: Rect,
1915 _radius: f32,
1916 _color: [f32; 4],
1917 _width: f32,
1918 _dash: f32,
1919 _gap: f32,
1920 ) {
1921 }
1922 fn draw_9slice(
1924 &mut self,
1925 _image_name: &str,
1926 _rect: Rect,
1927 _left: f32,
1928 _top: f32,
1929 _right: f32,
1930 _bottom: f32,
1931 ) {
1932 }
1933
1934 fn push_clip_rect(&mut self, _rect: Rect) {}
1938 fn pop_clip_rect(&mut self) {}
1940 fn current_clip_rect(&self) -> Rect {
1943 Rect::new(-10000.0, -10000.0, 20000.0, 20000.0)
1944 }
1945
1946 fn push_opacity(&mut self, _opacity: f32) {}
1950 fn pop_opacity(&mut self) {}
1952
1953 fn set_theme(&mut self, _theme: ColorTheme) {}
1955 fn set_rage(&mut self, _rage: f32) {}
1956 fn set_berserker_mode(&mut self, _state: BerserkerMode) {}
1957 fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
1958 fn set_scene(&mut self, _scene: &str) {}
1960
1961 fn capture_png(&mut self) -> Vec<u8> { Vec::new() }
1964 fn print(&mut self) {}
1966
1967 fn set_scene_preset(&mut self, _preset: u32) {}
1968
1969 fn bifrost(&mut self, _rect: Rect, _blur: f32, _saturation: f32, _opacity: f32) {}
1972 fn gungnir(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32, _intensity: f32) {}
1974 fn mani_glow(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32) {}
1976 fn push_mjolnir_slice(&mut self, _angle: f32, _offset: f32) {}
1978 fn pop_mjolnir_slice(&mut self) {}
1979 fn memoize(&mut self, id: u64, data_hash: u64, render_fn: &dyn Fn(&mut dyn Renderer));
1983 fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1985 fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1986 fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
1988
1989 fn set_aria_role(&mut self, _role: &str) {}
1991 fn set_aria_label(&mut self, _label: &str) {}
1992
1993 fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
1995
1996 fn set_key(&mut self, _key: &str) {}
1998
1999 fn get_telemetry(&self) -> TelemetryData {
2002 TelemetryData::default()
2003 }
2004
2005 fn push_shadow(&mut self, _radius: f32, _color: [f32; 4], _offset: [f32; 2]) {}
2008 fn pop_shadow(&mut self) {}
2010
2011 fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
2014 fn pop_vnode(&mut self) {}
2016 fn register_handler(
2018 &mut self,
2019 _event_type: &str,
2020 _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
2021 ) {
2022 }
2023
2024 fn set_z_index(&mut self, _z: f32) {}
2028 fn get_z_index(&self) -> f32 {
2030 0.0
2031 }
2032
2033 fn load_svg(&mut self, _name: &str, _svg_data: &[u8]) {}
2036 fn draw_svg(&mut self, _name: &str, _rect: Rect) {}
2038
2039 fn push_transform(&mut self, _translation: [f32; 2], _scale: [f32; 2], _rotation: f32) {}
2044 fn pop_transform(&mut self) {}
2046 fn query_layout(&self, _node_id: scene_graph::NodeId) -> Option<Rect> {
2048 None
2049 }
2050 fn set_debug_layout(&mut self, _enabled: bool) {}
2052 fn get_debug_layout(&self) -> bool {
2054 false
2055 }
2056}
2057
2058pub mod accessibility {
2060 pub fn relative_luminance(color: [f32; 4]) -> f32 {
2062 let f = |c: f32| {
2063 if c <= 0.03928 {
2064 c / 12.92
2065 } else {
2066 ((c + 0.055) / 1.055).powf(2.4)
2067 }
2068 };
2069 0.2126 * f(color[0]) + 0.7152 * f(color[1]) + 0.0722 * f(color[2])
2070 }
2071
2072 pub fn contrast_ratio(c1: [f32; 4], c2: [f32; 4]) -> f32 {
2074 let l1 = relative_luminance(c1);
2075 let l2 = relative_luminance(c2);
2076 let (light, dark) = if l1 > l2 { (l1, l2) } else { (l2, l1) };
2077 (light + 0.05) / (dark + 0.05)
2078 }
2079}
2080#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
2082pub enum RenderTier {
2083 Tier1GPU = 0,
2085 Tier2GPU = 1,
2087 Tier3Fallback = 2,
2089}
2090use bytemuck::{Pod, Zeroable};
2094#[repr(C)]
2096#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
2097pub struct ColorTheme {
2098 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
2100 pub glass_base: [f32; 4],
2101 pub glass_edge: [f32; 4],
2102 pub rune_glow: [f32; 4],
2103 pub ember_core: [f32; 4],
2104 pub background_deep: [f32; 4],
2105 pub mani_glow: [f32; 4], pub glass_blur_strength: f32,
2107 pub shatter_edge_width: f32,
2108 pub neon_bloom_radius: f32,
2109 pub rune_opacity: f32,
2110}
2111impl ColorTheme {
2112 pub fn asgard() -> Self {
2114 Self {
2115 primary_neon: [0.0, 1.0, 0.95, 1.2],
2116 shatter_neon: [1.0, 0.0, 0.75, 1.5],
2117 glass_base: [0.04, 0.04, 0.06, 0.82],
2118 glass_edge: [0.0, 0.45, 0.55, 0.6],
2119 rune_glow: [0.75, 0.98, 1.0, 0.9],
2120 ember_core: [0.95, 0.12, 0.12, 1.0],
2121 background_deep: [0.01, 0.01, 0.03, 1.0],
2122 mani_glow: [0.7, 0.9, 1.0, 0.05],
2123 glass_blur_strength: 0.6,
2124 shatter_edge_width: 1.8,
2125 neon_bloom_radius: 0.022,
2126 rune_opacity: 0.55,
2127 }
2128 }
2129
2130 pub fn midgard() -> Self {
2132 Self {
2133 primary_neon: [0.2, 0.4, 0.6, 1.0], shatter_neon: [0.5, 0.5, 0.5, 1.0], glass_base: [0.1, 0.12, 0.15, 1.0], glass_edge: [0.3, 0.35, 0.4, 1.0], rune_glow: [0.8, 0.8, 0.8, 0.0], ember_core: [0.5, 0.5, 0.5, 1.0],
2139 background_deep: [0.05, 0.05, 0.07, 1.0],
2140 mani_glow: [0.0, 0.0, 0.0, 0.0], glass_blur_strength: 0.0, shatter_edge_width: 1.0,
2143 neon_bloom_radius: 0.0,
2144 rune_opacity: 0.0,
2145 }
2146 }
2147
2148 pub fn cyberpunk_viking() -> Self {
2149 Self::asgard()
2150 }
2151 pub fn vibrant_glass() -> Self {
2152 Self {
2153 primary_neon: [0.0, 1.0, 0.95, 1.2],
2154 shatter_neon: [1.0, 0.0, 0.75, 1.5],
2155 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],
2158 ember_core: [1.0, 0.4, 0.1, 1.0],
2159 background_deep: [0.05, 0.05, 0.1, 1.0],
2160 mani_glow: [0.7, 0.9, 1.0, 0.05],
2161 glass_blur_strength: 0.9,
2162 shatter_edge_width: 1.8,
2163 neon_bloom_radius: 0.022,
2164 rune_opacity: 0.55,
2165 }
2166 }
2167}
2168impl Default for ColorTheme {
2169 fn default() -> Self {
2170 Self::vibrant_glass()
2171 }
2172}
2173#[repr(C)]
2175#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
2176pub struct SceneUniforms {
2177 pub view: glam::Mat4,
2178 pub proj: glam::Mat4,
2179 pub time: f32,
2180 pub delta_time: f32,
2181 pub resolution: [f32; 2],
2182 pub mouse: [f32; 2],
2183 pub mouse_velocity: [f32; 2],
2184 pub shatter_origin: [f32; 2],
2185 pub shatter_time: f32,
2186 pub shatter_force: f32,
2187 pub berzerker_rage: f32,
2188 pub berzerker_mode: u32,
2189 pub scroll_offset: f32,
2190 pub scale_factor: f32,
2191 pub scene_type: u32,
2192 pub _pad: [f32; 3], }
2194
2195pub const SCENE_AURORA: u32 = 0;
2196pub const SCENE_VOID: u32 = 1;
2197pub const SCENE_NEBULA: u32 = 2;
2198pub const SCENE_GLITCH: u32 = 3;
2199pub const SCENE_YGGDRASIL: u32 = 4;
2200
2201impl SceneUniforms {
2202 pub fn new(width: f32, height: f32) -> Self {
2203 Self {
2204 view: glam::Mat4::IDENTITY,
2205 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
2206 time: 0.0,
2207 delta_time: 0.016,
2208 resolution: [width, height],
2209 mouse: [0.5, 0.5],
2210 mouse_velocity: [0.0, 0.0],
2211 shatter_origin: [0.5, 0.5],
2212 shatter_time: -100.0,
2213 shatter_force: 0.0,
2214 berzerker_rage: 0.0,
2215 berzerker_mode: 0,
2216 scroll_offset: 0.0,
2217 scale_factor: 1.0,
2218 scene_type: SCENE_AURORA,
2219 _pad: [0.0; 3],
2220 }
2221 }
2222}
2223#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
2225pub struct Mesh {
2226 pub vertices: Vec<[f32; 3]>,
2227 pub normals: Vec<[f32; 3]>,
2228 pub indices: Vec<u32>,
2229}
2230impl Mesh {
2231 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
2232 let mut cursor = std::io::Cursor::new(data);
2233 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
2234 Ok((Vec::new(), Default::default()))
2235 })?;
2236 let mut meshes = Vec::new();
2237 for m in models {
2238 let mesh = m.mesh;
2239 let vertices: Vec<[f32; 3]> = mesh
2240 .positions
2241 .chunks(3)
2242 .map(|c| [c[0], c[1], c[2]])
2243 .collect();
2244 let normals = if mesh.normals.is_empty() {
2245 vec![[0.0, 0.0, 1.0]; vertices.len()]
2246 } else {
2247 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
2248 };
2249 meshes.push(Mesh {
2250 vertices,
2251 normals,
2252 indices: mesh.indices,
2253 });
2254 }
2255 Ok(meshes)
2256 }
2257 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
2258 let mut cursor = std::io::Cursor::new(data);
2259 let stl = stl_io::read_stl(&mut cursor)?;
2260 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
2261 let mut indices = Vec::new();
2262 for face in stl.faces {
2263 indices.push(face.vertices[0] as u32);
2264 indices.push(face.vertices[1] as u32);
2265 indices.push(face.vertices[2] as u32);
2266 }
2267 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
2268 Ok(Mesh {
2269 vertices,
2270 normals,
2271 indices,
2272 })
2273 }
2274}
2275pub trait FrameRenderer<E = ()>: Renderer {
2278 fn begin_frame(&mut self) -> E;
2279 fn render_frame(&mut self) {
2280 }
2282 fn end_frame(&mut self, encoder: E);
2283}
2284use std::sync::Arc;
2285type SubscriberList<T> = Arc<std::sync::Mutex<Vec<Box<dyn Fn(&T) + Send + Sync>>>>;
2286#[derive(Clone)]
2288pub struct State<T: Clone + Send + Sync + 'static> {
2289 swap: Arc<arc_swap::ArcSwap<T>>,
2290 metadata_swap: Arc<arc_swap::ArcSwap<Option<agents::MutationMetadata>>>,
2291 #[cfg(not(target_arch = "wasm32"))]
2292 tvar: Arc<stm::TVar<T>>,
2293 #[cfg(not(target_arch = "wasm32"))]
2294 metadata_tvar: Arc<stm::TVar<Option<agents::MutationMetadata>>>,
2295 subscribers: SubscriberList<T>,
2296 version: Arc<std::sync::atomic::AtomicU64>,
2297 resolution: agents::ConflictResolution,
2298}
2299impl<T: Clone + Send + Sync + 'static> State<T> {
2300 pub fn new(value: T) -> Self {
2302 #[cfg(not(target_arch = "wasm32"))]
2303 let tvar = Arc::new(stm::TVar::new(value.clone()));
2304 #[cfg(not(target_arch = "wasm32"))]
2305 let metadata_tvar = Arc::new(stm::TVar::new(None));
2306 Self {
2307 swap: Arc::new(arc_swap::ArcSwap::from_pointee(value)),
2308 metadata_swap: Arc::new(arc_swap::ArcSwap::new(Arc::new(None))),
2309 #[cfg(not(target_arch = "wasm32"))]
2310 tvar,
2311 #[cfg(not(target_arch = "wasm32"))]
2312 metadata_tvar,
2313 subscribers: Arc::new(std::sync::Mutex::new(Vec::new())),
2314 version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
2315 resolution: agents::ConflictResolution::default(),
2316 }
2317 }
2318 pub fn with_resolution(mut self, resolution: agents::ConflictResolution) -> Self {
2320 self.resolution = resolution;
2321 self
2322 }
2323 pub fn get(&self) -> T {
2325 (**self.swap.load()).clone()
2326 }
2327 pub fn set(&self, value: T) {
2329 #[cfg(not(target_arch = "wasm32"))]
2330 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
2331 let new_meta = agents::get_current_mutation_metadata();
2332 let existing_meta = self.metadata_tvar.read(tx)?;
2333 let mut skip = false;
2334 if self.resolution == agents::ConflictResolution::PriorityWins
2335 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
2336 && new_m.priority < old_m.priority {
2337 skip = true;
2338 }
2339 if !skip {
2340 self.tvar.write(tx, value.clone())?;
2341 self.metadata_tvar.write(tx, new_meta)?;
2342 Ok((false, value.clone(), new_meta))
2343 } else {
2344 Ok((true, self.tvar.read(tx)?, existing_meta))
2345 }
2346 });
2347 #[cfg(target_arch = "wasm32")]
2348 let (was_skipped, final_val, final_meta) = (false, value, agents::get_current_mutation_metadata());
2349 if was_skipped {
2350 if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
2351 agents::notify_conflict(agents::ConflictEvent {
2352 agent_id: new_m.agent_id,
2353 priority: new_m.priority,
2354 existing_agent_id: old_m.agent_id,
2355 existing_priority: old_m.priority,
2356 timestamp_ms: new_m.timestamp_ms,
2357 });
2358 }
2359 return;
2360 }
2361 self.swap.store(Arc::new(final_val.clone()));
2362 self.metadata_swap.store(Arc::new(final_meta));
2363 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2364 let subs = Arc::clone(&self.subscribers);
2365 if crate::is_batching() {
2366 crate::enqueue_batch_task(Box::new(move || {
2367 let s = subs.lock().unwrap();
2368 for cb in s.iter() {
2369 cb(&final_val);
2370 }
2371 }));
2372 } else {
2373 let s = subs.lock().unwrap();
2374 for cb in s.iter() {
2375 cb(&final_val);
2376 }
2377 }
2378 }
2379 pub fn mutate<F: Fn(&T) -> T>(&self, f: F) {
2380 #[cfg(not(target_arch = "wasm32"))]
2381 {
2382 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
2383 let new_meta = agents::get_current_mutation_metadata();
2384 let existing_meta = self.metadata_tvar.read(tx)?;
2385 let mut skip = false;
2386 if self.resolution == agents::ConflictResolution::PriorityWins
2387 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
2388 && new_m.priority < old_m.priority {
2389 skip = true;
2390 }
2391 if !skip {
2392 let current = self.tvar.read(tx)?;
2393 let next = f(¤t);
2394 self.tvar.write(tx, next.clone())?;
2395 self.metadata_tvar.write(tx, new_meta)?;
2396 Ok((false, next, new_meta))
2397 } else {
2398 Ok((true, self.tvar.read(tx)?, existing_meta))
2399 }
2400 });
2401 if was_skipped {
2402 if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
2403 agents::notify_conflict(agents::ConflictEvent {
2404 agent_id: new_m.agent_id,
2405 priority: new_m.priority,
2406 existing_agent_id: old_m.agent_id,
2407 existing_priority: old_m.priority,
2408 timestamp_ms: new_m.timestamp_ms,
2409 });
2410 }
2411 return;
2412 }
2413 self.swap.store(Arc::new(final_val.clone()));
2414 self.metadata_swap.store(Arc::new(final_meta));
2415 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2416 let subs = Arc::clone(&self.subscribers);
2417 if crate::is_batching() {
2418 crate::enqueue_batch_task(Box::new(move || {
2419 let s = subs.lock().unwrap();
2420 for cb in s.iter() {
2421 cb(&final_val);
2422 }
2423 }));
2424 } else {
2425 let s = subs.lock().unwrap();
2426 for cb in s.iter() {
2427 cb(&final_val);
2428 }
2429 }
2430 }
2431 #[cfg(target_arch = "wasm32")]
2432 {
2433 self.set(f(&self.get()));
2434 }
2435 }
2436 pub fn version(&self) -> u64 {
2438 self.version.load(std::sync::atomic::Ordering::Acquire)
2439 }
2440 pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
2442 self.subscribers.lock().unwrap().push(Box::new(callback));
2443 }
2444}
2445use crate::runtime::NodeStateSnapshot;
2446use std::sync::atomic::{AtomicBool, Ordering};
2447use std::sync::OnceLock;
2448pub static SYSTEM_STATE: OnceLock<Arc<arc_swap::ArcSwap<KnowledgeState>>> = OnceLock::new();
2450#[cfg(not(target_arch = "wasm32"))]
2451static KNOWLEDGE_TVAR: OnceLock<stm::TVar<KnowledgeState>> = OnceLock::new();
2452static IS_BATCHING: AtomicBool = AtomicBool::new(false);
2453pub static IS_RENDERING: AtomicBool = AtomicBool::new(false);
2454pub static LAYOUT_DIRTY: AtomicBool = AtomicBool::new(false);
2455type BatchQueue = OnceLock<std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync>>>>;
2456static BATCH_QUEUE: BatchQueue = OnceLock::new();
2457pub fn is_batching() -> bool {
2459 IS_BATCHING.load(Ordering::Acquire)
2460}
2461pub fn is_rendering() -> bool {
2463 IS_RENDERING.load(Ordering::Acquire)
2464}
2465pub fn begin_render_phase() {
2467 IS_RENDERING.store(true, Ordering::Release);
2468}
2469pub fn end_render_phase() {
2471 IS_RENDERING.store(false, Ordering::Release);
2472}
2473pub fn enqueue_batch_task(task: Box<dyn FnOnce() + Send + Sync>) {
2475 let mut queue = BATCH_QUEUE
2476 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
2477 .lock()
2478 .unwrap();
2479 queue.push(task);
2480}
2481pub fn batch<F: FnOnce()>(f: F) {
2485 if IS_BATCHING.swap(true, Ordering::AcqRel) {
2486 f();
2488 return;
2489 }
2490 f();
2491 IS_BATCHING.store(false, Ordering::Release);
2492 let mut queue = BATCH_QUEUE
2493 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
2494 .lock()
2495 .unwrap();
2496 let tasks: Vec<_> = queue.drain(..).collect();
2497 drop(queue);
2498 for task in tasks {
2499 task();
2500 }
2501}
2502pub fn get_system_state() -> Arc<arc_swap::ArcSwap<KnowledgeState>> {
2504 SYSTEM_STATE
2505 .get_or_init(|| Arc::new(arc_swap::ArcSwap::from_pointee(KnowledgeState::default())))
2506 .clone()
2507}
2508pub fn load_system_state() -> arc_swap::Guard<Arc<KnowledgeState>> {
2509 get_system_state().load()
2510}
2511pub fn update_system_state<F>(f: F)
2512where
2513 F: Fn(&KnowledgeState) -> KnowledgeState,
2514{
2515 if is_rendering() {
2516 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
2517 }
2518 LAYOUT_DIRTY.store(true, Ordering::SeqCst);
2519 let swap = get_system_state();
2520 let current = swap.load();
2521 let new_state = Arc::new(f(¤t));
2522 swap.store(Arc::clone(&new_state));
2523 #[cfg(not(target_arch = "wasm32"))]
2524 {
2525 let tvar = KNOWLEDGE_TVAR
2526 .get_or_init(|| stm::TVar::new((*new_state).clone()));
2527 stm::atomically(|tx| tvar.write(tx, (*new_state).clone()));
2528 }
2529}
2530pub fn transact_system_state<F>(f: F)
2531where
2532 F: Fn(&KnowledgeState) -> KnowledgeState,
2533{
2534 #[cfg(not(target_arch = "wasm32"))]
2535 {
2536 if is_rendering() {
2537 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
2538 }
2539 let tvar = KNOWLEDGE_TVAR
2540 .get_or_init(|| {
2541 stm::TVar::new((**get_system_state().load()).clone())
2542 })
2543 .clone();
2544 let new_state = stm::atomically(move |tx| {
2545 let current = tvar.read(tx)?;
2546 let next = f(¤t);
2547 tvar.write(tx, next.clone())?;
2548 Ok(next)
2549 });
2550 get_system_state().store(Arc::new(new_state));
2551 }
2552 #[cfg(target_arch = "wasm32")]
2553 {
2554 if is_rendering() {
2555 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
2556 }
2557 update_system_state(f);
2558 }
2559}
2560impl KnowledgeState {
2561 pub fn new() -> Self {
2563 Self::default()
2564 }
2565 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
2567 self.component_states
2568 .insert(id, Arc::new(std::sync::RwLock::new(state)));
2569 }
2570pub fn get_component_state<T: 'static + Send + Sync>(
2572 &self,
2573 id: u64,
2574 ) -> Option<Arc<std::sync::RwLock<T>>> {
2575 let lock = self.component_states.get(&id)?;
2576 let _inner: &std::sync::RwLock<dyn std::any::Any + Send + Sync> = lock;
2578 None }
2582 pub fn remember(&mut self, fragment: KnowledgeFragment) {
2584 self.fragments.insert(fragment.id.clone(), fragment);
2585 }
2586 pub fn process_query(&mut self, query: &str) {
2588 let query_lower = query.to_lowercase();
2589 let mut results: Vec<(f32, String)> = self
2590 .fragments
2591 .iter()
2592 .map(|(id, frag)| {
2593 let mut score = 0.0;
2594 if frag.summary.to_lowercase().contains(&query_lower) {
2595 score += 1.0;
2596 }
2597 if frag.source.to_lowercase().contains(&query_lower) {
2598 score += 0.5;
2599 }
2600 (score, id.clone())
2601 })
2602 .filter(|(score, _)| *score > 0.0)
2603 .collect();
2604 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
2606 self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
2607 }
2608 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
2610 let mut snapshots = Vec::new();
2611 for frag in self.fragments.values() {
2613 if let Ok(val) = serde_json::to_value(frag) {
2614 snapshots.push(NodeStateSnapshot { id: 0, state: val });
2615 }
2616 }
2617 snapshots
2618 }
2619}
2620#[derive(Clone)]
2622pub struct Binding<T: Clone + Send + Sync + 'static> {
2623 swap: Arc<arc_swap::ArcSwap<T>>,
2624 #[cfg(not(target_arch = "wasm32"))]
2625 tvar: Arc<stm::TVar<T>>,
2626 version: Arc<std::sync::atomic::AtomicU64>,
2627}
2628impl<T: Clone + Send + Sync + 'static> Binding<T> {
2629 pub fn from_state(state: &State<T>) -> Self {
2631 Self {
2632 swap: Arc::clone(&state.swap),
2633 #[cfg(not(target_arch = "wasm32"))]
2634 tvar: Arc::clone(&state.tvar),
2635 version: Arc::clone(&state.version),
2636 }
2637 }
2638 pub fn get(&self) -> T {
2640 (**self.swap.load()).clone()
2641 }
2642 pub fn set(&self, value: T) {
2644 self.swap.store(Arc::new(value.clone()));
2645 #[cfg(not(target_arch = "wasm32"))]
2646 {
2647 let tvar = Arc::clone(&self.tvar);
2648 let v = value.clone();
2649 stm::atomically(move |tx| tvar.write(tx, v.clone()));
2650 }
2651 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2652 }
2653 pub fn version(&self) -> u64 {
2655 self.version.load(std::sync::atomic::Ordering::Acquire)
2656 }
2657}
2658#[cfg(not(target_arch = "wasm32"))]
2659pub fn transact_pair<A, B, F>(state_a: &State<A>, state_b: &State<B>, f: F)
2660where
2661 A: Clone + Send + Sync + 'static,
2662 B: Clone + Send + Sync + 'static,
2663 F: Fn(&A, &B) -> (A, B),
2664{
2665 let tvar_a = Arc::clone(&state_a.tvar);
2666 let tvar_b = Arc::clone(&state_b.tvar);
2667 let (new_a, new_b) = stm::atomically(move |tx| {
2668 let a = tvar_a.read(tx)?;
2669 let b = tvar_b.read(tx)?;
2670 let (na, nb) = f(&a, &b);
2671 tvar_a.write(tx, na.clone())?;
2672 tvar_b.write(tx, nb.clone())?;
2673 Ok((na, nb))
2674 });
2675 state_a.swap.store(Arc::new(new_a.clone()));
2676 state_b.swap.store(Arc::new(new_b.clone()));
2677 state_a.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2678 state_b.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2679 let subs_a = Arc::clone(&state_a.subscribers);
2680 let subs_b = Arc::clone(&state_b.subscribers);
2681 if crate::is_batching() {
2682 crate::enqueue_batch_task(Box::new(move || {
2683 {
2684 let s = subs_a.lock().unwrap();
2685 for cb in s.iter() { cb(&new_a); }
2686 }
2687 {
2688 let s = subs_b.lock().unwrap();
2689 for cb in s.iter() { cb(&new_b); }
2690 }
2691 }));
2692 } else {
2693 {
2694 let s = subs_a.lock().unwrap();
2695 for cb in s.iter() { cb(&new_a); }
2696 }
2697 {
2698 let s = subs_b.lock().unwrap();
2699 for cb in s.iter() { cb(&new_b); }
2700 }
2701 }
2702}
2703use std::any::TypeId;
2704use std::sync::Mutex;
2705pub(crate) static ENVIRONMENT: OnceLock<
2707 Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
2708> = OnceLock::new();
2709pub trait EnvKey: 'static + Send + Sync {
2713 type Value: Clone + Send + Sync + 'static;
2715 fn default_value() -> Self::Value;
2717}
2718pub struct YggdrasilKey;
2720impl EnvKey for YggdrasilKey {
2721 type Value = YggdrasilTokens;
2722 fn default_value() -> Self::Value {
2723 default_tokens()
2724 }
2725}
2726#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2729pub enum Appearance {
2730 Light,
2731 Dark,
2732}
2733#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2735pub enum Orientation {
2736 Horizontal,
2737 Vertical,
2738}
2739#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2741pub enum Alignment {
2742 #[default]
2743 Center,
2744 Leading,
2745 Trailing,
2746 Top,
2747 Bottom,
2748}
2749#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2751pub enum Distribution {
2752 #[default]
2753 Fill,
2754 Center,
2755 Leading,
2756 Trailing,
2757 SpaceBetween,
2758 SpaceAround,
2759 SpaceEvenly,
2760}
2761#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2763pub struct Color {
2764 pub r: f32,
2765 pub g: f32,
2766 pub b: f32,
2767 pub a: f32,
2768}
2769impl Color {
2770 pub const BLACK: Color = Color {
2771 r: 0.0,
2772 g: 0.0,
2773 b: 0.0,
2774 a: 1.0,
2775 };
2776 pub const WHITE: Color = Color {
2777 r: 1.0,
2778 g: 1.0,
2779 b: 1.0,
2780 a: 1.0,
2781 };
2782 pub const TRANSPARENT: Color = Color {
2783 r: 0.0,
2784 g: 0.0,
2785 b: 0.0,
2786 a: 0.0,
2787 };
2788 pub const RED: Color = Color {
2789 r: 1.0,
2790 g: 0.0,
2791 b: 0.0,
2792 a: 1.0,
2793 };
2794 pub const GREEN: Color = Color {
2795 r: 0.0,
2796 g: 1.0,
2797 b: 0.0,
2798 a: 1.0,
2799 };
2800 pub const BLUE: Color = Color {
2801 r: 0.0,
2802 g: 0.0,
2803 b: 1.0,
2804 a: 1.0,
2805 };
2806 pub const VIKING_GOLD: Color = Color {
2807 r: 1.0,
2808 g: 0.84,
2809 b: 0.0,
2810 a: 1.0,
2811 };
2812 pub const MAGENTA_LIQUID: Color = Color {
2813 r: 1.0,
2814 g: 0.0,
2815 b: 1.0,
2816 a: 1.0,
2817 };
2818 pub const TACTICAL_OBSIDIAN: Color = Color {
2819 r: 0.05,
2820 g: 0.05,
2821 b: 0.07,
2822 a: 1.0,
2823 };
2824 pub fn relative_luminance(&self) -> f32 {
2826 fn res(c: f32) -> f32 {
2827 if c <= 0.03928 {
2828 c / 12.92
2829 } else {
2830 ((c + 0.055) / 1.055).powf(2.4)
2831 }
2832 }
2833 0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
2834 }
2835 pub fn contrast_ratio(&self, other: &Color) -> f32 {
2837 let l1 = self.relative_luminance();
2838 let l2 = other.relative_luminance();
2839 if l1 > l2 {
2840 (l1 + 0.05) / (l2 + 0.05)
2841 } else {
2842 (l2 + 0.05) / (l1 + 0.05)
2843 }
2844 }
2845 pub const CYAN: Color = Color {
2846 r: 0.0,
2847 g: 1.0,
2848 b: 1.0,
2849 a: 1.0,
2850 };
2851 pub const YELLOW: Color = Color {
2852 r: 1.0,
2853 g: 1.0,
2854 b: 0.0,
2855 a: 1.0,
2856 };
2857 pub const MAGENTA: Color = Color {
2858 r: 1.0,
2859 g: 0.0,
2860 b: 1.0,
2861 a: 1.0,
2862 };
2863 pub const GRAY: Color = Color {
2864 r: 0.5,
2865 g: 0.5,
2866 b: 0.5,
2867 a: 1.0,
2868 };
2869 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
2871 Self { r, g, b, a }
2872 }
2873 pub fn as_array(&self) -> [f32; 4] {
2875 [self.r, self.g, self.b, self.a]
2876 }
2877}
2878impl View for Color {
2879 type Body = Never;
2880 fn body(self) -> Self::Body {
2881 unreachable!()
2882 }
2883 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
2884 renderer.fill_rect(rect, self.as_array());
2885 }
2886}
2887pub struct AppearanceKey;
2889impl EnvKey for AppearanceKey {
2890 type Value = Appearance;
2891 fn default_value() -> Self::Value {
2892 Appearance::Dark }
2894}
2895pub struct StyleResolver;
2897impl StyleResolver {
2898 pub fn color(key: &str) -> String {
2900 let tokens = Environment::<YggdrasilKey>::new().get();
2901 let appearance = Environment::<AppearanceKey>::new().get();
2902 let is_dark = appearance == Appearance::Dark;
2903 tokens
2904 .get_color(key, is_dark)
2905 .unwrap_or_else(|| "#FF00FF".to_string()) }
2907 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
2909 let tokens = Environment::<YggdrasilKey>::new().get();
2910 let appearance = Environment::<AppearanceKey>::new().get();
2911 let is_dark = appearance == Appearance::Dark;
2912 tokens.get(category, key, is_dark)
2913 }
2914}
2915pub fn default_tokens() -> YggdrasilTokens {
2917 let mut tokens = YggdrasilTokens::new();
2918 tokens.color.insert(
2920 "background".to_string(),
2921 TokenValue::Single {
2922 value: "#000000".to_string(), },
2924 );
2925 tokens.color.insert(
2926 "primary".to_string(),
2927 TokenValue::Single {
2928 value: "#00FFFF".to_string(), },
2930 );
2931 tokens.color.insert(
2932 "secondary".to_string(),
2933 TokenValue::Single {
2934 value: "#FF00FF".to_string(), },
2936 );
2937 tokens.color.insert(
2938 "surface".to_string(),
2939 TokenValue::Adaptive {
2940 light: "#FFFFFF".to_string(),
2941 dark: "#121212".to_string(),
2942 },
2943 );
2944 tokens.color.insert(
2945 "text".to_string(),
2946 TokenValue::Adaptive {
2947 light: "#000000".to_string(),
2948 dark: "#FFFFFF".to_string(),
2949 },
2950 );
2951 tokens.bifrost.insert(
2953 "blur".to_string(),
2954 TokenValue::Single {
2955 value: "25.0".to_string(),
2956 },
2957 );
2958 tokens.bifrost.insert(
2959 "saturation".to_string(),
2960 TokenValue::Single {
2961 value: "1.2".to_string(),
2962 },
2963 );
2964 tokens.bifrost.insert(
2965 "opacity".to_string(),
2966 TokenValue::Single {
2967 value: "0.65".to_string(),
2968 },
2969 );
2970 tokens.gungnir.insert(
2972 "intensity".to_string(),
2973 TokenValue::Single {
2974 value: "1.0".to_string(),
2975 },
2976 );
2977 tokens.gungnir.insert(
2978 "radius".to_string(),
2979 TokenValue::Single {
2980 value: "15.0".to_string(),
2981 },
2982 );
2983 tokens.mjolnir.insert(
2985 "clip_angle".to_string(),
2986 TokenValue::Single {
2987 value: "12.0".to_string(),
2988 },
2989 );
2990 tokens.mjolnir.insert(
2991 "border_width".to_string(),
2992 TokenValue::Single {
2993 value: "2.0".to_string(),
2994 },
2995 );
2996 tokens.anim.insert(
2998 "stiffness".to_string(),
2999 TokenValue::Single {
3000 value: "170.0".to_string(),
3001 },
3002 );
3003 tokens.anim.insert(
3004 "damping".to_string(),
3005 TokenValue::Single {
3006 value: "26.0".to_string(),
3007 },
3008 );
3009 tokens.anim.insert(
3010 "mass".to_string(),
3011 TokenValue::Single {
3012 value: "1.0".to_string(),
3013 },
3014 );
3015 tokens.accessibility.insert(
3017 "reduce_motion".to_string(),
3018 TokenValue::Single {
3019 value: "false".to_string(),
3020 },
3021 );
3022 tokens
3023}
3024pub struct Environment<K: EnvKey> {
3026 _marker: std::marker::PhantomData<K>,
3027}
3028impl<K: EnvKey> Default for Environment<K> {
3029 fn default() -> Self {
3030 Self::new()
3031 }
3032}
3033impl<K: EnvKey> Environment<K> {
3034 pub fn new() -> Self {
3036 Self {
3037 _marker: std::marker::PhantomData,
3038 }
3039 }
3040 pub fn get(&self) -> K::Value {
3042 if let Some(env_store) = ENVIRONMENT.get() {
3043 let env_lock = env_store.lock().unwrap();
3044 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
3045 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
3046 return typed_val.clone();
3047 } else {
3048 log::warn!("Environment: Downcast failed for key type {:?}", std::any::type_name::<K>());
3049 }
3050 } else {
3051 log::debug!("Environment: Key not found: {:?}. Returning default.", std::any::type_name::<K>());
3052 }
3053 } else {
3054 log::debug!("Environment: Store not initialized. Key: {:?}. Returning default.", std::any::type_name::<K>());
3055 }
3056 K::default_value()
3057 }
3058}
3059pub mod env {
3061 pub fn insert<K: super::EnvKey>(value: K::Value) {
3063 let store = super::ENVIRONMENT.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
3064 let mut env_map = store.lock().unwrap();
3065 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
3066 }
3067 pub fn remove<K: super::EnvKey>() {
3069 if let Some(store) = super::ENVIRONMENT.get() {
3070 let mut env_map = store.lock().unwrap();
3071 env_map.remove(&std::any::TypeId::of::<K>());
3072 }
3073 }
3074}
3075#[derive(Debug, Clone, Copy, PartialEq)]
3078pub struct Size {
3079 pub width: f32,
3080 pub height: f32,
3081}
3082
3083impl Size {
3084 pub const ZERO: Self = Self { width: 0.0, height: 0.0 };
3085
3086 pub fn new(width: f32, height: f32) -> Self {
3087 Self { width, height }
3088 }
3089}
3090
3091#[derive(Debug, Clone, Copy, PartialEq)]
3093pub struct EdgeInsets {
3094 pub top: f32,
3095 pub leading: f32,
3096 pub bottom: f32,
3097 pub trailing: f32,
3098}
3099
3100impl EdgeInsets {
3101 pub fn all(value: f32) -> Self {
3103 Self {
3104 top: value,
3105 leading: value,
3106 bottom: value,
3107 trailing: value,
3108 }
3109 }
3110
3111 pub fn vertical(value: f32) -> Self {
3113 Self {
3114 top: value,
3115 leading: 0.0,
3116 bottom: value,
3117 trailing: 0.0,
3118 }
3119 }
3120
3121 pub fn horizontal(value: f32) -> Self {
3123 Self {
3124 top: 0.0,
3125 leading: value,
3126 bottom: 0.0,
3127 trailing: value,
3128 }
3129 }
3130}
3131
3132#[derive(Debug, Clone, Copy, PartialEq)]
3134pub struct FrameModifier {
3135 pub width: Option<f32>,
3136 pub height: Option<f32>,
3137}
3138
3139impl Default for FrameModifier {
3140 fn default() -> Self {
3141 Self::new()
3142 }
3143}
3144
3145impl FrameModifier {
3146 pub fn new() -> Self {
3147 Self {
3148 width: None,
3149 height: None,
3150 }
3151 }
3152
3153 pub fn width(mut self, width: f32) -> Self {
3154 self.width = Some(width);
3155 self
3156 }
3157
3158 pub fn height(mut self, height: f32) -> Self {
3159 self.height = Some(height);
3160 self
3161 }
3162
3163 pub fn size(mut self, width: f32, height: f32) -> Self {
3164 self.width = Some(width);
3165 self.height = Some(height);
3166 self
3167 }
3168}
3169
3170impl ViewModifier for FrameModifier {
3171 fn modify<V: View>(self, content: V) -> impl View {
3172 ModifiedView::new(content, self)
3173 }
3174}
3175
3176#[derive(Debug, Clone, Copy, PartialEq)]
3178pub struct FlexModifier {
3179 pub weight: f32,
3180}
3181
3182impl ViewModifier for FlexModifier {
3183 fn modify<V: View>(self, content: V) -> impl View {
3184 ModifiedView::new(content, self)
3185 }
3186
3187 fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
3188 self.weight
3189 }
3190}
3191
3192#[derive(Debug, Clone, Copy, PartialEq)]
3194pub struct OffsetModifier {
3195 pub x: f32,
3196 pub y: f32,
3197}
3198
3199impl OffsetModifier {
3200 pub fn new(x: f32, y: f32) -> Self {
3201 Self { x, y }
3202 }
3203}
3204
3205impl ViewModifier for OffsetModifier {
3206 fn modify<V: View>(self, content: V) -> impl View {
3207 ModifiedView::new(content, self)
3208 }
3209}
3210
3211#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3213pub struct ZIndexModifier {
3214 pub z_index: i32,
3215}
3216
3217impl ZIndexModifier {
3218 pub fn new(z_index: i32) -> Self {
3219 Self { z_index }
3220 }
3221}
3222
3223impl ViewModifier for ZIndexModifier {
3224 fn modify<V: View>(self, content: V) -> impl View {
3225 ModifiedView::new(content, self)
3226 }
3227}
3228
3229#[derive(Debug, Clone, Copy, PartialEq, Default)]
3231pub struct LayoutConstraints {
3232 pub min_width: Option<f32>,
3233 pub max_width: Option<f32>,
3234 pub min_height: Option<f32>,
3235 pub max_height: Option<f32>,
3236}
3237
3238#[derive(Debug, Clone, Copy, PartialEq)]
3240pub struct LayoutModifier {
3241 pub constraints: LayoutConstraints,
3242}
3243
3244impl LayoutModifier {
3245 pub fn new(constraints: LayoutConstraints) -> Self {
3246 Self { constraints }
3247 }
3248}
3249
3250impl ViewModifier for LayoutModifier {
3251 fn modify<V: View>(self, content: V) -> impl View {
3252 ModifiedView::new(content, self)
3253 }
3254}
3255
3256#[derive(Debug, Clone, Copy, PartialEq)]
3258pub struct SafeAreaModifier {
3259 pub ignores: bool,
3260}
3261
3262impl ViewModifier for SafeAreaModifier {
3263 fn modify<V: View>(self, content: V) -> impl View {
3264 ModifiedView::new(content, self)
3265 }
3266}
3267
3268#[derive(Debug, Clone, Copy, PartialEq)]
3270pub struct ElevationModifier {
3271 pub level: f32,
3272}
3273
3274impl ViewModifier for ElevationModifier {
3275 fn modify<V: View>(self, content: V) -> impl View {
3276 ModifiedView::new(content, self)
3277 }
3278
3279 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
3280 if self.level > 0.0 {
3281 let radius = self.level * 2.0;
3282 let offset_y = self.level * 0.5;
3283 let shadow_color = [0.0, 0.0, 0.0, 0.3];
3284 renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
3285 view.render(renderer, rect);
3286 renderer.pop_shadow();
3287 } else {
3288 view.render(renderer, rect);
3289 }
3290 }
3291}
3292
3293pub mod layout {
3295 use super::*;
3296
3297 pub struct LayoutCache {
3299 pub safe_area: SafeArea,
3300 size_cache: HashMap<(u64, u32, u32), Size>, }
3302
3303 impl Default for LayoutCache {
3304 fn default() -> Self {
3305 Self::new()
3306 }
3307 }
3308
3309 impl LayoutCache {
3310 pub fn new() -> Self {
3311 Self {
3312 safe_area: SafeArea::default(),
3313 size_cache: HashMap::new(),
3314 }
3315 }
3316
3317 pub fn clear(&mut self) {
3318 self.safe_area = SafeArea::default();
3319 self.size_cache.clear();
3320 }
3321
3322 pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
3323 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
3324 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
3325 self.size_cache.get(&(view_hash, pw, ph)).copied()
3326 }
3327
3328 pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: Size) {
3329 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
3330 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
3331 self.size_cache.insert((view_hash, pw, ph), size);
3332 }
3333
3334 pub fn invalidate_view(&mut self, view_hash: u64) {
3336 self.size_cache.retain(|&(hash, _, _), _| hash != view_hash);
3337 }
3338 }
3339
3340 #[derive(Debug, Clone, Copy, PartialEq)]
3342 pub struct SizeProposal {
3343 pub width: Option<f32>,
3344 pub height: Option<f32>,
3345 }
3346
3347 impl SizeProposal {
3348 pub fn unspecified() -> Self {
3349 Self {
3350 width: None,
3351 height: None,
3352 }
3353 }
3354
3355 pub fn width(width: f32) -> Self {
3356 Self {
3357 width: Some(width),
3358 height: None,
3359 }
3360 }
3361
3362 pub fn height(height: f32) -> Self {
3363 Self {
3364 width: None,
3365 height: Some(height),
3366 }
3367 }
3368
3369 pub fn tight(width: f32, height: f32) -> Self {
3370 Self {
3371 width: Some(width),
3372 height: Some(height),
3373 }
3374 }
3375
3376 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
3377 Self { width, height }
3378 }
3379 }
3380
3381 pub trait LayoutView: Send {
3383 fn size_that_fits(
3385 &self,
3386 proposal: SizeProposal,
3387 subviews: &[&dyn LayoutView],
3388 cache: &mut LayoutCache,
3389 ) -> Size;
3390
3391 fn place_subviews(
3393 &self,
3394 bounds: Rect,
3395 subviews: &mut [&mut dyn LayoutView],
3396 cache: &mut LayoutCache,
3397 );
3398
3399 fn flex_weight(&self) -> f32 {
3401 0.0
3402 }
3403 }
3404 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
3406 pub struct EdgeInsets {
3407 pub top: f32,
3408 pub leading: f32,
3409 pub bottom: f32,
3410 pub trailing: f32,
3411 }
3412
3413 impl EdgeInsets {
3414 pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
3415 Self { top, leading, bottom, trailing }
3416 }
3417
3418 pub fn all(value: f32) -> Self {
3419 Self {
3420 top: value,
3421 leading: value,
3422 bottom: value,
3423 trailing: value,
3424 }
3425 }
3426 }
3427
3428 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
3430 pub struct SafeArea {
3431 pub insets: EdgeInsets,
3432 }
3433
3434 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
3436 pub struct Rect {
3437 pub x: f32,
3438 pub y: f32,
3439 pub width: f32,
3440 pub height: f32,
3441 }
3442
3443 impl Rect {
3444 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
3445 Self {
3446 x,
3447 y,
3448 width,
3449 height,
3450 }
3451 }
3452
3453 pub fn inset(&self, amount: f32) -> Self {
3454 Self {
3455 x: self.x + amount,
3456 y: self.y + amount,
3457 width: (self.width - amount * 2.0).max(0.0),
3458 height: (self.height - amount * 2.0).max(0.0),
3459 }
3460 }
3461
3462 pub fn offset(&self, dx: f32, dy: f32) -> Self {
3463 Self {
3464 x: self.x + dx,
3465 y: self.y + dy,
3466 ..*self
3467 }
3468 }
3469
3470 pub fn zero() -> Self {
3471 Self {
3472 x: 0.0,
3473 y: 0.0,
3474 width: 0.0,
3475 height: 0.0,
3476 }
3477 }
3478
3479 pub fn contains(&self, x: f32, y: f32) -> bool {
3480 x >= self.x && x <= self.x + self.width && y >= self.y && y <= self.y + self.height
3481 }
3482
3483 pub fn size(&self) -> Size {
3484 Size {
3485 width: self.width,
3486 height: self.height,
3487 }
3488 }
3489
3490 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
3492 if n == 0 {
3493 return vec![];
3494 }
3495 let item_width = self.width / n as f32;
3496 (0..n)
3497 .map(|i| Rect {
3498 x: self.x + i as f32 * item_width,
3499 y: self.y,
3500 width: item_width,
3501 height: self.height,
3502 })
3503 .collect()
3504 }
3505
3506 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
3508 if n == 0 {
3509 return vec![];
3510 }
3511 let item_height = self.height / n as f32;
3512 (0..n)
3513 .map(|i| Rect {
3514 x: self.x,
3515 y: self.y + i as f32 * item_height,
3516 width: self.width,
3517 height: item_height,
3518 })
3519 .collect()
3520 }
3521 }
3522}
3523
3524pub use layout::{LayoutCache, LayoutView, Rect, SizeProposal};
3526pub mod runtime;
3529pub mod scene_graph;
3530pub mod agents;
3531pub mod material;
3532
3533
3534pub use scene_graph::{NodeId, bifrost_registry};
3535
3536pub trait AssetManager: Send + Sync {
3540 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
3542
3543 fn preload_image(&self, url: &str);
3545}
3546
3547#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
3549pub enum Event {
3550 PointerDown { x: f32, y: f32, button: u32 },
3551 PointerUp { x: f32, y: f32, button: u32 },
3552 PointerMove { x: f32, y: f32 },
3553 PointerClick { x: f32, y: f32, button: u32 },
3554 PointerEnter,
3555 PointerLeave,
3556 KeyDown { key: String },
3557 KeyUp { key: String },
3558 Ime(String),
3560}
3561
3562impl Event {
3563 pub fn name(&self) -> &'static str {
3565 match self {
3566 Self::PointerDown { .. } => "pointerdown",
3567 Self::PointerUp { .. } => "pointerup",
3568 Self::PointerMove { .. } => "pointermove",
3569 Self::PointerClick { .. } => "pointerclick",
3570 Self::PointerEnter => "pointerenter",
3571 Self::PointerLeave => "pointerleave",
3572 Self::KeyDown { .. } => "keydown",
3573 Self::KeyUp { .. } => "keyup",
3574 Self::Ime(_) => "ime",
3575 }
3576 }
3577}
3578
3579#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3581pub enum EventResponse {
3582 Handled,
3583 Ignored,
3584}
3585
3586pub struct DefaultAssetManager {
3588 cache: AssetCache,
3589}
3590type AssetCache = Arc<arc_swap::ArcSwap<HashMap<String, AssetState<Arc<Vec<u8>>>>>>;
3591
3592impl Default for DefaultAssetManager {
3593 fn default() -> Self {
3594 Self::new()
3595 }
3596}
3597
3598impl DefaultAssetManager {
3599 pub fn new() -> Self {
3600 Self {
3601 cache: Arc::new(arc_swap::ArcSwap::from_pointee(HashMap::new())),
3602 }
3603 }
3604}
3605
3606impl AssetManager for DefaultAssetManager {
3607 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
3608 if let Some(state) = self.cache.load().get(url) {
3609 return state.clone();
3610 }
3611
3612 self.cache.rcu(|map| {
3613 let mut m = (**map).clone();
3614 m.entry(url.to_string()).or_insert(AssetState::Loading);
3615 m
3616 });
3617 AssetState::Loading
3618 }
3619
3620 fn preload_image(&self, _url: &str) {}
3621}
3622
3623use std::future::Future;
3624
3625pub struct Suspense<T: Clone + Send + Sync + 'static> {
3628 inner: State<AssetState<T>>,
3629}
3630
3631impl<T: Clone + Send + Sync + 'static> Default for Suspense<T> {
3632 fn default() -> Self {
3633 Self::new()
3634 }
3635}
3636
3637impl<T: Clone + Send + Sync + 'static> Suspense<T> {
3638 pub fn new() -> Self {
3639 Self {
3640 inner: State::new(AssetState::Loading),
3641 }
3642 }
3643
3644 pub fn new_async<F>(future: F) -> Self
3645 where
3646 F: Future<Output = Result<T, String>> + Send + 'static,
3647 {
3648 let suspense = Self::new();
3649 let suspense_clone = suspense.clone();
3650
3651 #[cfg(not(target_arch = "wasm32"))]
3652 {
3653 if let Ok(handle) = tokio::runtime::Handle::try_current() {
3655 handle.spawn(async move {
3656 let result = future.await;
3657 match result {
3658 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3659 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3660 }
3661 });
3662 } else {
3663 std::thread::spawn(move || {
3664 let rt = tokio::runtime::Builder::new_current_thread()
3665 .enable_all()
3666 .build()
3667 .unwrap();
3668 rt.block_on(async {
3669 let result = future.await;
3670 match result {
3671 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3672 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3673 }
3674 });
3675 });
3676 }
3677 }
3678 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
3679 {
3680 wasm_bindgen_futures::spawn_local(async move {
3681 let result = future.await;
3682 match result {
3683 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3684 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3685 }
3686 });
3687 }
3688
3689 suspense
3690 }
3691
3692 pub fn ready(value: T) -> Self {
3693 Self {
3694 inner: State::new(AssetState::Ready(value)),
3695 }
3696 }
3697
3698 pub fn error(message: impl Into<String>) -> Self {
3699 Self {
3700 inner: State::new(AssetState::Error(message.into())),
3701 }
3702 }
3703
3704 pub fn get(&self) -> AssetState<T> {
3705 self.inner.get()
3706 }
3707
3708 pub fn get_ref(&self) -> AssetState<T> {
3709 self.inner.get()
3710 }
3711
3712 pub fn is_loading(&self) -> bool {
3713 matches!(self.get(), AssetState::Loading)
3714 }
3715
3716 pub fn is_ready(&self) -> bool {
3717 matches!(self.get(), AssetState::Ready(_))
3718 }
3719
3720 pub fn is_error(&self) -> bool {
3721 matches!(self.get(), AssetState::Error(_))
3722 }
3723
3724 pub fn ready_value(&self) -> Option<T> {
3725 match self.get() {
3726 AssetState::Ready(value) => Some(value),
3727 _ => None,
3728 }
3729 }
3730
3731 pub fn error_message(&self) -> Option<String> {
3732 match self.get() {
3733 AssetState::Error(message) => Some(message),
3734 _ => None,
3735 }
3736 }
3737
3738 pub fn subscribe<F: Fn(&AssetState<T>) + Send + Sync + 'static>(&self, callback: F) {
3739 self.inner.subscribe(callback)
3740 }
3741
3742 pub fn inner_state(&self) -> &State<AssetState<T>> {
3743 &self.inner
3744 }
3745}
3746
3747impl<T: Clone + Send + Sync + 'static> Clone for Suspense<T> {
3748 fn clone(&self) -> Self {
3749 Self {
3750 inner: self.inner.clone(),
3751 }
3752 }
3753}
3754
3755impl<T: Clone + Send + Sync + 'static> From<T> for Suspense<T> {
3756 fn from(value: T) -> Self {
3757 Self::ready(value)
3758 }
3759}
3760
3761impl<T: Clone + Send + Sync + 'static> From<Result<T, String>> for Suspense<T> {
3762 fn from(result: Result<T, String>) -> Self {
3763 match result {
3764 Ok(value) => Self::ready(value),
3765 Err(error) => Self::error(error),
3766 }
3767 }
3768}
3769
3770#[cfg(test)]
3771mod phase1_test;
3772
3773#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3775pub enum BerserkerMode {
3776 Normal,
3777 Rage, Frenzy, GodMode, }
3781
3782pub trait Seer: Send + Sync {
3785 fn predict(&self, context: &str) -> String;
3787 fn whispers(&self) -> Vec<String>;
3789}