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 {
105 *v = (*v * decay_factor).max(1.0);
106 }
107 }
108 }
109
110 pub fn reinforce(&mut self, node_ids: &[String], boost: f32) {
112 for node in &mut self.nodes {
113 if node_ids.contains(&node.id) {
114 node.weight += boost;
115 }
116 }
117 }
118
119 pub fn update_pointer(&mut self, new_pos: [f32; 2]) {
121 self.pointer_velocity = [
122 new_pos[0] - self.last_pointer_pos[0],
123 new_pos[1] - self.last_pointer_pos[1],
124 ];
125 self.last_pointer_pos = new_pos;
126 }
127}
128pub type KnowledgeId = String;
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct KnowledgeFragment {
135 pub id: String,
137 pub summary: String,
139 pub source: String,
141 pub created_at: u64,
143 pub accessed_count: u32,
145 pub content: Option<String>,
147}
148
149impl KnowledgeFragment {
150 pub fn new(id: String, summary: String, source: String) -> Self {
151 Self {
152 id,
153 summary,
154 source,
155 created_at: 0,
156 accessed_count: 0,
157 content: None,
158 }
159 }
160}
161
162#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
164pub enum MemoryLayer {
165 Episodic,
167 Semantic,
169 Procedural,
171}
172
173#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Default)]
177pub enum Realm {
178 Midgard,
179 #[default]
180 Asgard,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct TemporalNode {
186 pub id: String,
188 pub fragment_id: KnowledgeId,
190 pub timestamp: u64,
192 pub layer: MemoryLayer,
194 pub weight: f32,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct TemporalEdge {
201 pub source: String,
203 pub target: String,
205 pub relation: String,
207 pub weight: f32,
209}
210
211#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
212pub struct AssetKey(pub String);
213
214impl EnvKey for AssetKey {
215 type Value = Arc<dyn AssetManager>;
216 fn default_value() -> Self::Value {
217 Arc::new(DefaultAssetManager::new())
218 }
219}
220
221#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
223pub enum AssetState<T> {
224 Loading,
225 Ready(T),
226 Error(String),
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
231#[serde(untagged)]
232pub enum TokenValue {
233 Single { value: String },
235 Adaptive { light: String, dark: String },
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct YggdrasilTokens {
242 pub color: HashMap<String, TokenValue>,
243 pub font: HashMap<String, TokenValue>,
244 pub spacing: HashMap<String, TokenValue>,
245 pub radius: HashMap<String, TokenValue>,
246 pub shadow: HashMap<String, TokenValue>,
247 pub border: HashMap<String, TokenValue>,
248 pub anim: HashMap<String, TokenValue>,
249 pub bifrost: HashMap<String, TokenValue>,
250 pub gungnir: HashMap<String, TokenValue>,
251 pub mjolnir: HashMap<String, TokenValue>,
252 pub accessibility: HashMap<String, TokenValue>,
253}
254
255impl Default for YggdrasilTokens {
256 fn default() -> Self {
257 Self::new()
258 }
259}
260
261impl YggdrasilTokens {
262 pub fn new() -> Self {
263 Self {
264 color: HashMap::new(),
265 font: HashMap::new(),
266 spacing: HashMap::new(),
267 radius: HashMap::new(),
268 shadow: HashMap::new(),
269 border: HashMap::new(),
270 anim: HashMap::new(),
271 bifrost: HashMap::new(),
272 gungnir: HashMap::new(),
273 mjolnir: HashMap::new(),
274 accessibility: HashMap::new(),
275 }
276 }
277
278 pub fn get_color(&self, key: &str, is_dark: bool) -> Option<String> {
280 self.color.get(key).map(|token| match token {
281 TokenValue::Single { value } => value.clone(),
282 TokenValue::Adaptive { light, dark } => {
283 if is_dark {
284 dark.clone()
285 } else {
286 light.clone()
287 }
288 }
289 })
290 }
291
292 pub fn get<T: FromStr>(&self, category: &str, key: &str, is_dark: bool) -> Option<T> {
294 let map = match category {
295 "color" => &self.color,
296 "font" => &self.font,
297 "spacing" => &self.spacing,
298 "radius" => &self.radius,
299 "shadow" => &self.shadow,
300 "border" => &self.border,
301 "anim" => &self.anim,
302 "bifrost" => &self.bifrost,
303 "gungnir" => &self.gungnir,
304 "mjolnir" => &self.mjolnir,
305 "accessibility" => &self.accessibility,
306 _ => return None,
307 };
308
309 map.get(key).and_then(|token| match token {
310 TokenValue::Single { value } => value.parse().ok(),
311 TokenValue::Adaptive { light, dark } => {
312 let value = if is_dark { dark } else { light };
313 value.parse().ok()
314 }
315 })
316 }
317}
318
319pub trait View: Sized + Send {
320 type Body: View;
323
324 fn body(self) -> Self::Body;
325
326 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
329
330 fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
333 Size::ZERO
334 }
335
336 fn layout(&self) -> Option<&dyn layout::LayoutView> {
338 None
339 }
340
341 fn flex_weight(&self) -> f32 {
343 0.0
344 }
345
346 fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
348 ModifiedView::new(self, m)
349 }
350
351 fn bifrost(
353 self,
354 blur: f32,
355 saturation: f32,
356 opacity: f32,
357 ) -> ModifiedView<Self, BifrostModifier> {
358 self.modifier(BifrostModifier {
359 blur,
360 saturation,
361 opacity,
362 })
363 }
364
365 fn gungnir(
367 self,
368 color: impl Into<String>,
369 radius: f32,
370 intensity: f32,
371 ) -> ModifiedView<Self, GungnirModifier> {
372 self.modifier(GungnirModifier {
373 color: color.into(),
374 radius,
375 intensity,
376 })
377 }
378
379 fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
381 self.modifier(MjolnirSliceModifier { angle, offset })
382 }
383
384 fn mjolnir_shatter(
386 self,
387 pieces: u32,
388 force: f32,
389 ) -> ModifiedView<Self, MjolnirShatterModifier> {
390 self.modifier(MjolnirShatterModifier { pieces, force })
391 }
392
393 fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
395 self.modifier(BifrostBridgeModifier { id: id.into() })
396 }
397
398 fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
400 self.modifier(BackgroundModifier { color })
401 }
402
403 fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
405 self.modifier(PaddingModifier { amount })
406 }
407
408 fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
410 self.modifier(OpacityModifier {
411 opacity: opacity.clamp(0.0, 1.0),
412 })
413 }
414
415 fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
417 self.modifier(ForegroundColorModifier { color })
418 }
419
420 fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
422 self.modifier(FrameModifier { width, height })
423 }
424
425 fn flex(self, weight: f32) -> ModifiedView<Self, FlexModifier> {
427 self.modifier(FlexModifier { weight })
428 }
429
430 fn safe_area_padding(self) -> ModifiedView<Self, SafeAreaModifier> {
432 self.modifier(SafeAreaModifier { ignores: false })
433 }
434
435 fn ignores_safe_area(self) -> ModifiedView<Self, SafeAreaModifier> {
437 self.modifier(SafeAreaModifier { ignores: true })
438 }
439
440 fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
442 self.modifier(ClipModifier)
443 }
444
445 fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
447 self.modifier(BorderModifier { color, width })
448 }
449
450 fn elevation(self, level: f32) -> ModifiedView<Self, ElevationModifier> {
452 self.modifier(ElevationModifier { level })
453 }
454
455 fn magnetic(self, radius: f32, intensity: f32) -> ModifiedView<Self, MagneticModifier> {
457 self.modifier(MagneticModifier { radius, intensity })
458 }
459
460 fn mani_glow(self, color: [f32; 4], radius: f32) -> ModifiedView<Self, ManiGlowModifier> {
462 self.modifier(ManiGlowModifier { color, radius })
463 }
464
465 fn memory_layer(self, layer: MemoryLayer) -> ModifiedView<Self, BifrostLayerModifier> {
467 self.modifier(BifrostLayerModifier { layer })
468 }
469
470 fn fafnir_evolve(self, id: u64) -> ModifiedView<Self, FafnirModifier> {
472 self.modifier(FafnirModifier { id })
473 }
474
475 fn mimir_intent(self) -> ModifiedView<Self, MimirIntentModifier> {
477 self.modifier(MimirIntentModifier)
478 }
479
480 fn kvasir_vibes(self, complexity: f32) -> ModifiedView<Self, KvasirVibeModifier> {
482 self.modifier(KvasirVibeModifier { complexity })
483 }
484
485 fn odins_eye(self) -> ModifiedView<Self, OdinsEyeModifier> {
487 self.modifier(OdinsEyeModifier)
488 }
489
490 fn on_appear<F: Fn() + Send + Sync + 'static>(
492 self,
493 action: F,
494 ) -> ModifiedView<Self, LifecycleModifier> {
495 self.modifier(LifecycleModifier {
496 on_appear: Some(Arc::new(action)),
497 on_disappear: None,
498 })
499 }
500
501 fn on_disappear<F: Fn() + Send + Sync + 'static>(
503 self,
504 action: F,
505 ) -> ModifiedView<Self, LifecycleModifier> {
506 self.modifier(LifecycleModifier {
507 on_appear: None,
508 on_disappear: Some(Arc::new(action)),
509 })
510 }
511
512 fn on_click<F: Fn() + Send + Sync + 'static>(
514 self,
515 action: F,
516 ) -> ModifiedView<Self, OnClickModifier> {
517 self.modifier(OnClickModifier {
518 action: Arc::new(action),
519 })
520 }
521
522 fn on_pointer_enter<F: Fn() + Send + Sync + 'static>(
524 self,
525 action: F,
526 ) -> ModifiedView<Self, OnPointerEnterModifier> {
527 self.modifier(OnPointerEnterModifier {
528 action: Arc::new(action),
529 })
530 }
531
532 fn on_pointer_leave<F: Fn() + Send + Sync + 'static>(
534 self,
535 action: F,
536 ) -> ModifiedView<Self, OnPointerLeaveModifier> {
537 self.modifier(OnPointerLeaveModifier {
538 action: Arc::new(action),
539 })
540 }
541
542 fn on_pointer_move<F: Fn(f32, f32) + Send + Sync + 'static>(
544 self,
545 action: F,
546 ) -> ModifiedView<Self, OnPointerMoveModifier> {
547 self.modifier(OnPointerMoveModifier {
548 action: Arc::new(action),
549 })
550 }
551
552 fn on_pointer_down<F: Fn() + Send + Sync + 'static>(
554 self,
555 action: F,
556 ) -> ModifiedView<Self, OnPointerDownModifier> {
557 self.modifier(OnPointerDownModifier {
558 action: Arc::new(action),
559 })
560 }
561
562 fn on_pointer_up<F: Fn() + Send + Sync + 'static>(
564 self,
565 action: F,
566 ) -> ModifiedView<Self, OnPointerUpModifier> {
567 self.modifier(OnPointerUpModifier {
568 action: Arc::new(action),
569 })
570 }
571
572 fn erase(self) -> AnyView
574 where
575 Self: Clone + 'static,
576 {
577 AnyView::new(self)
578 }
579}
580
581pub trait ErasedView: Send {
583 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect);
584 fn name(&self) -> &'static str;
585 fn flex_weight_erased(&self) -> f32;
586 fn layout_erased(&self) -> Option<&dyn layout::LayoutView>;
587 fn clone_box(&self) -> Box<dyn ErasedView>;
588}
589
590impl<V: View + Clone + 'static> ErasedView for V {
591 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
592 self.render(renderer, rect);
593 }
594
595 fn name(&self) -> &'static str {
596 std::any::type_name::<V>()
597 }
598
599 fn flex_weight_erased(&self) -> f32 {
600 self.flex_weight()
601 }
602
603 fn layout_erased(&self) -> Option<&dyn layout::LayoutView> {
604 self.layout()
605 }
606
607 fn clone_box(&self) -> Box<dyn ErasedView> {
608 Box::new(self.clone())
609 }
610}
611
612pub struct MemoView<V, F> {
615 id: u64,
616 data_hash: u64,
617 builder: F,
618 _v: std::marker::PhantomData<V>,
619}
620
621impl<V: View, F: Fn() -> V + Send + Sync> MemoView<V, F> {
622 pub fn new(id: u64, data_hash: u64, builder: F) -> Self {
624 Self {
625 id,
626 data_hash,
627 builder,
628 _v: std::marker::PhantomData,
629 }
630 }
631}
632
633impl<V: View + 'static, F: Fn() -> V + Send + Sync + 'static> View for MemoView<V, F> {
634 type Body = Never;
635 fn body(self) -> Self::Body {
636 unreachable!("MemoView does not have a body")
637 }
638
639 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
640 renderer.memoize(self.id, self.data_hash, &|r| {
641 let view = (self.builder)();
642 view.render(r, rect);
643 });
644 }
645}
646
647pub struct AnyView {
649 inner: Box<dyn ErasedView>,
650}
651
652impl Clone for AnyView {
653 fn clone(&self) -> Self {
654 Self {
655 inner: self.inner.clone_box(),
656 }
657 }
658}
659
660impl AnyView {
661 pub fn new<V: View + Clone + 'static>(view: V) -> Self {
662 Self {
663 inner: Box::new(view),
664 }
665 }
666}
667
668impl View for AnyView {
669 type Body = Never;
670 fn body(self) -> Self::Body {
671 unreachable!()
672 }
673
674 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
675 renderer.push_vnode(rect, self.inner.name());
676 self.inner.render_erased(renderer, rect);
677 renderer.pop_vnode();
678 }
679
680 fn flex_weight(&self) -> f32 {
681 self.inner.flex_weight_erased()
682 }
683
684 fn layout(&self) -> Option<&dyn layout::LayoutView> {
685 self.inner.layout_erased()
686 }
687}
688
689#[derive(Debug, Clone, PartialEq)]
693pub struct BifrostBridgeModifier {
694 pub id: String,
695}
696
697impl ViewModifier for BifrostBridgeModifier {
698 fn modify<V: View>(self, content: V) -> impl View {
699 ModifiedView::new(content, self)
700 }
701
702 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
703 renderer.register_shared_element(&self.id, rect);
705 }
706}
707
708#[derive(Debug, Clone, Copy, PartialEq)]
711pub struct MjolnirSliceModifier {
712 pub angle: f32,
713 pub offset: f32,
714}
715
716impl ViewModifier for MjolnirSliceModifier {
717 fn modify<V: View>(self, content: V) -> impl View {
718 ModifiedView::new(content, self)
719 }
720
721 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
722 renderer.push_mjolnir_slice(self.angle, self.offset);
723 }
724
725 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
726 renderer.pop_mjolnir_slice();
727 }
728}
729
730#[derive(Debug, Clone, Copy, PartialEq)]
733pub struct MjolnirShatterModifier {
734 pub pieces: u32,
735 pub force: f32,
736}
737
738impl ViewModifier for MjolnirShatterModifier {
739 fn modify<V: View>(self, content: V) -> impl View {
740 ModifiedView::new(content, self)
741 }
742
743 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
744 let pieces = self.pieces.max(1);
746 for i in 0..pieces {
747 let progress = i as f32 / pieces as f32;
748 let next_progress = (i + 1) as f32 / pieces as f32;
749
750 let angle_start = progress * 360.0;
751 let angle_end = next_progress * 360.0;
752
753 renderer.push_mjolnir_slice(angle_start, 0.0);
755 renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
756
757 let mid_angle = (angle_start + angle_end) / 2.0;
759 let rad = mid_angle.to_radians();
760 let dx = rad.cos() * self.force;
761 let dy = rad.sin() * self.force;
762
763 let shard_rect = Rect {
764 x: rect.x + dx,
765 y: rect.y + dy,
766 ..rect
767 };
768
769 view.render(renderer, shard_rect);
770
771 renderer.pop_mjolnir_slice();
772 renderer.pop_mjolnir_slice();
773 }
774 }
775}
776
777#[derive(Debug, Clone, Copy, PartialEq)]
780pub struct BifrostModifier {
781 pub blur: f32,
782 pub saturation: f32,
783 pub opacity: f32,
784}
785
786impl ViewModifier for BifrostModifier {
787 fn modify<V: View>(self, content: V) -> impl View {
788 ModifiedView::new(content, self)
789 }
790
791 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
792 if renderer.is_over_budget() {
793 renderer.bifrost(rect, self.blur * 0.5, self.saturation, self.opacity);
795 } else {
796 renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
797 }
798 }
799}
800
801#[derive(Debug, Clone, Copy, PartialEq)]
803pub struct BackgroundModifier {
804 pub color: [f32; 4],
805}
806
807impl ViewModifier for BackgroundModifier {
808 fn modify<V: View>(self, content: V) -> impl View {
809 ModifiedView::new(content, self)
810 }
811
812 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
813 renderer.fill_rect(rect, self.color);
814 }
815}
816
817#[derive(Debug, Clone, Copy, PartialEq)]
819pub struct PaddingModifier {
820 pub amount: f32,
821}
822
823impl ViewModifier for PaddingModifier {
824 fn modify<V: View>(self, content: V) -> impl View {
825 ModifiedView::new(content, self)
826 }
827
828 fn transform_rect(&self, rect: Rect) -> Rect {
829 Rect {
830 x: rect.x + self.amount,
831 y: rect.y + self.amount,
832 width: (rect.width - 2.0 * self.amount).max(0.0),
833 height: (rect.height - 2.0 * self.amount).max(0.0),
834 }
835 }
836
837 fn transform_proposal(&self, mut proposal: SizeProposal) -> SizeProposal {
838 if let Some(w) = proposal.width {
839 proposal.width = Some((w - 2.0 * self.amount).max(0.0));
840 }
841 if let Some(h) = proposal.height {
842 proposal.height = Some((h - 2.0 * self.amount).max(0.0));
843 }
844 proposal
845 }
846
847 fn transform_size(&self, mut size: Size) -> Size {
848 size.width += 2.0 * self.amount;
849 size.height += 2.0 * self.amount;
850 size
851 }
852}
853
854#[derive(Debug, Clone, PartialEq)]
857pub struct GungnirModifier {
858 pub color: String,
859 pub radius: f32,
860 pub intensity: f32,
861}
862
863impl ViewModifier for GungnirModifier {
864 fn modify<V: View>(self, content: V) -> impl View {
865 ModifiedView::new(content, self)
866 }
867
868 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
869 renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
871 }
872}
873
874#[derive(Debug, Clone, Copy, PartialEq)]
876pub struct GungnirPulseModifier {
877 pub color: [f32; 4],
878 pub radius: f32,
879 pub speed: f32,
880}
881
882impl ViewModifier for GungnirPulseModifier {
883 fn modify<V: View>(self, content: V) -> impl View {
884 ModifiedView::new(content, self)
885 }
886
887 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
888 let time = std::time::SystemTime::now()
889 .duration_since(std::time::UNIX_EPOCH)
890 .unwrap_or_default()
891 .as_secs_f32();
892
893 let intensity = (time * self.speed).sin() * 0.5 + 0.5;
896 let mut color = self.color;
897 color[3] *= intensity;
898
899 renderer.stroke_rect(rect, color, self.radius);
901 }
902}
903
904#[derive(Debug, Clone, Copy, PartialEq)]
906pub struct MagneticModifier {
907 pub radius: f32,
908 pub intensity: f32,
909}
910
911impl ViewModifier for MagneticModifier {
912 fn modify<V: View>(self, content: V) -> impl View {
913 ModifiedView::new(content, self)
914 }
915
916 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
917 let [px, py] = renderer.get_pointer_position();
918 let center_x = rect.x + rect.width / 2.0;
919 let center_y = rect.y + rect.height / 2.0;
920
921 let dx = px - center_x;
922 let dy = py - center_y;
923 let dist = (dx * dx + dy * dy).sqrt();
924
925 let mut offset_x = 0.0;
926 let mut offset_y = 0.0;
927
928 if dist < self.radius && dist > 0.0 {
929 let force = (1.0 - dist / self.radius) * self.intensity;
930 offset_x = dx * force;
931 offset_y = dy * force;
932 }
933
934 let magnetic_rect = Rect {
935 x: rect.x + offset_x,
936 y: rect.y + offset_y,
937 ..rect
938 };
939
940 view.render(renderer, magnetic_rect);
941 }
942}
943
944#[derive(Debug, Clone, Copy, PartialEq)]
947pub struct ManiGlowModifier {
948 pub color: [f32; 4],
949 pub radius: f32,
950}
951
952impl ViewModifier for ManiGlowModifier {
953 fn modify<V: View>(self, content: V) -> impl View {
954 ModifiedView::new(content, self)
955 }
956
957 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
958 if crate::load_system_state().realm == Realm::Asgard {
959 renderer.mani_glow(rect, self.color, self.radius);
960 }
961 view.render(renderer, rect);
962 }
963}
964
965#[derive(Debug, Clone, Copy, PartialEq)]
970pub struct BifrostLayerModifier {
971 pub layer: MemoryLayer,
972}
973
974impl ViewModifier for BifrostLayerModifier {
975 fn modify<V: View>(self, content: V) -> impl View {
976 ModifiedView::new(content, self)
977 }
978
979 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
980 let realm = crate::load_system_state().realm;
981 match self.layer {
982 MemoryLayer::Episodic => {
983 if realm == Realm::Asgard {
984 renderer.bifrost(rect, 40.0, 1.2, 0.7);
985 } else {
986 renderer.fill_rect(rect, [0.1, 0.12, 0.15, 0.8]);
987 }
988 }
989 MemoryLayer::Semantic => {
990 if realm == Realm::Asgard {
991 renderer.gungnir(rect, [1.0, 0.84, 0.0, 1.0], 15.0, 0.6);
992 } else {
993 renderer.stroke_rect(rect, [0.4, 0.4, 0.4, 1.0], 1.5);
994 }
995 }
996 MemoryLayer::Procedural => {
997 renderer.fill_rect(rect, [0.05, 0.05, 0.07, 0.95]);
998 let stroke_color = if realm == Realm::Asgard {
999 [0.3, 0.3, 0.3, 1.0]
1000 } else {
1001 [0.2, 0.2, 0.2, 1.0]
1002 };
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
1027 .get_component_state::<f32>(self.id)
1028 .map(|v| *v.read().unwrap())
1029 .unwrap_or(1.0);
1030
1031 let growth = (vitality - 1.0).clamp(0.0, 4.0);
1034 let scale = 1.0 + growth * 0.12;
1035 let glow_intensity = growth * 0.25;
1036
1037 let id = self.id;
1039 renderer.register_handler(
1040 "pointermove",
1041 std::sync::Arc::new(move |_| {
1042 crate::update_system_state(|s| {
1043 let mut s = s.clone();
1044 let v = s
1045 .get_component_state::<f32>(id)
1046 .map(|v| *v.read().unwrap())
1047 .unwrap_or(1.0);
1048 s.set_component_state(id, (v + 0.05).min(5.0)); s
1050 });
1051 }),
1052 );
1053
1054 if scale > 1.01 {
1055 renderer.push_transform([0.0, 0.0], [scale, scale], 0.0);
1056 }
1057
1058 if glow_intensity > 0.1 && state.realm == Realm::Asgard {
1059 renderer.gungnir(rect, [1.0, 0.84, 0.0, 1.0], 15.0 * vitality, glow_intensity);
1060 }
1061
1062 view.render(renderer, rect);
1063
1064 if scale > 1.01 {
1065 renderer.pop_transform();
1066 }
1067 }
1068}
1069
1070#[derive(Debug, Clone, Copy, PartialEq)]
1072pub struct MimirIntentModifier;
1073
1074impl ViewModifier for MimirIntentModifier {
1075 fn modify<V: View>(self, content: V) -> impl View {
1076 ModifiedView::new(content, self)
1077 }
1078
1079 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1080 let state = crate::load_system_state();
1081 let pos = state.last_pointer_pos;
1082 let vel = state.pointer_velocity;
1083
1084 let center = [rect.x + rect.width / 2.0, rect.y + rect.height / 2.0];
1086 let dx = center[0] - pos[0];
1087 let dy = center[1] - pos[1];
1088
1089 let dot = vel[0] * dx + vel[1] * dy;
1091 let speed_sq = vel[0] * vel[0] + vel[1] * vel[1];
1092 let dist_sq = dx * dx + dy * dy;
1093
1094 if dot > 0.0 && dist_sq < 250.0 * 250.0 && speed_sq > 0.5 && state.realm == Realm::Asgard {
1095 let intent_strength = (dot / (speed_sq.sqrt() * dist_sq.sqrt())).clamp(0.0, 1.0);
1097 renderer.stroke_rect(rect, [0.0, 0.9, 1.0, 0.3 * intent_strength], 1.5);
1098 }
1099
1100 view.render(renderer, rect);
1101 }
1102}
1103
1104#[derive(Debug, Clone, Copy, PartialEq)]
1106pub struct KvasirVibeModifier {
1107 pub complexity: f32,
1108}
1109
1110impl ViewModifier for KvasirVibeModifier {
1111 fn modify<V: View>(self, content: V) -> impl View {
1112 ModifiedView::new(content, self)
1113 }
1114
1115 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1116 if crate::load_system_state().realm == Realm::Asgard {
1117 let t = renderer.elapsed_time();
1118 let c = self.complexity.clamp(0.0, 1.0);
1119
1120 let blur = 20.0 + c * 40.0;
1123 let turbulence_x = (t * (1.0 + c * 2.0)).sin() * 8.0 * c;
1124 let turbulence_y = (t * (0.8 + c * 1.5)).cos() * 5.0 * c;
1125 renderer.bifrost(
1126 rect.offset(turbulence_x, turbulence_y),
1127 blur,
1128 0.8 + c * 0.4,
1129 0.25,
1130 );
1131
1132 if c > 0.2 {
1134 let pulse = (t * (3.0 + c * 5.0)).sin().abs() * c;
1135 let color = [0.0, 0.9, 1.0, 0.4 * pulse]; renderer.gungnir(rect, color, 12.0 + c * 24.0, 0.6 * pulse);
1137 }
1138
1139 if c > 0.7 {
1141 let instability = (t * 15.0).cos().abs() * (c - 0.7) * 3.3;
1142 let warning_color = [1.0, 0.0, 0.4, 0.12 * instability];
1143 renderer.fill_rect(rect, warning_color);
1144 renderer.stroke_rect(rect, [1.0, 0.0, 0.2, 0.45 * instability], 1.8);
1145 }
1146 }
1147 view.render(renderer, rect);
1148 }
1149}
1150
1151#[derive(Debug, Clone, Copy, PartialEq)]
1153pub struct OdinsEyeModifier;
1154
1155impl ViewModifier for OdinsEyeModifier {
1156 fn modify<V: View>(self, content: V) -> impl View {
1157 ModifiedView::new(content, self)
1158 }
1159
1160 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1161 let state = crate::load_system_state();
1162 let t = renderer.elapsed_time();
1163
1164 view.render(renderer, rect);
1166
1167 if state.realm == Realm::Asgard {
1168 let eye_pulse = (t * 0.5).sin().abs() * 0.05;
1171 renderer.draw_radial_gradient(
1172 rect,
1173 [0.0, 0.6, 0.8, 0.08 + eye_pulse], [0.0, 0.0, 0.0, 0.0], );
1176
1177 let hugin_rect = Rect {
1179 x: rect.x + 20.0,
1180 y: rect.y + 40.0,
1181 width: 200.0,
1182 height: rect.height - 80.0,
1183 };
1184 renderer.draw_text(
1185 "HUGIN: THOUGHT",
1186 hugin_rect.x,
1187 hugin_rect.y,
1188 10.0,
1189 [0.0, 1.0, 1.0, 0.6],
1190 );
1191 for (i, thought) in state.thoughts.iter().rev().take(10).enumerate() {
1192 renderer.draw_text(
1193 thought,
1194 hugin_rect.x,
1195 hugin_rect.y + 20.0 + i as f32 * 14.0,
1196 9.0,
1197 [1.0, 1.0, 1.0, 0.4],
1198 );
1199 }
1200
1201 let munin_rect = Rect {
1203 x: rect.x + rect.width - 220.0,
1204 y: rect.y + 40.0,
1205 width: 200.0,
1206 height: rect.height - 80.0,
1207 };
1208 renderer.draw_text(
1209 "MUNIN: MEMORY",
1210 munin_rect.x,
1211 munin_rect.y,
1212 10.0,
1213 [1.0, 0.84, 0.0, 0.6],
1214 );
1215 for (i, node) in state.nodes.iter().take(10).enumerate() {
1216 let opacity = (node.weight.min(1.0)) * 0.5;
1217 renderer.draw_text(
1218 &node.id,
1219 munin_rect.x,
1220 munin_rect.y + 20.0 + i as f32 * 14.0,
1221 9.0,
1222 [1.0, 1.0, 1.0, opacity],
1223 );
1224 }
1225
1226 if let Some(focus_id) = &state.odin_focus {
1228 renderer.draw_text(
1230 &format!("EYE FOCUS: {}", focus_id),
1231 rect.x + rect.width / 2.0 - 50.0,
1232 rect.y + 20.0,
1233 12.0,
1234 [0.0, 1.0, 1.0, 0.8],
1235 );
1236
1237 renderer.gungnir(
1240 Rect {
1241 x: rect.x + rect.width / 2.0 - 1.0,
1242 y: rect.y,
1243 width: 2.0,
1244 height: rect.height,
1245 },
1246 [0.0, 1.0, 1.0, 1.0],
1247 20.0,
1248 0.4,
1249 );
1250 }
1251 }
1252 }
1253}
1254
1255#[derive(Debug, Clone, Copy, PartialEq)]
1257pub struct SleipnirParams {
1258 pub stiffness: f32,
1259 pub damping: f32,
1260 pub mass: f32,
1261}
1262
1263impl SleipnirParams {
1264 pub fn snappy() -> Self {
1265 Self {
1266 stiffness: 230.0,
1267 damping: 22.0,
1268 mass: 1.0,
1269 }
1270 }
1271 pub fn fluid() -> Self {
1272 Self {
1273 stiffness: 170.0,
1274 damping: 26.0,
1275 mass: 1.0,
1276 }
1277 }
1278 pub fn heavy() -> Self {
1279 Self {
1280 stiffness: 90.0,
1281 damping: 20.0,
1282 mass: 1.0,
1283 }
1284 }
1285 pub fn bouncy() -> Self {
1286 Self {
1287 stiffness: 190.0,
1288 damping: 14.0,
1289 mass: 1.0,
1290 }
1291 }
1292}
1293
1294impl Default for SleipnirParams {
1295 fn default() -> Self {
1296 Self::fluid()
1297 }
1298}
1299
1300#[derive(Debug, Clone, Copy, PartialEq)]
1301struct SolverState {
1302 x: f32,
1303 v: f32,
1304}
1305
1306#[derive(Debug, Clone, Copy, PartialEq)]
1309pub struct SleipnirSolver {
1310 params: SleipnirParams,
1311 target: f32,
1312 state: SolverState,
1313}
1314
1315impl SleipnirSolver {
1316 pub fn new(params: SleipnirParams, target: f32, current: f32) -> Self {
1318 Self {
1319 params,
1320 target,
1321 state: SolverState { x: current, v: 0.0 },
1322 }
1323 }
1324
1325 pub fn tick(&mut self, dt: f32) -> f32 {
1327 if dt <= 0.0 {
1328 return self.state.x;
1329 }
1330
1331 let mut remaining = dt;
1333 let step = 1.0 / 120.0;
1334
1335 while remaining > 0.0 {
1336 let d = remaining.min(step);
1337 self.step(d);
1338 remaining -= d;
1339 }
1340
1341 self.state.x
1342 }
1343
1344 fn step(&mut self, dt: f32) {
1345 let a = self.evaluate(self.state, 0.0, SolverState { x: 0.0, v: 0.0 });
1346 let b = self.evaluate(self.state, dt * 0.5, a);
1347 let c = self.evaluate(self.state, dt * 0.5, b);
1348 let d = self.evaluate(self.state, dt, c);
1349
1350 let dxdt = 1.0 / 6.0 * (a.x + 2.0 * (b.x + c.x) + d.x);
1351 let dvdt = 1.0 / 6.0 * (a.v + 2.0 * (b.v + c.v) + d.v);
1352
1353 self.state.x += dxdt * dt;
1354 self.state.v += dvdt * dt;
1355 }
1356
1357 fn evaluate(&self, initial: SolverState, dt: f32, d: SolverState) -> SolverState {
1358 let state = SolverState {
1359 x: initial.x + d.x * dt,
1360 v: initial.v + d.v * dt,
1361 };
1362 let force =
1363 -self.params.stiffness * (state.x - self.target) - self.params.damping * state.v;
1364 let mass = self.params.mass.max(0.001);
1365 SolverState {
1366 x: state.v,
1367 v: force / mass,
1368 }
1369 }
1370
1371 pub fn is_settled(&self) -> bool {
1372 (self.state.x - self.target).abs() < 0.001 && self.state.v.abs() < 0.001
1373 }
1374
1375 pub fn set_target(&mut self, target: f32) {
1376 self.target = target;
1377 }
1378
1379 pub fn current_value(&self) -> f32 {
1380 self.state.x
1381 }
1382}
1383
1384#[derive(Debug, Clone, PartialEq)]
1386pub struct SleipnirModifier {
1387 pub id: u64,
1388 pub target: f32,
1389 pub params: SleipnirParams,
1390}
1391
1392impl ViewModifier for SleipnirModifier {
1393 fn modify<V: View>(self, content: V) -> impl View {
1394 ModifiedView::new(content, self)
1395 }
1396
1397 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1398 let state = load_system_state();
1399
1400 let solver_lock_opt = state.get_component_state::<SleipnirSolver>(self.id);
1402
1403 let current_val;
1404
1405 if let Some(lock) = solver_lock_opt {
1406 let mut solver = lock.write().unwrap();
1408 solver.set_target(self.target);
1409 current_val = solver.tick(renderer.delta_time());
1410
1411 if !solver.is_settled() {
1413 renderer.request_redraw();
1414 }
1415 } else {
1416 let solver = SleipnirSolver::new(
1418 self.params,
1419 self.target,
1420 self.target, );
1422
1423 get_system_state().rcu(|old| {
1425 let mut new_state = (**old).clone();
1426 new_state.set_component_state(self.id, solver);
1427 new_state
1428 });
1429
1430 current_val = self.target;
1431 }
1432
1433 renderer.push_transform([0.0, current_val], [1.0, 1.0], 0.0);
1435 view.render(renderer, rect);
1436 renderer.pop_transform();
1437 }
1438}
1439
1440#[derive(Debug, Clone, Copy, PartialEq)]
1443pub struct TransformModifier {
1444 pub translation: [f32; 2],
1445 pub scale: [f32; 2],
1446 pub rotation: f32,
1447}
1448
1449impl Default for TransformModifier {
1450 fn default() -> Self {
1451 Self::new()
1452 }
1453}
1454
1455impl TransformModifier {
1456 pub fn new() -> Self {
1457 Self {
1458 translation: [0.0, 0.0],
1459 scale: [1.0, 1.0],
1460 rotation: 0.0,
1461 }
1462 }
1463
1464 pub fn translate(mut self, x: f32, y: f32) -> Self {
1465 self.translation = [x, y];
1466 self
1467 }
1468
1469 pub fn scale(mut self, x: f32, y: f32) -> Self {
1470 self.scale = [x, y];
1471 self
1472 }
1473
1474 pub fn rotate(mut self, radians: f32) -> Self {
1475 self.rotation = radians;
1476 self
1477 }
1478}
1479
1480impl ViewModifier for TransformModifier {
1481 fn modify<V: View>(self, content: V) -> impl View {
1482 ModifiedView::new(content, self)
1483 }
1484
1485 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1486 renderer.push_transform(self.translation, self.scale, self.rotation);
1487 view.render(renderer, rect);
1488 renderer.pop_transform();
1489 }
1490}
1491
1492#[derive(Clone)]
1495pub struct LifecycleModifier {
1496 pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
1497 pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
1498}
1499
1500impl ViewModifier for LifecycleModifier {
1501 fn modify<V: View>(self, content: V) -> impl View {
1502 ModifiedView::new(content, self)
1503 }
1504}
1505
1506#[derive(Debug, Clone, Copy, PartialEq)]
1509pub struct OpacityModifier {
1510 pub opacity: f32,
1511}
1512
1513impl ViewModifier for OpacityModifier {
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 renderer.push_opacity(self.opacity);
1520 }
1521
1522 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1523 renderer.pop_opacity();
1524 }
1525}
1526
1527#[derive(Clone)]
1529pub struct OnClickModifier {
1530 pub action: Arc<dyn Fn() + Send + Sync>,
1531}
1532
1533impl ViewModifier for OnClickModifier {
1534 fn modify<V: View>(self, content: V) -> impl View {
1535 ModifiedView::new(content, self)
1536 }
1537
1538 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1539 let action = self.action.clone();
1540 renderer.register_handler(
1541 "pointerclick",
1542 std::sync::Arc::new(move |event| {
1543 if let Event::PointerClick { .. } = event {
1544 (action)();
1545 }
1546 }),
1547 );
1548 }
1549}
1550
1551#[derive(Clone)]
1553pub struct OnPointerEnterModifier {
1554 pub action: Arc<dyn Fn() + Send + Sync>,
1555}
1556
1557impl ViewModifier for OnPointerEnterModifier {
1558 fn modify<V: View>(self, content: V) -> impl View {
1559 ModifiedView::new(content, self)
1560 }
1561
1562 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1563 let action = self.action.clone();
1564 renderer.register_handler(
1565 "pointerenter",
1566 std::sync::Arc::new(move |event| {
1567 if let Event::PointerEnter = event {
1568 (action)();
1569 }
1570 }),
1571 );
1572 }
1573}
1574
1575#[derive(Clone)]
1577pub struct OnPointerLeaveModifier {
1578 pub action: Arc<dyn Fn() + Send + Sync>,
1579}
1580
1581impl ViewModifier for OnPointerLeaveModifier {
1582 fn modify<V: View>(self, content: V) -> impl View {
1583 ModifiedView::new(content, self)
1584 }
1585
1586 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1587 let action = self.action.clone();
1588 renderer.register_handler(
1589 "pointerleave",
1590 std::sync::Arc::new(move |event| {
1591 if let Event::PointerLeave = event {
1592 (action)();
1593 }
1594 }),
1595 );
1596 }
1597}
1598
1599#[derive(Clone)]
1601pub struct OnPointerMoveModifier {
1602 pub action: Arc<dyn Fn(f32, f32) + Send + Sync>,
1603}
1604
1605impl ViewModifier for OnPointerMoveModifier {
1606 fn modify<V: View>(self, content: V) -> impl View {
1607 ModifiedView::new(content, self)
1608 }
1609
1610 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1611 let action = self.action.clone();
1612 renderer.register_handler(
1613 "pointermove",
1614 std::sync::Arc::new(move |event| {
1615 if let Event::PointerMove { x, y } = event {
1616 (action)(x, y);
1617 }
1618 }),
1619 );
1620 }
1621}
1622
1623#[derive(Clone)]
1625pub struct OnPointerDownModifier {
1626 pub action: Arc<dyn Fn() + Send + Sync>,
1627}
1628
1629impl ViewModifier for OnPointerDownModifier {
1630 fn modify<V: View>(self, content: V) -> impl View {
1631 ModifiedView::new(content, self)
1632 }
1633
1634 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1635 let action = self.action.clone();
1636 renderer.register_handler(
1637 "pointerdown",
1638 std::sync::Arc::new(move |event| {
1639 if let Event::PointerDown { .. } = event {
1640 (action)();
1641 }
1642 }),
1643 );
1644 }
1645}
1646
1647#[derive(Clone)]
1649pub struct OnPointerUpModifier {
1650 pub action: Arc<dyn Fn() + Send + Sync>,
1651}
1652
1653impl ViewModifier for OnPointerUpModifier {
1654 fn modify<V: View>(self, content: V) -> impl View {
1655 ModifiedView::new(content, self)
1656 }
1657
1658 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1659 let action = self.action.clone();
1660 renderer.register_handler(
1661 "pointerup",
1662 std::sync::Arc::new(move |event| {
1663 if let Event::PointerUp { .. } = event {
1664 (action)();
1665 }
1666 }),
1667 );
1668 }
1669}
1670
1671#[derive(Debug, Clone, Copy, PartialEq)]
1674pub struct ForegroundColorModifier {
1675 pub color: [f32; 4],
1676}
1677
1678impl ViewModifier for ForegroundColorModifier {
1679 fn modify<V: View>(self, content: V) -> impl View {
1680 ModifiedView::new(content, self)
1681 }
1682}
1683
1684#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1687pub struct ClipModifier;
1688
1689impl ViewModifier for ClipModifier {
1690 fn modify<V: View>(self, content: V) -> impl View {
1691 ModifiedView::new(content, self)
1692 }
1693
1694 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1695 renderer.push_clip_rect(rect);
1696 }
1697
1698 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1699 renderer.pop_clip_rect();
1700 }
1701}
1702
1703#[derive(Debug, Clone, Copy, PartialEq)]
1705pub struct BorderModifier {
1706 pub color: [f32; 4],
1707 pub width: f32,
1708}
1709
1710impl ViewModifier for BorderModifier {
1711 fn modify<V: View>(self, content: V) -> impl View {
1712 ModifiedView::new(content, self)
1713 }
1714
1715 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1716 renderer.stroke_rect(rect, self.color, self.width);
1717 }
1718}
1719
1720#[doc(hidden)]
1722pub enum Never {}
1723
1724impl View for Never {
1725 type Body = Never;
1726 fn body(self) -> Never {
1727 unreachable!()
1728 }
1729}
1730
1731#[derive(Debug, Clone, Copy, Default)]
1733pub struct EmptyView;
1734
1735impl View for EmptyView {
1736 type Body = Never;
1737 fn body(self) -> Self::Body {
1738 unreachable!()
1739 }
1740 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1741 fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
1742 Size {
1743 width: 0.0,
1744 height: 0.0,
1745 }
1746 }
1747}
1748
1749#[derive(Clone)]
1752pub struct ModifiedView<V, M> {
1753 view: V,
1754 modifier: M,
1755}
1756
1757impl<V: View, M: ViewModifier> ModifiedView<V, M> {
1758 #[doc(hidden)]
1759 pub fn new(view: V, modifier: M) -> Self {
1760 Self { view, modifier }
1761 }
1762}
1763
1764impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
1765 type Body = ModifiedView<V::Body, M>;
1766
1767 fn body(self) -> Self::Body {
1768 ModifiedView {
1769 view: self.view.body(),
1770 modifier: self.modifier.clone(),
1771 }
1772 }
1773
1774 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1775 self.modifier.render_view(&self.view, renderer, rect);
1776 }
1777
1778 fn intrinsic_size(&self, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1779 self.modifier.measure_view(&self.view, renderer, proposal)
1780 }
1781
1782 fn flex_weight(&self) -> f32 {
1783 self.modifier.child_flex_weight(&self.view)
1784 }
1785
1786 fn layout(&self) -> Option<&dyn layout::LayoutView> {
1787 self.modifier.layout().or_else(|| self.view.layout())
1788 }
1789}
1790
1791pub trait ViewModifier: Send + Clone {
1792 fn modify<V: View>(self, content: V) -> impl View;
1793
1794 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1796
1797 fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1799
1800 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1803 self.render(renderer, rect);
1804 let child_rect = self.transform_rect(rect);
1805 view.render(renderer, child_rect);
1806 self.post_render(renderer, rect);
1807 }
1808
1809 fn transform_rect(&self, rect: Rect) -> Rect {
1810 rect
1811 }
1812
1813 fn transform_proposal(&self, proposal: SizeProposal) -> SizeProposal {
1815 proposal
1816 }
1817
1818 fn transform_size(&self, size: Size) -> Size {
1820 size
1821 }
1822
1823 fn measure_view<V: View>(
1825 &self,
1826 view: &V,
1827 renderer: &mut dyn Renderer,
1828 proposal: SizeProposal,
1829 ) -> Size {
1830 let child_proposal = self.transform_proposal(proposal);
1831 let child_size = view.intrinsic_size(renderer, child_proposal);
1832 self.transform_size(child_size)
1833 }
1834
1835 fn child_flex_weight<V: View>(&self, view: &V) -> f32 {
1837 view.flex_weight()
1838 }
1839
1840 fn layout(&self) -> Option<&dyn layout::LayoutView> {
1841 None
1842 }
1843}
1844
1845#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1847pub struct TelemetryData {
1848 pub frame_time_ms: f32,
1849 pub p99_frame_time_ms: f32,
1851 pub frame_jitter_ms: f32,
1853 pub hardware_stall_detected: bool,
1855
1856 pub input_time_ms: f32,
1858 pub state_flush_time_ms: f32,
1859 pub layout_time_ms: f32,
1860 pub draw_time_ms: f32,
1861 pub gpu_submit_time_ms: f32,
1862
1863 pub draw_calls: u32,
1864 pub vertices: u32,
1865
1866 pub berserker_rage: f32,
1868
1869 pub vram_usage_mb: f32,
1871 pub vram_textures_mb: f32,
1872 pub vram_buffers_mb: f32,
1873 pub vram_pipelines_mb: f32,
1874 pub vram_exhausted: bool,
1876}
1877
1878#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1880pub struct FrameBudget {
1881 pub target_ms: f32,
1883 pub allow_degradation: bool,
1886}
1887
1888impl Default for FrameBudget {
1889 fn default() -> Self {
1890 Self {
1891 target_ms: 16.0,
1892 allow_degradation: true,
1893 }
1894 }
1895}
1896
1897pub trait ElapsedTime {
1905 fn elapsed_time(&self) -> f32;
1907
1908 fn delta_time(&self) -> f32;
1910}
1911
1912pub trait Renderer: ElapsedTime + Send {
1919 fn request_redraw(&mut self) {}
1922
1923 fn is_over_budget(&self) -> bool {
1926 false
1927 }
1928
1929 fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
1931 fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
1932 fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
1934
1935 fn draw_3d_cube(&mut self, _rect: Rect, _color: [f32; 4], _rotation: [f32; 3]) {}
1938
1939 fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1941 fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
1942 fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1944 fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
1946 fn fill_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4]) {}
1948 fn stroke_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4], _stroke_width: f32) {}
1950
1951 fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
1953 fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
1955
1956 fn draw_texture(&mut self, _texture_id: u32, _rect: Rect) {}
1959 fn draw_image(&mut self, _image_name: &str, _rect: Rect) {}
1961 fn load_image(&mut self, _name: &str, _data: &[u8]) {}
1963 fn prewarm_vram(&mut self, _assets: Vec<(String, Vec<u8>)>) {}
1966
1967 fn get_pointer_position(&self) -> [f32; 2] {
1969 [0.0, 0.0]
1970 }
1971
1972 fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
1975 fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
1977
1978 fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
1981
1982 fn draw_linear_gradient(
1985 &mut self,
1986 _rect: Rect,
1987 _start_color: [f32; 4],
1988 _end_color: [f32; 4],
1989 _angle: f32,
1990 ) {
1991 }
1992 fn draw_radial_gradient(
1994 &mut self,
1995 _rect: Rect,
1996 _inner_color: [f32; 4],
1997 _outer_color: [f32; 4],
1998 ) {
1999 }
2000 fn draw_drop_shadow(
2002 &mut self,
2003 _rect: Rect,
2004 _radius: f32,
2005 _color: [f32; 4],
2006 _blur: f32,
2007 _spread: f32,
2008 ) {
2009 }
2010 fn stroke_dashed_rounded_rect(
2012 &mut self,
2013 _rect: Rect,
2014 _radius: f32,
2015 _color: [f32; 4],
2016 _width: f32,
2017 _dash: f32,
2018 _gap: f32,
2019 ) {
2020 }
2021 fn draw_9slice(
2023 &mut self,
2024 _image_name: &str,
2025 _rect: Rect,
2026 _left: f32,
2027 _top: f32,
2028 _right: f32,
2029 _bottom: f32,
2030 ) {
2031 }
2032
2033 fn push_clip_rect(&mut self, _rect: Rect) {}
2037 fn pop_clip_rect(&mut self) {}
2039 fn current_clip_rect(&self) -> Rect {
2042 Rect::new(-10000.0, -10000.0, 20000.0, 20000.0)
2043 }
2044
2045 fn push_opacity(&mut self, _opacity: f32) {}
2049 fn pop_opacity(&mut self) {}
2051
2052 fn set_theme(&mut self, _theme: ColorTheme) {}
2054 fn set_rage(&mut self, _rage: f32) {}
2055 fn set_berserker_mode(&mut self, _state: BerserkerMode) {}
2056 fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
2057 fn set_scene(&mut self, _scene: &str) {}
2059
2060 fn capture_png(&mut self) -> Vec<u8> {
2063 Vec::new()
2064 }
2065 fn print(&mut self) {}
2067
2068 fn set_scene_preset(&mut self, _preset: u32) {}
2069
2070 fn bifrost(&mut self, _rect: Rect, _blur: f32, _saturation: f32, _opacity: f32) {}
2073 fn gungnir(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32, _intensity: f32) {}
2075 fn mani_glow(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32) {}
2077 fn push_mjolnir_slice(&mut self, _angle: f32, _offset: f32) {}
2079 fn pop_mjolnir_slice(&mut self) {}
2080 fn memoize(&mut self, id: u64, data_hash: u64, render_fn: &dyn Fn(&mut dyn Renderer));
2084 fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
2086 fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
2087 fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
2089
2090 fn set_aria_role(&mut self, _role: &str) {}
2092 fn set_aria_label(&mut self, _label: &str) {}
2093
2094 fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
2096
2097 fn set_key(&mut self, _key: &str) {}
2099
2100 fn get_telemetry(&self) -> TelemetryData {
2103 TelemetryData::default()
2104 }
2105
2106 fn push_shadow(&mut self, _radius: f32, _color: [f32; 4], _offset: [f32; 2]) {}
2109 fn pop_shadow(&mut self) {}
2111
2112 fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
2115 fn pop_vnode(&mut self) {}
2117 fn register_handler(
2119 &mut self,
2120 _event_type: &str,
2121 _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
2122 ) {
2123 }
2124
2125 fn set_z_index(&mut self, _z: f32) {}
2129 fn get_z_index(&self) -> f32 {
2131 0.0
2132 }
2133
2134 fn load_svg(&mut self, _name: &str, _svg_data: &[u8]) {}
2137 fn draw_svg(&mut self, _name: &str, _rect: Rect) {}
2139
2140 fn push_transform(&mut self, _translation: [f32; 2], _scale: [f32; 2], _rotation: f32) {}
2145 fn pop_transform(&mut self) {}
2147 fn query_layout(&self, _node_id: scene_graph::NodeId) -> Option<Rect> {
2149 None
2150 }
2151 fn set_debug_layout(&mut self, _enabled: bool) {}
2153 fn get_debug_layout(&self) -> bool {
2155 false
2156 }
2157}
2158
2159pub mod accessibility {
2161 pub fn relative_luminance(color: [f32; 4]) -> f32 {
2163 let f = |c: f32| {
2164 if c <= 0.03928 {
2165 c / 12.92
2166 } else {
2167 ((c + 0.055) / 1.055).powf(2.4)
2168 }
2169 };
2170 0.2126 * f(color[0]) + 0.7152 * f(color[1]) + 0.0722 * f(color[2])
2171 }
2172
2173 pub fn contrast_ratio(c1: [f32; 4], c2: [f32; 4]) -> f32 {
2175 let l1 = relative_luminance(c1);
2176 let l2 = relative_luminance(c2);
2177 let (light, dark) = if l1 > l2 { (l1, l2) } else { (l2, l1) };
2178 (light + 0.05) / (dark + 0.05)
2179 }
2180}
2181#[derive(
2183 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
2184)]
2185pub enum RenderTier {
2186 Tier1GPU = 0,
2188 Tier2GPU = 1,
2190 Tier3Fallback = 2,
2192}
2193use bytemuck::{Pod, Zeroable};
2197#[repr(C)]
2199#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
2200pub struct ColorTheme {
2201 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
2203 pub glass_base: [f32; 4],
2204 pub glass_edge: [f32; 4],
2205 pub rune_glow: [f32; 4],
2206 pub ember_core: [f32; 4],
2207 pub background_deep: [f32; 4],
2208 pub mani_glow: [f32; 4], pub glass_blur_strength: f32,
2210 pub shatter_edge_width: f32,
2211 pub neon_bloom_radius: f32,
2212 pub rune_opacity: f32,
2213}
2214impl ColorTheme {
2215 pub fn asgard() -> Self {
2217 Self {
2218 primary_neon: [0.0, 1.0, 0.95, 1.2],
2219 shatter_neon: [1.0, 0.0, 0.75, 1.5],
2220 glass_base: [0.04, 0.04, 0.06, 0.82],
2221 glass_edge: [0.0, 0.45, 0.55, 0.6],
2222 rune_glow: [0.75, 0.98, 1.0, 0.9],
2223 ember_core: [0.95, 0.12, 0.12, 1.0],
2224 background_deep: [0.01, 0.01, 0.03, 1.0],
2225 mani_glow: [0.7, 0.9, 1.0, 0.05],
2226 glass_blur_strength: 0.6,
2227 shatter_edge_width: 1.8,
2228 neon_bloom_radius: 0.022,
2229 rune_opacity: 0.55,
2230 }
2231 }
2232
2233 pub fn midgard() -> Self {
2235 Self {
2236 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],
2242 background_deep: [0.05, 0.05, 0.07, 1.0],
2243 mani_glow: [0.0, 0.0, 0.0, 0.0], glass_blur_strength: 0.0, shatter_edge_width: 1.0,
2246 neon_bloom_radius: 0.0,
2247 rune_opacity: 0.0,
2248 }
2249 }
2250
2251 pub fn cyberpunk_viking() -> Self {
2252 Self::asgard()
2253 }
2254 pub fn vibrant_glass() -> Self {
2255 Self {
2256 primary_neon: [0.0, 1.0, 0.95, 1.2],
2257 shatter_neon: [1.0, 0.0, 0.75, 1.5],
2258 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],
2261 ember_core: [1.0, 0.4, 0.1, 1.0],
2262 background_deep: [0.05, 0.05, 0.1, 1.0],
2263 mani_glow: [0.7, 0.9, 1.0, 0.05],
2264 glass_blur_strength: 0.9,
2265 shatter_edge_width: 1.8,
2266 neon_bloom_radius: 0.022,
2267 rune_opacity: 0.55,
2268 }
2269 }
2270}
2271impl Default for ColorTheme {
2272 fn default() -> Self {
2273 Self::vibrant_glass()
2274 }
2275}
2276#[repr(C)]
2278#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
2279pub struct SceneUniforms {
2280 pub view: glam::Mat4,
2281 pub proj: glam::Mat4,
2282 pub time: f32,
2283 pub delta_time: f32,
2284 pub resolution: [f32; 2],
2285 pub mouse: [f32; 2],
2286 pub mouse_velocity: [f32; 2],
2287 pub shatter_origin: [f32; 2],
2288 pub shatter_time: f32,
2289 pub shatter_force: f32,
2290 pub berzerker_rage: f32,
2291 pub berzerker_mode: u32,
2292 pub scroll_offset: f32,
2293 pub scale_factor: f32,
2294 pub scene_type: u32,
2295 pub _pad: [f32; 3], }
2297
2298pub const SCENE_AURORA: u32 = 0;
2299pub const SCENE_VOID: u32 = 1;
2300pub const SCENE_NEBULA: u32 = 2;
2301pub const SCENE_GLITCH: u32 = 3;
2302pub const SCENE_YGGDRASIL: u32 = 4;
2303
2304impl SceneUniforms {
2305 pub fn new(width: f32, height: f32) -> Self {
2306 Self {
2307 view: glam::Mat4::IDENTITY,
2308 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
2309 time: 0.0,
2310 delta_time: 0.016,
2311 resolution: [width, height],
2312 mouse: [0.5, 0.5],
2313 mouse_velocity: [0.0, 0.0],
2314 shatter_origin: [0.5, 0.5],
2315 shatter_time: -100.0,
2316 shatter_force: 0.0,
2317 berzerker_rage: 0.0,
2318 berzerker_mode: 0,
2319 scroll_offset: 0.0,
2320 scale_factor: 1.0,
2321 scene_type: SCENE_AURORA,
2322 _pad: [0.0; 3],
2323 }
2324 }
2325}
2326#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
2328pub struct Mesh {
2329 pub vertices: Vec<[f32; 3]>,
2330 pub normals: Vec<[f32; 3]>,
2331 pub indices: Vec<u32>,
2332}
2333impl Mesh {
2334 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
2335 let mut cursor = std::io::Cursor::new(data);
2336 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
2337 Ok((Vec::new(), Default::default()))
2338 })?;
2339 let mut meshes = Vec::new();
2340 for m in models {
2341 let mesh = m.mesh;
2342 let vertices: Vec<[f32; 3]> = mesh
2343 .positions
2344 .chunks(3)
2345 .map(|c| [c[0], c[1], c[2]])
2346 .collect();
2347 let normals = if mesh.normals.is_empty() {
2348 vec![[0.0, 0.0, 1.0]; vertices.len()]
2349 } else {
2350 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
2351 };
2352 meshes.push(Mesh {
2353 vertices,
2354 normals,
2355 indices: mesh.indices,
2356 });
2357 }
2358 Ok(meshes)
2359 }
2360 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
2361 let mut cursor = std::io::Cursor::new(data);
2362 let stl = stl_io::read_stl(&mut cursor)?;
2363 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
2364 let mut indices = Vec::new();
2365 for face in stl.faces {
2366 indices.push(face.vertices[0] as u32);
2367 indices.push(face.vertices[1] as u32);
2368 indices.push(face.vertices[2] as u32);
2369 }
2370 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
2371 Ok(Mesh {
2372 vertices,
2373 normals,
2374 indices,
2375 })
2376 }
2377}
2378pub trait FrameRenderer<E = ()>: Renderer {
2381 fn begin_frame(&mut self) -> E;
2382 fn render_frame(&mut self) {
2383 }
2385 fn end_frame(&mut self, encoder: E);
2386}
2387use std::sync::Arc;
2388type SubscriberList<T> = Arc<std::sync::Mutex<Vec<Box<dyn Fn(&T) + Send + Sync>>>>;
2389#[derive(Clone)]
2391pub struct State<T: Clone + Send + Sync + 'static> {
2392 swap: Arc<arc_swap::ArcSwap<T>>,
2393 metadata_swap: Arc<arc_swap::ArcSwap<Option<agents::MutationMetadata>>>,
2394 #[cfg(not(target_arch = "wasm32"))]
2395 tvar: Arc<stm::TVar<T>>,
2396 #[cfg(not(target_arch = "wasm32"))]
2397 metadata_tvar: Arc<stm::TVar<Option<agents::MutationMetadata>>>,
2398 subscribers: SubscriberList<T>,
2399 version: Arc<std::sync::atomic::AtomicU64>,
2400 resolution: agents::ConflictResolution,
2401}
2402impl<T: Clone + Send + Sync + 'static> State<T> {
2403 pub fn new(value: T) -> Self {
2405 #[cfg(not(target_arch = "wasm32"))]
2406 let tvar = Arc::new(stm::TVar::new(value.clone()));
2407 #[cfg(not(target_arch = "wasm32"))]
2408 let metadata_tvar = Arc::new(stm::TVar::new(None));
2409 Self {
2410 swap: Arc::new(arc_swap::ArcSwap::from_pointee(value)),
2411 metadata_swap: Arc::new(arc_swap::ArcSwap::new(Arc::new(None))),
2412 #[cfg(not(target_arch = "wasm32"))]
2413 tvar,
2414 #[cfg(not(target_arch = "wasm32"))]
2415 metadata_tvar,
2416 subscribers: Arc::new(std::sync::Mutex::new(Vec::new())),
2417 version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
2418 resolution: agents::ConflictResolution::default(),
2419 }
2420 }
2421 pub fn with_resolution(mut self, resolution: agents::ConflictResolution) -> Self {
2423 self.resolution = resolution;
2424 self
2425 }
2426 pub fn get(&self) -> T {
2428 (**self.swap.load()).clone()
2429 }
2430 pub fn set(&self, value: T) {
2432 #[cfg(not(target_arch = "wasm32"))]
2433 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
2434 let new_meta = agents::get_current_mutation_metadata();
2435 let existing_meta = self.metadata_tvar.read(tx)?;
2436 let mut skip = false;
2437 if self.resolution == agents::ConflictResolution::PriorityWins
2438 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
2439 && new_m.priority < old_m.priority
2440 {
2441 skip = true;
2442 }
2443 if !skip {
2444 self.tvar.write(tx, value.clone())?;
2445 self.metadata_tvar.write(tx, new_meta)?;
2446 Ok((false, value.clone(), new_meta))
2447 } else {
2448 Ok((true, self.tvar.read(tx)?, existing_meta))
2449 }
2450 });
2451 #[cfg(target_arch = "wasm32")]
2452 let (was_skipped, final_val, final_meta) =
2453 (false, value, agents::get_current_mutation_metadata());
2454 if was_skipped {
2455 if let (Some(new_m), Some(old_m)) =
2456 (agents::get_current_mutation_metadata(), final_meta)
2457 {
2458 agents::notify_conflict(agents::ConflictEvent {
2459 agent_id: new_m.agent_id,
2460 priority: new_m.priority,
2461 existing_agent_id: old_m.agent_id,
2462 existing_priority: old_m.priority,
2463 timestamp_ms: new_m.timestamp_ms,
2464 });
2465 }
2466 return;
2467 }
2468 self.swap.store(Arc::new(final_val.clone()));
2469 self.metadata_swap.store(Arc::new(final_meta));
2470 self.version
2471 .fetch_add(1, std::sync::atomic::Ordering::Release);
2472 let subs = Arc::clone(&self.subscribers);
2473 if crate::is_batching() {
2474 crate::enqueue_batch_task(Box::new(move || {
2475 let s = subs.lock().unwrap();
2476 for cb in s.iter() {
2477 cb(&final_val);
2478 }
2479 }));
2480 } else {
2481 let s = subs.lock().unwrap();
2482 for cb in s.iter() {
2483 cb(&final_val);
2484 }
2485 }
2486 }
2487 pub fn mutate<F: Fn(&T) -> T>(&self, f: F) {
2488 #[cfg(not(target_arch = "wasm32"))]
2489 {
2490 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
2491 let new_meta = agents::get_current_mutation_metadata();
2492 let existing_meta = self.metadata_tvar.read(tx)?;
2493 let mut skip = false;
2494 if self.resolution == agents::ConflictResolution::PriorityWins
2495 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
2496 && new_m.priority < old_m.priority
2497 {
2498 skip = true;
2499 }
2500 if !skip {
2501 let current = self.tvar.read(tx)?;
2502 let next = f(¤t);
2503 self.tvar.write(tx, next.clone())?;
2504 self.metadata_tvar.write(tx, new_meta)?;
2505 Ok((false, next, new_meta))
2506 } else {
2507 Ok((true, self.tvar.read(tx)?, existing_meta))
2508 }
2509 });
2510 if was_skipped {
2511 if let (Some(new_m), Some(old_m)) =
2512 (agents::get_current_mutation_metadata(), final_meta)
2513 {
2514 agents::notify_conflict(agents::ConflictEvent {
2515 agent_id: new_m.agent_id,
2516 priority: new_m.priority,
2517 existing_agent_id: old_m.agent_id,
2518 existing_priority: old_m.priority,
2519 timestamp_ms: new_m.timestamp_ms,
2520 });
2521 }
2522 return;
2523 }
2524 self.swap.store(Arc::new(final_val.clone()));
2525 self.metadata_swap.store(Arc::new(final_meta));
2526 self.version
2527 .fetch_add(1, std::sync::atomic::Ordering::Release);
2528 let subs = Arc::clone(&self.subscribers);
2529 if crate::is_batching() {
2530 crate::enqueue_batch_task(Box::new(move || {
2531 let s = subs.lock().unwrap();
2532 for cb in s.iter() {
2533 cb(&final_val);
2534 }
2535 }));
2536 } else {
2537 let s = subs.lock().unwrap();
2538 for cb in s.iter() {
2539 cb(&final_val);
2540 }
2541 }
2542 }
2543 #[cfg(target_arch = "wasm32")]
2544 {
2545 self.set(f(&self.get()));
2546 }
2547 }
2548 pub fn version(&self) -> u64 {
2550 self.version.load(std::sync::atomic::Ordering::Acquire)
2551 }
2552 pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
2554 self.subscribers.lock().unwrap().push(Box::new(callback));
2555 }
2556}
2557use crate::runtime::NodeStateSnapshot;
2558use std::sync::OnceLock;
2559use std::sync::atomic::{AtomicBool, Ordering};
2560pub static SYSTEM_STATE: OnceLock<Arc<arc_swap::ArcSwap<KnowledgeState>>> = OnceLock::new();
2562#[cfg(not(target_arch = "wasm32"))]
2563static KNOWLEDGE_TVAR: OnceLock<stm::TVar<KnowledgeState>> = OnceLock::new();
2564static IS_BATCHING: AtomicBool = AtomicBool::new(false);
2565pub static IS_RENDERING: AtomicBool = AtomicBool::new(false);
2566pub static LAYOUT_DIRTY: AtomicBool = AtomicBool::new(false);
2567type BatchQueue = OnceLock<std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync>>>>;
2568static BATCH_QUEUE: BatchQueue = OnceLock::new();
2569static STATE_WRITE_MUTEX: std::sync::Mutex<()> = std::sync::Mutex::new(());
2572pub fn is_batching() -> bool {
2574 IS_BATCHING.load(Ordering::Acquire)
2575}
2576pub fn is_rendering() -> bool {
2578 IS_RENDERING.load(Ordering::Acquire)
2579}
2580pub fn begin_render_phase() {
2582 IS_RENDERING.store(true, Ordering::Release);
2583}
2584pub fn end_render_phase() {
2586 IS_RENDERING.store(false, Ordering::Release);
2587}
2588pub fn enqueue_batch_task(task: Box<dyn FnOnce() + Send + Sync>) {
2590 let mut queue = BATCH_QUEUE
2591 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
2592 .lock()
2593 .unwrap();
2594 queue.push(task);
2595}
2596pub fn batch<F: FnOnce()>(f: F) {
2600 if IS_BATCHING.swap(true, Ordering::AcqRel) {
2601 f();
2603 return;
2604 }
2605 f();
2606 IS_BATCHING.store(false, Ordering::Release);
2607 let mut queue = BATCH_QUEUE
2608 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
2609 .lock()
2610 .unwrap();
2611 let tasks: Vec<_> = queue.drain(..).collect();
2612 drop(queue);
2613 for task in tasks {
2614 task();
2615 }
2616}
2617pub fn get_system_state() -> Arc<arc_swap::ArcSwap<KnowledgeState>> {
2619 SYSTEM_STATE
2620 .get_or_init(|| Arc::new(arc_swap::ArcSwap::from_pointee(KnowledgeState::default())))
2621 .clone()
2622}
2623pub fn load_system_state() -> arc_swap::Guard<Arc<KnowledgeState>> {
2624 get_system_state().load()
2625}
2626pub fn update_system_state<F>(f: F)
2627where
2628 F: Fn(&KnowledgeState) -> KnowledgeState,
2629{
2630 let _lock = STATE_WRITE_MUTEX.lock().unwrap();
2631 if is_rendering() {
2632 log::warn!(
2633 "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2634 );
2635 }
2636 LAYOUT_DIRTY.store(true, Ordering::SeqCst);
2637 let swap = get_system_state();
2638 let current = swap.load();
2639 let new_state = Arc::new(f(¤t));
2640 swap.store(Arc::clone(&new_state));
2641 #[cfg(not(target_arch = "wasm32"))]
2642 {
2643 let tvar = KNOWLEDGE_TVAR.get_or_init(|| stm::TVar::new((*new_state).clone()));
2644 stm::atomically(|tx| tvar.write(tx, (*new_state).clone()));
2645 }
2646}
2647pub fn transact_system_state<F>(f: F)
2648where
2649 F: Fn(&KnowledgeState) -> KnowledgeState,
2650{
2651 let _lock = STATE_WRITE_MUTEX.lock().unwrap();
2652 #[cfg(not(target_arch = "wasm32"))]
2653 {
2654 if is_rendering() {
2655 log::warn!(
2656 "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2657 );
2658 }
2659 let tvar = KNOWLEDGE_TVAR
2660 .get_or_init(|| stm::TVar::new((**get_system_state().load()).clone()))
2661 .clone();
2662 let new_state = stm::atomically(move |tx| {
2663 let current = tvar.read(tx)?;
2664 let next = f(¤t);
2665 tvar.write(tx, next.clone())?;
2666 Ok(next)
2667 });
2668 get_system_state().store(Arc::new(new_state));
2669 }
2670 #[cfg(target_arch = "wasm32")]
2671 {
2672 if is_rendering() {
2673 log::warn!(
2674 "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2675 );
2676 }
2677 update_system_state(f);
2678 }
2679}
2680impl KnowledgeState {
2681 pub fn new() -> Self {
2683 Self::default()
2684 }
2685 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
2687 self.component_states
2688 .insert(id, Arc::new(std::sync::RwLock::new(state)));
2689 }
2690 pub fn get_component_state<T: 'static + Send + Sync>(
2692 &self,
2693 id: u64,
2694 ) -> Option<Arc<std::sync::RwLock<T>>> {
2695 let lock = self.component_states.get(&id)?;
2696 let any_ref = lock.read().ok()?;
2700 if any_ref.is::<T>() {
2701 drop(any_ref);
2703 let cloned: Arc<std::sync::RwLock<dyn std::any::Any + Send + Sync>> = Arc::clone(lock);
2704 Some(unsafe {
2707 let raw = Arc::into_raw(cloned);
2708 Arc::from_raw(raw as *const std::sync::RwLock<T>)
2709 })
2710 } else {
2711 None
2712 }
2713 }
2714 pub fn remember(&mut self, fragment: KnowledgeFragment) {
2716 self.fragments.insert(fragment.id.clone(), fragment);
2717 }
2718 pub fn process_query(&mut self, query: &str) {
2720 let query_lower = query.to_lowercase();
2721 let mut results: Vec<(f32, String)> = self
2722 .fragments
2723 .iter()
2724 .map(|(id, frag)| {
2725 let mut score = 0.0;
2726 if frag.summary.to_lowercase().contains(&query_lower) {
2727 score += 1.0;
2728 }
2729 if frag.source.to_lowercase().contains(&query_lower) {
2730 score += 0.5;
2731 }
2732 (score, id.clone())
2733 })
2734 .filter(|(score, _)| *score > 0.0)
2735 .collect();
2736 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
2738 self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
2739 }
2740 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
2742 let mut snapshots = Vec::new();
2743 for frag in self.fragments.values() {
2745 if let Ok(val) = serde_json::to_value(frag) {
2746 snapshots.push(NodeStateSnapshot { id: 0, state: val });
2747 }
2748 }
2749 snapshots
2750 }
2751}
2752#[derive(Clone)]
2754pub struct Binding<T: Clone + Send + Sync + 'static> {
2755 swap: Arc<arc_swap::ArcSwap<T>>,
2756 #[cfg(not(target_arch = "wasm32"))]
2757 tvar: Arc<stm::TVar<T>>,
2758 version: Arc<std::sync::atomic::AtomicU64>,
2759}
2760impl<T: Clone + Send + Sync + 'static> Binding<T> {
2761 pub fn from_state(state: &State<T>) -> Self {
2763 Self {
2764 swap: Arc::clone(&state.swap),
2765 #[cfg(not(target_arch = "wasm32"))]
2766 tvar: Arc::clone(&state.tvar),
2767 version: Arc::clone(&state.version),
2768 }
2769 }
2770 pub fn get(&self) -> T {
2772 (**self.swap.load()).clone()
2773 }
2774 pub fn set(&self, value: T) {
2776 self.swap.store(Arc::new(value.clone()));
2777 #[cfg(not(target_arch = "wasm32"))]
2778 {
2779 let tvar = Arc::clone(&self.tvar);
2780 let v = value.clone();
2781 stm::atomically(move |tx| tvar.write(tx, v.clone()));
2782 }
2783 self.version
2784 .fetch_add(1, std::sync::atomic::Ordering::Release);
2785 }
2786 pub fn version(&self) -> u64 {
2788 self.version.load(std::sync::atomic::Ordering::Acquire)
2789 }
2790}
2791#[cfg(not(target_arch = "wasm32"))]
2792pub fn transact_pair<A, B, F>(state_a: &State<A>, state_b: &State<B>, f: F)
2793where
2794 A: Clone + Send + Sync + 'static,
2795 B: Clone + Send + Sync + 'static,
2796 F: Fn(&A, &B) -> (A, B),
2797{
2798 let tvar_a = Arc::clone(&state_a.tvar);
2799 let tvar_b = Arc::clone(&state_b.tvar);
2800 let (new_a, new_b) = stm::atomically(move |tx| {
2801 let a = tvar_a.read(tx)?;
2802 let b = tvar_b.read(tx)?;
2803 let (na, nb) = f(&a, &b);
2804 tvar_a.write(tx, na.clone())?;
2805 tvar_b.write(tx, nb.clone())?;
2806 Ok((na, nb))
2807 });
2808 state_a.swap.store(Arc::new(new_a.clone()));
2809 state_b.swap.store(Arc::new(new_b.clone()));
2810 state_a
2811 .version
2812 .fetch_add(1, std::sync::atomic::Ordering::Release);
2813 state_b
2814 .version
2815 .fetch_add(1, std::sync::atomic::Ordering::Release);
2816 let subs_a = Arc::clone(&state_a.subscribers);
2817 let subs_b = Arc::clone(&state_b.subscribers);
2818 if crate::is_batching() {
2819 crate::enqueue_batch_task(Box::new(move || {
2820 {
2821 let s = subs_a.lock().unwrap();
2822 for cb in s.iter() {
2823 cb(&new_a);
2824 }
2825 }
2826 {
2827 let s = subs_b.lock().unwrap();
2828 for cb in s.iter() {
2829 cb(&new_b);
2830 }
2831 }
2832 }));
2833 } else {
2834 {
2835 let s = subs_a.lock().unwrap();
2836 for cb in s.iter() {
2837 cb(&new_a);
2838 }
2839 }
2840 {
2841 let s = subs_b.lock().unwrap();
2842 for cb in s.iter() {
2843 cb(&new_b);
2844 }
2845 }
2846 }
2847}
2848use std::any::TypeId;
2849use std::sync::Mutex;
2850pub(crate) static ENVIRONMENT: OnceLock<
2852 Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
2853> = OnceLock::new();
2854pub trait EnvKey: 'static + Send + Sync {
2857 type Value: Clone + Send + Sync + 'static;
2859 fn default_value() -> Self::Value;
2861}
2862pub struct YggdrasilKey;
2864impl EnvKey for YggdrasilKey {
2865 type Value = YggdrasilTokens;
2866 fn default_value() -> Self::Value {
2867 default_tokens()
2868 }
2869}
2870#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2873pub enum Appearance {
2874 Light,
2875 Dark,
2876}
2877#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2879pub enum Orientation {
2880 Horizontal,
2881 Vertical,
2882}
2883#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2885pub enum Alignment {
2886 #[default]
2887 Center,
2888 Leading,
2889 Trailing,
2890 Top,
2891 Bottom,
2892}
2893#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2895pub enum Distribution {
2896 #[default]
2897 Fill,
2898 Center,
2899 Leading,
2900 Trailing,
2901 SpaceBetween,
2902 SpaceAround,
2903 SpaceEvenly,
2904}
2905#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2907pub struct Color {
2908 pub r: f32,
2909 pub g: f32,
2910 pub b: f32,
2911 pub a: f32,
2912}
2913impl Color {
2914 pub const BLACK: Color = Color {
2915 r: 0.0,
2916 g: 0.0,
2917 b: 0.0,
2918 a: 1.0,
2919 };
2920 pub const WHITE: Color = Color {
2921 r: 1.0,
2922 g: 1.0,
2923 b: 1.0,
2924 a: 1.0,
2925 };
2926 pub const TRANSPARENT: Color = Color {
2927 r: 0.0,
2928 g: 0.0,
2929 b: 0.0,
2930 a: 0.0,
2931 };
2932 pub const RED: Color = Color {
2933 r: 1.0,
2934 g: 0.0,
2935 b: 0.0,
2936 a: 1.0,
2937 };
2938 pub const GREEN: Color = Color {
2939 r: 0.0,
2940 g: 1.0,
2941 b: 0.0,
2942 a: 1.0,
2943 };
2944 pub const BLUE: Color = Color {
2945 r: 0.0,
2946 g: 0.0,
2947 b: 1.0,
2948 a: 1.0,
2949 };
2950 pub const VIKING_GOLD: Color = Color {
2951 r: 1.0,
2952 g: 0.84,
2953 b: 0.0,
2954 a: 1.0,
2955 };
2956 pub const MAGENTA_LIQUID: Color = Color {
2957 r: 1.0,
2958 g: 0.0,
2959 b: 1.0,
2960 a: 1.0,
2961 };
2962 pub const TACTICAL_OBSIDIAN: Color = Color {
2963 r: 0.05,
2964 g: 0.05,
2965 b: 0.07,
2966 a: 1.0,
2967 };
2968 pub fn relative_luminance(&self) -> f32 {
2970 fn res(c: f32) -> f32 {
2971 if c <= 0.03928 {
2972 c / 12.92
2973 } else {
2974 ((c + 0.055) / 1.055).powf(2.4)
2975 }
2976 }
2977 0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
2978 }
2979 pub fn contrast_ratio(&self, other: &Color) -> f32 {
2981 let l1 = self.relative_luminance();
2982 let l2 = other.relative_luminance();
2983 if l1 > l2 {
2984 (l1 + 0.05) / (l2 + 0.05)
2985 } else {
2986 (l2 + 0.05) / (l1 + 0.05)
2987 }
2988 }
2989 pub const CYAN: Color = Color {
2990 r: 0.0,
2991 g: 1.0,
2992 b: 1.0,
2993 a: 1.0,
2994 };
2995 pub const YELLOW: Color = Color {
2996 r: 1.0,
2997 g: 1.0,
2998 b: 0.0,
2999 a: 1.0,
3000 };
3001 pub const MAGENTA: Color = Color {
3002 r: 1.0,
3003 g: 0.0,
3004 b: 1.0,
3005 a: 1.0,
3006 };
3007 pub const GRAY: Color = Color {
3008 r: 0.5,
3009 g: 0.5,
3010 b: 0.5,
3011 a: 1.0,
3012 };
3013 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
3015 Self { r, g, b, a }
3016 }
3017 pub fn as_array(&self) -> [f32; 4] {
3019 [self.r, self.g, self.b, self.a]
3020 }
3021}
3022impl View for Color {
3023 type Body = Never;
3024 fn body(self) -> Self::Body {
3025 unreachable!()
3026 }
3027 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
3028 renderer.fill_rect(rect, self.as_array());
3029 }
3030}
3031pub struct AppearanceKey;
3033impl EnvKey for AppearanceKey {
3034 type Value = Appearance;
3035 fn default_value() -> Self::Value {
3036 Appearance::Dark }
3038}
3039pub struct StyleResolver;
3041impl StyleResolver {
3042 pub fn color(key: &str) -> String {
3044 let tokens = Environment::<YggdrasilKey>::new().get();
3045 let appearance = Environment::<AppearanceKey>::new().get();
3046 let is_dark = appearance == Appearance::Dark;
3047 tokens
3048 .get_color(key, is_dark)
3049 .unwrap_or_else(|| "#FF00FF".to_string()) }
3051 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
3053 let tokens = Environment::<YggdrasilKey>::new().get();
3054 let appearance = Environment::<AppearanceKey>::new().get();
3055 let is_dark = appearance == Appearance::Dark;
3056 tokens.get(category, key, is_dark)
3057 }
3058}
3059pub fn default_tokens() -> YggdrasilTokens {
3061 let mut tokens = YggdrasilTokens::new();
3062 tokens.color.insert(
3064 "background".to_string(),
3065 TokenValue::Single {
3066 value: "#000000".to_string(), },
3068 );
3069 tokens.color.insert(
3070 "primary".to_string(),
3071 TokenValue::Single {
3072 value: "#00FFFF".to_string(), },
3074 );
3075 tokens.color.insert(
3076 "secondary".to_string(),
3077 TokenValue::Single {
3078 value: "#FF00FF".to_string(), },
3080 );
3081 tokens.color.insert(
3082 "surface".to_string(),
3083 TokenValue::Adaptive {
3084 light: "#FFFFFF".to_string(),
3085 dark: "#121212".to_string(),
3086 },
3087 );
3088 tokens.color.insert(
3089 "text".to_string(),
3090 TokenValue::Adaptive {
3091 light: "#000000".to_string(),
3092 dark: "#FFFFFF".to_string(),
3093 },
3094 );
3095 tokens.bifrost.insert(
3097 "blur".to_string(),
3098 TokenValue::Single {
3099 value: "25.0".to_string(),
3100 },
3101 );
3102 tokens.bifrost.insert(
3103 "saturation".to_string(),
3104 TokenValue::Single {
3105 value: "1.2".to_string(),
3106 },
3107 );
3108 tokens.bifrost.insert(
3109 "opacity".to_string(),
3110 TokenValue::Single {
3111 value: "0.65".to_string(),
3112 },
3113 );
3114 tokens.gungnir.insert(
3116 "intensity".to_string(),
3117 TokenValue::Single {
3118 value: "1.0".to_string(),
3119 },
3120 );
3121 tokens.gungnir.insert(
3122 "radius".to_string(),
3123 TokenValue::Single {
3124 value: "15.0".to_string(),
3125 },
3126 );
3127 tokens.mjolnir.insert(
3129 "clip_angle".to_string(),
3130 TokenValue::Single {
3131 value: "12.0".to_string(),
3132 },
3133 );
3134 tokens.mjolnir.insert(
3135 "border_width".to_string(),
3136 TokenValue::Single {
3137 value: "2.0".to_string(),
3138 },
3139 );
3140 tokens.anim.insert(
3142 "stiffness".to_string(),
3143 TokenValue::Single {
3144 value: "170.0".to_string(),
3145 },
3146 );
3147 tokens.anim.insert(
3148 "damping".to_string(),
3149 TokenValue::Single {
3150 value: "26.0".to_string(),
3151 },
3152 );
3153 tokens.anim.insert(
3154 "mass".to_string(),
3155 TokenValue::Single {
3156 value: "1.0".to_string(),
3157 },
3158 );
3159 tokens.accessibility.insert(
3161 "reduce_motion".to_string(),
3162 TokenValue::Single {
3163 value: "false".to_string(),
3164 },
3165 );
3166 tokens
3167}
3168pub struct Environment<K: EnvKey> {
3170 _marker: std::marker::PhantomData<K>,
3171}
3172impl<K: EnvKey> Default for Environment<K> {
3173 fn default() -> Self {
3174 Self::new()
3175 }
3176}
3177impl<K: EnvKey> Environment<K> {
3178 pub fn new() -> Self {
3180 Self {
3181 _marker: std::marker::PhantomData,
3182 }
3183 }
3184 pub fn get(&self) -> K::Value {
3186 if let Some(env_store) = ENVIRONMENT.get() {
3187 let env_lock = env_store.lock().unwrap();
3188 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
3189 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
3190 return typed_val.clone();
3191 } else {
3192 log::warn!(
3193 "Environment: Downcast failed for key type {:?}",
3194 std::any::type_name::<K>()
3195 );
3196 }
3197 } else {
3198 log::debug!(
3199 "Environment: Key not found: {:?}. Returning default.",
3200 std::any::type_name::<K>()
3201 );
3202 }
3203 } else {
3204 log::debug!(
3205 "Environment: Store not initialized. Key: {:?}. Returning default.",
3206 std::any::type_name::<K>()
3207 );
3208 }
3209 K::default_value()
3210 }
3211}
3212pub mod env {
3214 pub fn insert<K: super::EnvKey>(value: K::Value) {
3216 let store = super::ENVIRONMENT
3217 .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
3218 let mut env_map = store.lock().unwrap();
3219 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
3220 }
3221 pub fn remove<K: super::EnvKey>() {
3223 if let Some(store) = super::ENVIRONMENT.get() {
3224 let mut env_map = store.lock().unwrap();
3225 env_map.remove(&std::any::TypeId::of::<K>());
3226 }
3227 }
3228}
3229#[derive(Debug, Clone, Copy, PartialEq)]
3232pub struct Size {
3233 pub width: f32,
3234 pub height: f32,
3235}
3236
3237impl Size {
3238 pub const ZERO: Self = Self {
3239 width: 0.0,
3240 height: 0.0,
3241 };
3242
3243 pub fn new(width: f32, height: f32) -> Self {
3244 Self { width, height }
3245 }
3246}
3247
3248#[derive(Debug, Clone, Copy, PartialEq)]
3250pub struct EdgeInsets {
3251 pub top: f32,
3252 pub leading: f32,
3253 pub bottom: f32,
3254 pub trailing: f32,
3255}
3256
3257impl EdgeInsets {
3258 pub fn all(value: f32) -> Self {
3260 Self {
3261 top: value,
3262 leading: value,
3263 bottom: value,
3264 trailing: value,
3265 }
3266 }
3267
3268 pub fn vertical(value: f32) -> Self {
3270 Self {
3271 top: value,
3272 leading: 0.0,
3273 bottom: value,
3274 trailing: 0.0,
3275 }
3276 }
3277
3278 pub fn horizontal(value: f32) -> Self {
3280 Self {
3281 top: 0.0,
3282 leading: value,
3283 bottom: 0.0,
3284 trailing: value,
3285 }
3286 }
3287}
3288
3289#[derive(Debug, Clone, Copy, PartialEq)]
3291pub struct FrameModifier {
3292 pub width: Option<f32>,
3293 pub height: Option<f32>,
3294}
3295
3296impl Default for FrameModifier {
3297 fn default() -> Self {
3298 Self::new()
3299 }
3300}
3301
3302impl FrameModifier {
3303 pub fn new() -> Self {
3304 Self {
3305 width: None,
3306 height: None,
3307 }
3308 }
3309
3310 pub fn width(mut self, width: f32) -> Self {
3311 self.width = Some(width);
3312 self
3313 }
3314
3315 pub fn height(mut self, height: f32) -> Self {
3316 self.height = Some(height);
3317 self
3318 }
3319
3320 pub fn size(mut self, width: f32, height: f32) -> Self {
3321 self.width = Some(width);
3322 self.height = Some(height);
3323 self
3324 }
3325}
3326
3327impl ViewModifier for FrameModifier {
3328 fn modify<V: View>(self, content: V) -> impl View {
3329 ModifiedView::new(content, self)
3330 }
3331}
3332
3333#[derive(Debug, Clone, Copy, PartialEq)]
3335pub struct FlexModifier {
3336 pub weight: f32,
3337}
3338
3339impl ViewModifier for FlexModifier {
3340 fn modify<V: View>(self, content: V) -> impl View {
3341 ModifiedView::new(content, self)
3342 }
3343
3344 fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
3345 self.weight
3346 }
3347}
3348
3349#[derive(Debug, Clone, Copy, PartialEq)]
3351pub struct OffsetModifier {
3352 pub x: f32,
3353 pub y: f32,
3354}
3355
3356impl OffsetModifier {
3357 pub fn new(x: f32, y: f32) -> Self {
3358 Self { x, y }
3359 }
3360}
3361
3362impl ViewModifier for OffsetModifier {
3363 fn modify<V: View>(self, content: V) -> impl View {
3364 ModifiedView::new(content, self)
3365 }
3366}
3367
3368#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3370pub struct ZIndexModifier {
3371 pub z_index: i32,
3372}
3373
3374impl ZIndexModifier {
3375 pub fn new(z_index: i32) -> Self {
3376 Self { z_index }
3377 }
3378}
3379
3380impl ViewModifier for ZIndexModifier {
3381 fn modify<V: View>(self, content: V) -> impl View {
3382 ModifiedView::new(content, self)
3383 }
3384}
3385
3386#[derive(Debug, Clone, Copy, PartialEq, Default)]
3388pub struct LayoutConstraints {
3389 pub min_width: Option<f32>,
3390 pub max_width: Option<f32>,
3391 pub min_height: Option<f32>,
3392 pub max_height: Option<f32>,
3393}
3394
3395#[derive(Debug, Clone, Copy, PartialEq)]
3397pub struct LayoutModifier {
3398 pub constraints: LayoutConstraints,
3399}
3400
3401impl LayoutModifier {
3402 pub fn new(constraints: LayoutConstraints) -> Self {
3403 Self { constraints }
3404 }
3405}
3406
3407impl ViewModifier for LayoutModifier {
3408 fn modify<V: View>(self, content: V) -> impl View {
3409 ModifiedView::new(content, self)
3410 }
3411}
3412
3413#[derive(Debug, Clone, Copy, PartialEq)]
3415pub struct SafeAreaModifier {
3416 pub ignores: bool,
3417}
3418
3419impl ViewModifier for SafeAreaModifier {
3420 fn modify<V: View>(self, content: V) -> impl View {
3421 ModifiedView::new(content, self)
3422 }
3423}
3424
3425#[derive(Debug, Clone, Copy, PartialEq)]
3427pub struct ElevationModifier {
3428 pub level: f32,
3429}
3430
3431impl ViewModifier for ElevationModifier {
3432 fn modify<V: View>(self, content: V) -> impl View {
3433 ModifiedView::new(content, self)
3434 }
3435
3436 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
3437 if self.level > 0.0 {
3438 let radius = self.level * 2.0;
3439 let offset_y = self.level * 0.5;
3440 let shadow_color = [0.0, 0.0, 0.0, 0.3];
3441 renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
3442 view.render(renderer, rect);
3443 renderer.pop_shadow();
3444 } else {
3445 view.render(renderer, rect);
3446 }
3447 }
3448}
3449
3450pub mod layout {
3452 use super::*;
3453
3454 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3457 pub struct LayoutKey {
3458 pub view_hash: u64,
3459 pub generation: u64,
3460 }
3461
3462 pub struct LayoutCache {
3464 pub safe_area: SafeArea,
3465 size_cache: HashMap<(u64, u32, u32), Size>, generation: u64,
3470 }
3471
3472 impl Default for LayoutCache {
3473 fn default() -> Self {
3474 Self::new()
3475 }
3476 }
3477
3478 impl LayoutCache {
3479 pub fn new() -> Self {
3480 Self {
3481 safe_area: SafeArea::default(),
3482 size_cache: HashMap::new(),
3483 generation: 0,
3484 }
3485 }
3486
3487 pub fn generation(&self) -> u64 {
3489 self.generation
3490 }
3491
3492 pub fn invalidate(&mut self) {
3496 self.generation = self.generation.wrapping_add(1);
3497 }
3498
3499 pub fn is_valid(&self, key: LayoutKey, current_gen: u64) -> bool {
3502 key.generation == current_gen && key.generation == self.generation
3503 }
3504
3505 pub fn clear(&mut self) {
3506 self.safe_area = SafeArea::default();
3507 self.size_cache.clear();
3508 }
3509
3510 pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
3511 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
3512 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
3513 self.size_cache.get(&(view_hash, pw, ph)).copied()
3514 }
3515
3516 pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: Size) {
3517 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
3518 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
3519 self.size_cache.insert((view_hash, pw, ph), size);
3520 }
3521
3522 pub fn invalidate_view(&mut self, view_hash: u64) {
3524 self.size_cache.retain(|&(hash, _, _), _| hash != view_hash);
3525 }
3526 }
3527
3528 #[derive(Debug, Clone, Copy, PartialEq)]
3530 pub struct SizeProposal {
3531 pub width: Option<f32>,
3532 pub height: Option<f32>,
3533 }
3534
3535 impl SizeProposal {
3536 pub fn unspecified() -> Self {
3537 Self {
3538 width: None,
3539 height: None,
3540 }
3541 }
3542
3543 pub fn width(width: f32) -> Self {
3544 Self {
3545 width: Some(width),
3546 height: None,
3547 }
3548 }
3549
3550 pub fn height(height: f32) -> Self {
3551 Self {
3552 width: None,
3553 height: Some(height),
3554 }
3555 }
3556
3557 pub fn tight(width: f32, height: f32) -> Self {
3558 Self {
3559 width: Some(width),
3560 height: Some(height),
3561 }
3562 }
3563
3564 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
3565 Self { width, height }
3566 }
3567 }
3568
3569 pub trait LayoutView: Send {
3571 fn size_that_fits(
3573 &self,
3574 proposal: SizeProposal,
3575 subviews: &[&dyn LayoutView],
3576 cache: &mut LayoutCache,
3577 ) -> Size;
3578
3579 fn place_subviews(
3581 &self,
3582 bounds: Rect,
3583 subviews: &mut [&mut dyn LayoutView],
3584 cache: &mut LayoutCache,
3585 );
3586
3587 fn flex_weight(&self) -> f32 {
3589 0.0
3590 }
3591
3592 fn debug_layout(&self, indent: usize) -> String {
3595 let prefix = " ".repeat(indent);
3596 format!("{}LayoutView", prefix)
3597 }
3598 }
3599 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
3601 pub struct EdgeInsets {
3602 pub top: f32,
3603 pub leading: f32,
3604 pub bottom: f32,
3605 pub trailing: f32,
3606 }
3607
3608 impl EdgeInsets {
3609 pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
3610 Self {
3611 top,
3612 leading,
3613 bottom,
3614 trailing,
3615 }
3616 }
3617
3618 pub fn all(value: f32) -> Self {
3619 Self {
3620 top: value,
3621 leading: value,
3622 bottom: value,
3623 trailing: value,
3624 }
3625 }
3626 }
3627
3628 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
3630 pub struct SafeArea {
3631 pub insets: EdgeInsets,
3632 }
3633
3634 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
3636 pub struct Rect {
3637 pub x: f32,
3638 pub y: f32,
3639 pub width: f32,
3640 pub height: f32,
3641 }
3642
3643 impl Rect {
3644 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
3645 Self {
3646 x,
3647 y,
3648 width,
3649 height,
3650 }
3651 }
3652
3653 pub fn inset(&self, amount: f32) -> Self {
3654 Self {
3655 x: self.x + amount,
3656 y: self.y + amount,
3657 width: (self.width - amount * 2.0).max(0.0),
3658 height: (self.height - amount * 2.0).max(0.0),
3659 }
3660 }
3661
3662 pub fn offset(&self, dx: f32, dy: f32) -> Self {
3663 Self {
3664 x: self.x + dx,
3665 y: self.y + dy,
3666 ..*self
3667 }
3668 }
3669
3670 pub fn zero() -> Self {
3671 Self {
3672 x: 0.0,
3673 y: 0.0,
3674 width: 0.0,
3675 height: 0.0,
3676 }
3677 }
3678
3679 pub fn contains(&self, x: f32, y: f32) -> bool {
3680 x >= self.x && x <= self.x + self.width && y >= self.y && y <= self.y + self.height
3681 }
3682
3683 pub fn size(&self) -> Size {
3684 Size {
3685 width: self.width,
3686 height: self.height,
3687 }
3688 }
3689
3690 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
3692 if n == 0 {
3693 return vec![];
3694 }
3695 let item_width = self.width / n as f32;
3696 (0..n)
3697 .map(|i| Rect {
3698 x: self.x + i as f32 * item_width,
3699 y: self.y,
3700 width: item_width,
3701 height: self.height,
3702 })
3703 .collect()
3704 }
3705
3706 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
3708 if n == 0 {
3709 return vec![];
3710 }
3711 let item_height = self.height / n as f32;
3712 (0..n)
3713 .map(|i| Rect {
3714 x: self.x,
3715 y: self.y + i as f32 * item_height,
3716 width: self.width,
3717 height: item_height,
3718 })
3719 .collect()
3720 }
3721 }
3722}
3723
3724pub use layout::{LayoutCache, LayoutKey, LayoutView, Rect, SizeProposal};
3726pub mod agents;
3729pub mod animation;
3730pub mod gpu;
3731pub mod material;
3732pub mod runtime;
3733pub mod scene_graph;
3734pub mod sdf_shadow;
3735
3736pub use scene_graph::{NodeId, bifrost_registry};
3737
3738pub trait AssetManager: Send + Sync {
3742 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
3744
3745 fn preload_image(&self, url: &str);
3747}
3748
3749#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
3751pub enum Event {
3752 PointerDown {
3753 x: f32,
3754 y: f32,
3755 button: u32,
3756 },
3757 PointerUp {
3758 x: f32,
3759 y: f32,
3760 button: u32,
3761 },
3762 PointerMove {
3763 x: f32,
3764 y: f32,
3765 },
3766 PointerClick {
3767 x: f32,
3768 y: f32,
3769 button: u32,
3770 },
3771 PointerEnter,
3772 PointerLeave,
3773 PointerWheel {
3776 x: f32,
3777 y: f32,
3778 delta_x: f32,
3779 delta_y: f32,
3780 },
3781 PointerDoubleClick {
3783 x: f32,
3784 y: f32,
3785 button: u32,
3786 },
3787 DragStart {
3789 x: f32,
3790 y: f32,
3791 button: u32,
3792 },
3793 DragMove {
3795 x: f32,
3796 y: f32,
3797 },
3798 DragEnd {
3800 x: f32,
3801 y: f32,
3802 },
3803 KeyDown {
3804 key: String,
3805 },
3806 KeyUp {
3807 key: String,
3808 },
3809 FocusIn,
3811 FocusOut,
3813 Copy,
3815 Cut,
3817 Paste(String),
3819 Ime(String),
3821 TouchStart {
3823 x: f32,
3824 y: f32,
3825 touch_id: u64,
3826 },
3827 TouchMove {
3829 x: f32,
3830 y: f32,
3831 touch_id: u64,
3832 },
3833 TouchEnd {
3835 x: f32,
3836 y: f32,
3837 touch_id: u64,
3838 },
3839}
3840
3841impl Event {
3842 pub fn name(&self) -> &'static str {
3844 match self {
3845 Self::PointerDown { .. } => "pointerdown",
3846 Self::PointerUp { .. } => "pointerup",
3847 Self::PointerMove { .. } => "pointermove",
3848 Self::PointerClick { .. } => "pointerclick",
3849 Self::PointerEnter => "pointerenter",
3850 Self::PointerLeave => "pointerleave",
3851 Self::PointerWheel { .. } => "pointerwheel",
3852 Self::PointerDoubleClick { .. } => "pointerdoubleclick",
3853 Self::DragStart { .. } => "dragstart",
3854 Self::DragMove { .. } => "dragmove",
3855 Self::DragEnd { .. } => "dragend",
3856 Self::KeyDown { .. } => "keydown",
3857 Self::KeyUp { .. } => "keyup",
3858 Self::FocusIn => "focusin",
3859 Self::FocusOut => "focusout",
3860 Self::Copy => "copy",
3861 Self::Cut => "cut",
3862 Self::Paste(_) => "paste",
3863 Self::Ime(_) => "ime",
3864 Self::TouchStart { .. } => "touchstart",
3865 Self::TouchMove { .. } => "touchmove",
3866 Self::TouchEnd { .. } => "touchend",
3867 }
3868 }
3869}
3870
3871#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3873pub enum EventResponse {
3874 Handled,
3875 Ignored,
3876}
3877
3878pub struct DefaultAssetManager {
3880 cache: AssetCache,
3881}
3882type AssetCache = Arc<arc_swap::ArcSwap<HashMap<String, AssetState<Arc<Vec<u8>>>>>>;
3883
3884impl Default for DefaultAssetManager {
3885 fn default() -> Self {
3886 Self::new()
3887 }
3888}
3889
3890impl DefaultAssetManager {
3891 pub fn new() -> Self {
3892 Self {
3893 cache: Arc::new(arc_swap::ArcSwap::from_pointee(HashMap::new())),
3894 }
3895 }
3896}
3897
3898impl AssetManager for DefaultAssetManager {
3899 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
3900 if let Some(state) = self.cache.load().get(url) {
3901 return state.clone();
3902 }
3903
3904 self.cache.rcu(|map| {
3905 let mut m = (**map).clone();
3906 m.entry(url.to_string()).or_insert(AssetState::Loading);
3907 m
3908 });
3909 AssetState::Loading
3910 }
3911
3912 fn preload_image(&self, _url: &str) {}
3913}
3914
3915use std::future::Future;
3916
3917pub struct Suspense<T: Clone + Send + Sync + 'static> {
3920 inner: State<AssetState<T>>,
3921}
3922
3923impl<T: Clone + Send + Sync + 'static> Default for Suspense<T> {
3924 fn default() -> Self {
3925 Self::new()
3926 }
3927}
3928
3929impl<T: Clone + Send + Sync + 'static> Suspense<T> {
3930 pub fn new() -> Self {
3931 Self {
3932 inner: State::new(AssetState::Loading),
3933 }
3934 }
3935
3936 pub fn new_async<F>(future: F) -> Self
3937 where
3938 F: Future<Output = Result<T, String>> + Send + 'static,
3939 {
3940 let suspense = Self::new();
3941 let suspense_clone = suspense.clone();
3942
3943 #[cfg(not(target_arch = "wasm32"))]
3944 {
3945 if let Ok(handle) = tokio::runtime::Handle::try_current() {
3947 handle.spawn(async move {
3948 let result = future.await;
3949 match result {
3950 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3951 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3952 }
3953 });
3954 } else {
3955 std::thread::spawn(move || {
3956 let rt = tokio::runtime::Builder::new_current_thread()
3957 .enable_all()
3958 .build()
3959 .unwrap();
3960 rt.block_on(async {
3961 let result = future.await;
3962 match result {
3963 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3964 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3965 }
3966 });
3967 });
3968 }
3969 }
3970 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
3971 {
3972 wasm_bindgen_futures::spawn_local(async move {
3973 let result = future.await;
3974 match result {
3975 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3976 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3977 }
3978 });
3979 }
3980
3981 suspense
3982 }
3983
3984 pub fn ready(value: T) -> Self {
3985 Self {
3986 inner: State::new(AssetState::Ready(value)),
3987 }
3988 }
3989
3990 pub fn error(message: impl Into<String>) -> Self {
3991 Self {
3992 inner: State::new(AssetState::Error(message.into())),
3993 }
3994 }
3995
3996 pub fn get(&self) -> AssetState<T> {
3997 self.inner.get()
3998 }
3999
4000 pub fn get_ref(&self) -> AssetState<T> {
4001 self.inner.get()
4002 }
4003
4004 pub fn is_loading(&self) -> bool {
4005 matches!(self.get(), AssetState::Loading)
4006 }
4007
4008 pub fn is_ready(&self) -> bool {
4009 matches!(self.get(), AssetState::Ready(_))
4010 }
4011
4012 pub fn is_error(&self) -> bool {
4013 matches!(self.get(), AssetState::Error(_))
4014 }
4015
4016 pub fn ready_value(&self) -> Option<T> {
4017 match self.get() {
4018 AssetState::Ready(value) => Some(value),
4019 _ => None,
4020 }
4021 }
4022
4023 pub fn error_message(&self) -> Option<String> {
4024 match self.get() {
4025 AssetState::Error(message) => Some(message),
4026 _ => None,
4027 }
4028 }
4029
4030 pub fn subscribe<F: Fn(&AssetState<T>) + Send + Sync + 'static>(&self, callback: F) {
4031 self.inner.subscribe(callback)
4032 }
4033
4034 pub fn inner_state(&self) -> &State<AssetState<T>> {
4035 &self.inner
4036 }
4037}
4038
4039impl<T: Clone + Send + Sync + 'static> Clone for Suspense<T> {
4040 fn clone(&self) -> Self {
4041 Self {
4042 inner: self.inner.clone(),
4043 }
4044 }
4045}
4046
4047impl<T: Clone + Send + Sync + 'static> From<T> for Suspense<T> {
4048 fn from(value: T) -> Self {
4049 Self::ready(value)
4050 }
4051}
4052
4053impl<T: Clone + Send + Sync + 'static> From<Result<T, String>> for Suspense<T> {
4054 fn from(result: Result<T, String>) -> Self {
4055 match result {
4056 Ok(value) => Self::ready(value),
4057 Err(error) => Self::error(error),
4058 }
4059 }
4060}
4061
4062#[cfg(test)]
4063mod phase1_test;
4064
4065#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4067pub enum BerserkerMode {
4068 Normal,
4069 Rage, Frenzy, GodMode, }
4073
4074pub trait Seer: Send + Sync {
4077 fn predict(&self, context: &str) -> String;
4079 fn whispers(&self) -> Vec<String>;
4081}