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