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 fn set_material(&mut self, _material: crate::material::DrawMaterial) {}
2162 fn current_material(&self) -> crate::material::DrawMaterial {
2164 crate::material::DrawMaterial::Opaque
2165 }
2166}
2167
2168pub mod accessibility {
2170 pub fn relative_luminance(color: [f32; 4]) -> f32 {
2172 let f = |c: f32| {
2173 if c <= 0.03928 {
2174 c / 12.92
2175 } else {
2176 ((c + 0.055) / 1.055).powf(2.4)
2177 }
2178 };
2179 0.2126 * f(color[0]) + 0.7152 * f(color[1]) + 0.0722 * f(color[2])
2180 }
2181
2182 pub fn contrast_ratio(c1: [f32; 4], c2: [f32; 4]) -> f32 {
2184 let l1 = relative_luminance(c1);
2185 let l2 = relative_luminance(c2);
2186 let (light, dark) = if l1 > l2 { (l1, l2) } else { (l2, l1) };
2187 (light + 0.05) / (dark + 0.05)
2188 }
2189}
2190#[derive(
2192 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
2193)]
2194pub enum RenderTier {
2195 Tier1GPU = 0,
2197 Tier2GPU = 1,
2199 Tier3Fallback = 2,
2201}
2202use bytemuck::{Pod, Zeroable};
2206#[repr(C)]
2208#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
2209pub struct ColorTheme {
2210 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
2212 pub glass_base: [f32; 4],
2213 pub glass_edge: [f32; 4],
2214 pub rune_glow: [f32; 4],
2215 pub ember_core: [f32; 4],
2216 pub background_deep: [f32; 4],
2217 pub mani_glow: [f32; 4], pub glass_blur_strength: f32,
2219 pub shatter_edge_width: f32,
2220 pub neon_bloom_radius: f32,
2221 pub rune_opacity: f32,
2222}
2223impl ColorTheme {
2224 pub fn asgard() -> Self {
2226 Self {
2227 primary_neon: [0.0, 1.0, 0.95, 1.2],
2228 shatter_neon: [1.0, 0.0, 0.75, 1.5],
2229 glass_base: [0.04, 0.04, 0.06, 0.82],
2230 glass_edge: [0.0, 0.45, 0.55, 0.6],
2231 rune_glow: [0.75, 0.98, 1.0, 0.9],
2232 ember_core: [0.95, 0.12, 0.12, 1.0],
2233 background_deep: [0.01, 0.01, 0.03, 1.0],
2234 mani_glow: [0.7, 0.9, 1.0, 0.05],
2235 glass_blur_strength: 0.6,
2236 shatter_edge_width: 1.8,
2237 neon_bloom_radius: 0.022,
2238 rune_opacity: 0.55,
2239 }
2240 }
2241
2242 pub fn midgard() -> Self {
2244 Self {
2245 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],
2251 background_deep: [0.05, 0.05, 0.07, 1.0],
2252 mani_glow: [0.0, 0.0, 0.0, 0.0], glass_blur_strength: 0.0, shatter_edge_width: 1.0,
2255 neon_bloom_radius: 0.0,
2256 rune_opacity: 0.0,
2257 }
2258 }
2259
2260 pub fn cyberpunk_viking() -> Self {
2261 Self::asgard()
2262 }
2263 pub fn vibrant_glass() -> Self {
2264 Self {
2265 primary_neon: [0.0, 1.0, 0.95, 1.2],
2266 shatter_neon: [1.0, 0.0, 0.75, 1.5],
2267 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],
2270 ember_core: [1.0, 0.4, 0.1, 1.0],
2271 background_deep: [0.05, 0.05, 0.1, 1.0],
2272 mani_glow: [0.7, 0.9, 1.0, 0.05],
2273 glass_blur_strength: 0.9,
2274 shatter_edge_width: 1.8,
2275 neon_bloom_radius: 0.022,
2276 rune_opacity: 0.55,
2277 }
2278 }
2279}
2280impl Default for ColorTheme {
2281 fn default() -> Self {
2282 Self::vibrant_glass()
2283 }
2284}
2285#[repr(C)]
2287#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
2288pub struct SceneUniforms {
2289 pub view: glam::Mat4,
2290 pub proj: glam::Mat4,
2291 pub time: f32,
2292 pub delta_time: f32,
2293 pub resolution: [f32; 2],
2294 pub mouse: [f32; 2],
2295 pub mouse_velocity: [f32; 2],
2296 pub shatter_origin: [f32; 2],
2297 pub shatter_time: f32,
2298 pub shatter_force: f32,
2299 pub berzerker_rage: f32,
2300 pub berzerker_mode: u32,
2301 pub scroll_offset: f32,
2302 pub scale_factor: f32,
2303 pub scene_type: u32,
2304 pub _pad: [f32; 3], }
2306
2307pub const SCENE_AURORA: u32 = 0;
2308pub const SCENE_VOID: u32 = 1;
2309pub const SCENE_NEBULA: u32 = 2;
2310pub const SCENE_GLITCH: u32 = 3;
2311pub const SCENE_YGGDRASIL: u32 = 4;
2312
2313impl SceneUniforms {
2314 pub fn new(width: f32, height: f32) -> Self {
2315 Self {
2316 view: glam::Mat4::IDENTITY,
2317 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
2318 time: 0.0,
2319 delta_time: 0.016,
2320 resolution: [width, height],
2321 mouse: [0.5, 0.5],
2322 mouse_velocity: [0.0, 0.0],
2323 shatter_origin: [0.5, 0.5],
2324 shatter_time: -100.0,
2325 shatter_force: 0.0,
2326 berzerker_rage: 0.0,
2327 berzerker_mode: 0,
2328 scroll_offset: 0.0,
2329 scale_factor: 1.0,
2330 scene_type: SCENE_AURORA,
2331 _pad: [0.0; 3],
2332 }
2333 }
2334}
2335#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
2337pub struct Mesh {
2338 pub vertices: Vec<[f32; 3]>,
2339 pub normals: Vec<[f32; 3]>,
2340 pub indices: Vec<u32>,
2341}
2342impl Mesh {
2343 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
2344 let mut cursor = std::io::Cursor::new(data);
2345 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
2346 Ok((Vec::new(), Default::default()))
2347 })?;
2348 let mut meshes = Vec::new();
2349 for m in models {
2350 let mesh = m.mesh;
2351 let vertices: Vec<[f32; 3]> = mesh
2352 .positions
2353 .chunks(3)
2354 .map(|c| [c[0], c[1], c[2]])
2355 .collect();
2356 let normals = if mesh.normals.is_empty() {
2357 vec![[0.0, 0.0, 1.0]; vertices.len()]
2358 } else {
2359 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
2360 };
2361 meshes.push(Mesh {
2362 vertices,
2363 normals,
2364 indices: mesh.indices,
2365 });
2366 }
2367 Ok(meshes)
2368 }
2369 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
2370 let mut cursor = std::io::Cursor::new(data);
2371 let stl = stl_io::read_stl(&mut cursor)?;
2372 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
2373 let mut indices = Vec::new();
2374 for face in stl.faces {
2375 indices.push(face.vertices[0] as u32);
2376 indices.push(face.vertices[1] as u32);
2377 indices.push(face.vertices[2] as u32);
2378 }
2379 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
2380 Ok(Mesh {
2381 vertices,
2382 normals,
2383 indices,
2384 })
2385 }
2386}
2387pub trait FrameRenderer<E = ()>: Renderer {
2390 fn begin_frame(&mut self) -> E;
2391 fn render_frame(&mut self) {
2392 }
2394 fn end_frame(&mut self, encoder: E);
2395}
2396use std::sync::Arc;
2397type SubscriberList<T> = Arc<std::sync::Mutex<Vec<Box<dyn Fn(&T) + Send + Sync>>>>;
2398#[derive(Clone)]
2400pub struct State<T: Clone + Send + Sync + 'static> {
2401 swap: Arc<arc_swap::ArcSwap<T>>,
2402 metadata_swap: Arc<arc_swap::ArcSwap<Option<agents::MutationMetadata>>>,
2403 #[cfg(not(target_arch = "wasm32"))]
2404 tvar: Arc<stm::TVar<T>>,
2405 #[cfg(not(target_arch = "wasm32"))]
2406 metadata_tvar: Arc<stm::TVar<Option<agents::MutationMetadata>>>,
2407 subscribers: SubscriberList<T>,
2408 version: Arc<std::sync::atomic::AtomicU64>,
2409 resolution: agents::ConflictResolution,
2410}
2411impl<T: Clone + Send + Sync + 'static> State<T> {
2412 pub fn new(value: T) -> Self {
2414 #[cfg(not(target_arch = "wasm32"))]
2415 let tvar = Arc::new(stm::TVar::new(value.clone()));
2416 #[cfg(not(target_arch = "wasm32"))]
2417 let metadata_tvar = Arc::new(stm::TVar::new(None));
2418 Self {
2419 swap: Arc::new(arc_swap::ArcSwap::from_pointee(value)),
2420 metadata_swap: Arc::new(arc_swap::ArcSwap::new(Arc::new(None))),
2421 #[cfg(not(target_arch = "wasm32"))]
2422 tvar,
2423 #[cfg(not(target_arch = "wasm32"))]
2424 metadata_tvar,
2425 subscribers: Arc::new(std::sync::Mutex::new(Vec::new())),
2426 version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
2427 resolution: agents::ConflictResolution::default(),
2428 }
2429 }
2430 pub fn with_resolution(mut self, resolution: agents::ConflictResolution) -> Self {
2432 self.resolution = resolution;
2433 self
2434 }
2435 pub fn get(&self) -> T {
2437 (**self.swap.load()).clone()
2438 }
2439 pub fn set(&self, value: T) {
2441 #[cfg(not(target_arch = "wasm32"))]
2442 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
2443 let new_meta = agents::get_current_mutation_metadata();
2444 let existing_meta = self.metadata_tvar.read(tx)?;
2445 let mut skip = false;
2446 if self.resolution == agents::ConflictResolution::PriorityWins
2447 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
2448 && new_m.priority < old_m.priority
2449 {
2450 skip = true;
2451 }
2452 if !skip {
2453 self.tvar.write(tx, value.clone())?;
2454 self.metadata_tvar.write(tx, new_meta)?;
2455 Ok((false, value.clone(), new_meta))
2456 } else {
2457 Ok((true, self.tvar.read(tx)?, existing_meta))
2458 }
2459 });
2460 #[cfg(target_arch = "wasm32")]
2461 let (was_skipped, final_val, final_meta) =
2462 (false, value, agents::get_current_mutation_metadata());
2463 if was_skipped {
2464 if let (Some(new_m), Some(old_m)) =
2465 (agents::get_current_mutation_metadata(), final_meta)
2466 {
2467 agents::notify_conflict(agents::ConflictEvent {
2468 agent_id: new_m.agent_id,
2469 priority: new_m.priority,
2470 existing_agent_id: old_m.agent_id,
2471 existing_priority: old_m.priority,
2472 timestamp_ms: new_m.timestamp_ms,
2473 });
2474 }
2475 return;
2476 }
2477 self.swap.store(Arc::new(final_val.clone()));
2478 self.metadata_swap.store(Arc::new(final_meta));
2479 self.version
2480 .fetch_add(1, std::sync::atomic::Ordering::Release);
2481 let subs = Arc::clone(&self.subscribers);
2482 if crate::is_batching() {
2483 crate::enqueue_batch_task(Box::new(move || {
2484 let s = subs.lock().unwrap();
2485 for cb in s.iter() {
2486 cb(&final_val);
2487 }
2488 }));
2489 } else {
2490 let s = subs.lock().unwrap();
2491 for cb in s.iter() {
2492 cb(&final_val);
2493 }
2494 }
2495 }
2496 pub fn mutate<F: Fn(&T) -> T>(&self, f: F) {
2497 #[cfg(not(target_arch = "wasm32"))]
2498 {
2499 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
2500 let new_meta = agents::get_current_mutation_metadata();
2501 let existing_meta = self.metadata_tvar.read(tx)?;
2502 let mut skip = false;
2503 if self.resolution == agents::ConflictResolution::PriorityWins
2504 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
2505 && new_m.priority < old_m.priority
2506 {
2507 skip = true;
2508 }
2509 if !skip {
2510 let current = self.tvar.read(tx)?;
2511 let next = f(¤t);
2512 self.tvar.write(tx, next.clone())?;
2513 self.metadata_tvar.write(tx, new_meta)?;
2514 Ok((false, next, new_meta))
2515 } else {
2516 Ok((true, self.tvar.read(tx)?, existing_meta))
2517 }
2518 });
2519 if was_skipped {
2520 if let (Some(new_m), Some(old_m)) =
2521 (agents::get_current_mutation_metadata(), final_meta)
2522 {
2523 agents::notify_conflict(agents::ConflictEvent {
2524 agent_id: new_m.agent_id,
2525 priority: new_m.priority,
2526 existing_agent_id: old_m.agent_id,
2527 existing_priority: old_m.priority,
2528 timestamp_ms: new_m.timestamp_ms,
2529 });
2530 }
2531 return;
2532 }
2533 self.swap.store(Arc::new(final_val.clone()));
2534 self.metadata_swap.store(Arc::new(final_meta));
2535 self.version
2536 .fetch_add(1, std::sync::atomic::Ordering::Release);
2537 let subs = Arc::clone(&self.subscribers);
2538 if crate::is_batching() {
2539 crate::enqueue_batch_task(Box::new(move || {
2540 let s = subs.lock().unwrap();
2541 for cb in s.iter() {
2542 cb(&final_val);
2543 }
2544 }));
2545 } else {
2546 let s = subs.lock().unwrap();
2547 for cb in s.iter() {
2548 cb(&final_val);
2549 }
2550 }
2551 }
2552 #[cfg(target_arch = "wasm32")]
2553 {
2554 self.set(f(&self.get()));
2555 }
2556 }
2557 pub fn version(&self) -> u64 {
2559 self.version.load(std::sync::atomic::Ordering::Acquire)
2560 }
2561 pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
2563 self.subscribers.lock().unwrap().push(Box::new(callback));
2564 }
2565}
2566use crate::runtime::NodeStateSnapshot;
2567use std::sync::OnceLock;
2568use std::sync::atomic::{AtomicBool, Ordering};
2569pub static SYSTEM_STATE: OnceLock<Arc<arc_swap::ArcSwap<KnowledgeState>>> = OnceLock::new();
2571#[cfg(not(target_arch = "wasm32"))]
2572static KNOWLEDGE_TVAR: OnceLock<stm::TVar<KnowledgeState>> = OnceLock::new();
2573static IS_BATCHING: AtomicBool = AtomicBool::new(false);
2574pub static IS_RENDERING: AtomicBool = AtomicBool::new(false);
2575pub static LAYOUT_DIRTY: AtomicBool = AtomicBool::new(false);
2576type BatchQueue = OnceLock<std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync>>>>;
2577static BATCH_QUEUE: BatchQueue = OnceLock::new();
2578static STATE_WRITE_MUTEX: std::sync::Mutex<()> = std::sync::Mutex::new(());
2581pub fn is_batching() -> bool {
2583 IS_BATCHING.load(Ordering::Acquire)
2584}
2585pub fn is_rendering() -> bool {
2587 IS_RENDERING.load(Ordering::Acquire)
2588}
2589pub fn begin_render_phase() {
2591 IS_RENDERING.store(true, Ordering::Release);
2592}
2593pub fn end_render_phase() {
2595 IS_RENDERING.store(false, Ordering::Release);
2596}
2597pub fn enqueue_batch_task(task: Box<dyn FnOnce() + Send + Sync>) {
2599 let mut queue = BATCH_QUEUE
2600 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
2601 .lock()
2602 .unwrap();
2603 queue.push(task);
2604}
2605pub fn batch<F: FnOnce()>(f: F) {
2609 if IS_BATCHING.swap(true, Ordering::AcqRel) {
2610 f();
2612 return;
2613 }
2614 f();
2615 IS_BATCHING.store(false, Ordering::Release);
2616 let mut queue = BATCH_QUEUE
2617 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
2618 .lock()
2619 .unwrap();
2620 let tasks: Vec<_> = queue.drain(..).collect();
2621 drop(queue);
2622 for task in tasks {
2623 task();
2624 }
2625}
2626pub fn get_system_state() -> Arc<arc_swap::ArcSwap<KnowledgeState>> {
2628 SYSTEM_STATE
2629 .get_or_init(|| Arc::new(arc_swap::ArcSwap::from_pointee(KnowledgeState::default())))
2630 .clone()
2631}
2632pub fn load_system_state() -> arc_swap::Guard<Arc<KnowledgeState>> {
2633 get_system_state().load()
2634}
2635pub fn update_system_state<F>(f: F)
2636where
2637 F: Fn(&KnowledgeState) -> KnowledgeState,
2638{
2639 let _lock = STATE_WRITE_MUTEX.lock().unwrap();
2640 if is_rendering() {
2641 log::warn!(
2642 "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2643 );
2644 }
2645 LAYOUT_DIRTY.store(true, Ordering::SeqCst);
2646 let swap = get_system_state();
2647 let current = swap.load();
2648 let new_state = Arc::new(f(¤t));
2649 swap.store(Arc::clone(&new_state));
2650 #[cfg(not(target_arch = "wasm32"))]
2651 {
2652 let tvar = KNOWLEDGE_TVAR.get_or_init(|| stm::TVar::new((*new_state).clone()));
2653 stm::atomically(|tx| tvar.write(tx, (*new_state).clone()));
2654 }
2655}
2656pub fn transact_system_state<F>(f: F)
2657where
2658 F: Fn(&KnowledgeState) -> KnowledgeState,
2659{
2660 let _lock = STATE_WRITE_MUTEX.lock().unwrap();
2661 #[cfg(not(target_arch = "wasm32"))]
2662 {
2663 if is_rendering() {
2664 log::warn!(
2665 "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2666 );
2667 }
2668 let tvar = KNOWLEDGE_TVAR
2669 .get_or_init(|| stm::TVar::new((**get_system_state().load()).clone()))
2670 .clone();
2671 let new_state = stm::atomically(move |tx| {
2672 let current = tvar.read(tx)?;
2673 let next = f(¤t);
2674 tvar.write(tx, next.clone())?;
2675 Ok(next)
2676 });
2677 get_system_state().store(Arc::new(new_state));
2678 }
2679 #[cfg(target_arch = "wasm32")]
2680 {
2681 if is_rendering() {
2682 log::warn!(
2683 "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2684 );
2685 }
2686 update_system_state(f);
2687 }
2688}
2689impl KnowledgeState {
2690 pub fn new() -> Self {
2692 Self::default()
2693 }
2694 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
2696 self.component_states
2697 .insert(id, Arc::new(std::sync::RwLock::new(state)));
2698 }
2699 pub fn get_component_state<T: 'static + Send + Sync>(
2701 &self,
2702 id: u64,
2703 ) -> Option<Arc<std::sync::RwLock<T>>> {
2704 let lock = self.component_states.get(&id)?;
2705 let any_ref = lock.read().ok()?;
2709 if any_ref.is::<T>() {
2710 drop(any_ref);
2712 let cloned: Arc<std::sync::RwLock<dyn std::any::Any + Send + Sync>> = Arc::clone(lock);
2713 Some(unsafe {
2716 let raw = Arc::into_raw(cloned);
2717 Arc::from_raw(raw as *const std::sync::RwLock<T>)
2718 })
2719 } else {
2720 None
2721 }
2722 }
2723 pub fn remember(&mut self, fragment: KnowledgeFragment) {
2725 self.fragments.insert(fragment.id.clone(), fragment);
2726 }
2727 pub fn process_query(&mut self, query: &str) {
2729 let query_lower = query.to_lowercase();
2730 let mut results: Vec<(f32, String)> = self
2731 .fragments
2732 .iter()
2733 .map(|(id, frag)| {
2734 let mut score = 0.0;
2735 if frag.summary.to_lowercase().contains(&query_lower) {
2736 score += 1.0;
2737 }
2738 if frag.source.to_lowercase().contains(&query_lower) {
2739 score += 0.5;
2740 }
2741 (score, id.clone())
2742 })
2743 .filter(|(score, _)| *score > 0.0)
2744 .collect();
2745 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
2747 self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
2748 }
2749 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
2751 let mut snapshots = Vec::new();
2752 for frag in self.fragments.values() {
2754 if let Ok(val) = serde_json::to_value(frag) {
2755 snapshots.push(NodeStateSnapshot { id: 0, state: val });
2756 }
2757 }
2758 snapshots
2759 }
2760}
2761#[derive(Clone)]
2763pub struct Binding<T: Clone + Send + Sync + 'static> {
2764 swap: Arc<arc_swap::ArcSwap<T>>,
2765 #[cfg(not(target_arch = "wasm32"))]
2766 tvar: Arc<stm::TVar<T>>,
2767 version: Arc<std::sync::atomic::AtomicU64>,
2768}
2769impl<T: Clone + Send + Sync + 'static> Binding<T> {
2770 pub fn from_state(state: &State<T>) -> Self {
2772 Self {
2773 swap: Arc::clone(&state.swap),
2774 #[cfg(not(target_arch = "wasm32"))]
2775 tvar: Arc::clone(&state.tvar),
2776 version: Arc::clone(&state.version),
2777 }
2778 }
2779 pub fn get(&self) -> T {
2781 (**self.swap.load()).clone()
2782 }
2783 pub fn set(&self, value: T) {
2785 self.swap.store(Arc::new(value.clone()));
2786 #[cfg(not(target_arch = "wasm32"))]
2787 {
2788 let tvar = Arc::clone(&self.tvar);
2789 let v = value.clone();
2790 stm::atomically(move |tx| tvar.write(tx, v.clone()));
2791 }
2792 self.version
2793 .fetch_add(1, std::sync::atomic::Ordering::Release);
2794 }
2795 pub fn version(&self) -> u64 {
2797 self.version.load(std::sync::atomic::Ordering::Acquire)
2798 }
2799}
2800#[cfg(not(target_arch = "wasm32"))]
2801pub fn transact_pair<A, B, F>(state_a: &State<A>, state_b: &State<B>, f: F)
2802where
2803 A: Clone + Send + Sync + 'static,
2804 B: Clone + Send + Sync + 'static,
2805 F: Fn(&A, &B) -> (A, B),
2806{
2807 let tvar_a = Arc::clone(&state_a.tvar);
2808 let tvar_b = Arc::clone(&state_b.tvar);
2809 let (new_a, new_b) = stm::atomically(move |tx| {
2810 let a = tvar_a.read(tx)?;
2811 let b = tvar_b.read(tx)?;
2812 let (na, nb) = f(&a, &b);
2813 tvar_a.write(tx, na.clone())?;
2814 tvar_b.write(tx, nb.clone())?;
2815 Ok((na, nb))
2816 });
2817 state_a.swap.store(Arc::new(new_a.clone()));
2818 state_b.swap.store(Arc::new(new_b.clone()));
2819 state_a
2820 .version
2821 .fetch_add(1, std::sync::atomic::Ordering::Release);
2822 state_b
2823 .version
2824 .fetch_add(1, std::sync::atomic::Ordering::Release);
2825 let subs_a = Arc::clone(&state_a.subscribers);
2826 let subs_b = Arc::clone(&state_b.subscribers);
2827 if crate::is_batching() {
2828 crate::enqueue_batch_task(Box::new(move || {
2829 {
2830 let s = subs_a.lock().unwrap();
2831 for cb in s.iter() {
2832 cb(&new_a);
2833 }
2834 }
2835 {
2836 let s = subs_b.lock().unwrap();
2837 for cb in s.iter() {
2838 cb(&new_b);
2839 }
2840 }
2841 }));
2842 } else {
2843 {
2844 let s = subs_a.lock().unwrap();
2845 for cb in s.iter() {
2846 cb(&new_a);
2847 }
2848 }
2849 {
2850 let s = subs_b.lock().unwrap();
2851 for cb in s.iter() {
2852 cb(&new_b);
2853 }
2854 }
2855 }
2856}
2857use std::any::TypeId;
2858use std::sync::Mutex;
2859pub(crate) static ENVIRONMENT: OnceLock<
2861 Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
2862> = OnceLock::new();
2863pub trait EnvKey: 'static + Send + Sync {
2866 type Value: Clone + Send + Sync + 'static;
2868 fn default_value() -> Self::Value;
2870}
2871pub struct YggdrasilKey;
2873impl EnvKey for YggdrasilKey {
2874 type Value = YggdrasilTokens;
2875 fn default_value() -> Self::Value {
2876 default_tokens()
2877 }
2878}
2879#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2882pub enum Appearance {
2883 Light,
2884 Dark,
2885}
2886#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2888pub enum Orientation {
2889 Horizontal,
2890 Vertical,
2891}
2892#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2894pub enum Alignment {
2895 #[default]
2896 Center,
2897 Leading,
2898 Trailing,
2899 Top,
2900 Bottom,
2901}
2902#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2904pub enum Distribution {
2905 #[default]
2906 Fill,
2907 Center,
2908 Leading,
2909 Trailing,
2910 SpaceBetween,
2911 SpaceAround,
2912 SpaceEvenly,
2913}
2914#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2916pub struct Color {
2917 pub r: f32,
2918 pub g: f32,
2919 pub b: f32,
2920 pub a: f32,
2921}
2922impl Color {
2923 pub const BLACK: Color = Color {
2924 r: 0.0,
2925 g: 0.0,
2926 b: 0.0,
2927 a: 1.0,
2928 };
2929 pub const WHITE: Color = Color {
2930 r: 1.0,
2931 g: 1.0,
2932 b: 1.0,
2933 a: 1.0,
2934 };
2935 pub const TRANSPARENT: Color = Color {
2936 r: 0.0,
2937 g: 0.0,
2938 b: 0.0,
2939 a: 0.0,
2940 };
2941 pub const RED: Color = Color {
2942 r: 1.0,
2943 g: 0.0,
2944 b: 0.0,
2945 a: 1.0,
2946 };
2947 pub const GREEN: Color = Color {
2948 r: 0.0,
2949 g: 1.0,
2950 b: 0.0,
2951 a: 1.0,
2952 };
2953 pub const BLUE: Color = Color {
2954 r: 0.0,
2955 g: 0.0,
2956 b: 1.0,
2957 a: 1.0,
2958 };
2959 pub const VIKING_GOLD: Color = Color {
2960 r: 1.0,
2961 g: 0.84,
2962 b: 0.0,
2963 a: 1.0,
2964 };
2965 pub const MAGENTA_LIQUID: Color = Color {
2966 r: 1.0,
2967 g: 0.0,
2968 b: 1.0,
2969 a: 1.0,
2970 };
2971 pub const TACTICAL_OBSIDIAN: Color = Color {
2972 r: 0.05,
2973 g: 0.05,
2974 b: 0.07,
2975 a: 1.0,
2976 };
2977 pub fn relative_luminance(&self) -> f32 {
2979 fn res(c: f32) -> f32 {
2980 if c <= 0.03928 {
2981 c / 12.92
2982 } else {
2983 ((c + 0.055) / 1.055).powf(2.4)
2984 }
2985 }
2986 0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
2987 }
2988 pub fn contrast_ratio(&self, other: &Color) -> f32 {
2990 let l1 = self.relative_luminance();
2991 let l2 = other.relative_luminance();
2992 if l1 > l2 {
2993 (l1 + 0.05) / (l2 + 0.05)
2994 } else {
2995 (l2 + 0.05) / (l1 + 0.05)
2996 }
2997 }
2998 pub const CYAN: Color = Color {
2999 r: 0.0,
3000 g: 1.0,
3001 b: 1.0,
3002 a: 1.0,
3003 };
3004 pub const YELLOW: Color = Color {
3005 r: 1.0,
3006 g: 1.0,
3007 b: 0.0,
3008 a: 1.0,
3009 };
3010 pub const MAGENTA: Color = Color {
3011 r: 1.0,
3012 g: 0.0,
3013 b: 1.0,
3014 a: 1.0,
3015 };
3016 pub const GRAY: Color = Color {
3017 r: 0.5,
3018 g: 0.5,
3019 b: 0.5,
3020 a: 1.0,
3021 };
3022 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
3024 Self { r, g, b, a }
3025 }
3026 pub fn as_array(&self) -> [f32; 4] {
3028 [self.r, self.g, self.b, self.a]
3029 }
3030}
3031impl View for Color {
3032 type Body = Never;
3033 fn body(self) -> Self::Body {
3034 unreachable!()
3035 }
3036 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
3037 renderer.fill_rect(rect, self.as_array());
3038 }
3039}
3040pub struct AppearanceKey;
3042impl EnvKey for AppearanceKey {
3043 type Value = Appearance;
3044 fn default_value() -> Self::Value {
3045 Appearance::Dark }
3047}
3048pub struct StyleResolver;
3050impl StyleResolver {
3051 pub fn color(key: &str) -> String {
3053 let tokens = Environment::<YggdrasilKey>::new().get();
3054 let appearance = Environment::<AppearanceKey>::new().get();
3055 let is_dark = appearance == Appearance::Dark;
3056 tokens
3057 .get_color(key, is_dark)
3058 .unwrap_or_else(|| "#FF00FF".to_string()) }
3060 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
3062 let tokens = Environment::<YggdrasilKey>::new().get();
3063 let appearance = Environment::<AppearanceKey>::new().get();
3064 let is_dark = appearance == Appearance::Dark;
3065 tokens.get(category, key, is_dark)
3066 }
3067 pub fn color_array(key: &str) -> [f32; 4] {
3071 let hex = Self::color(key);
3072 parse_hex_color(&hex)
3073 }
3074}
3075
3076fn parse_hex_color(hex: &str) -> [f32; 4] {
3078 let hex = hex.trim_start_matches('#');
3079 if hex.len() >= 6 {
3080 let r = u8::from_str_radix(&hex[0..2], 16).unwrap_or(255) as f32 / 255.0;
3081 let g = u8::from_str_radix(&hex[2..4], 16).unwrap_or(0) as f32 / 255.0;
3082 let b = u8::from_str_radix(&hex[4..6], 16).unwrap_or(255) as f32 / 255.0;
3083 let a = if hex.len() >= 8 {
3084 u8::from_str_radix(&hex[6..8], 16).unwrap_or(255) as f32 / 255.0
3085 } else {
3086 1.0
3087 };
3088 [r, g, b, a]
3089 } else {
3090 [1.0, 0.0, 1.0, 1.0] }
3092}
3093
3094pub fn default_tokens() -> YggdrasilTokens {
3096 let mut tokens = YggdrasilTokens::new();
3097 tokens.color.insert(
3099 "background".to_string(),
3100 TokenValue::Single {
3101 value: "#000000".to_string(), },
3103 );
3104 tokens.color.insert(
3105 "primary".to_string(),
3106 TokenValue::Single {
3107 value: "#00FFFF".to_string(), },
3109 );
3110 tokens.color.insert(
3111 "secondary".to_string(),
3112 TokenValue::Single {
3113 value: "#FF00FF".to_string(), },
3115 );
3116 tokens.color.insert(
3117 "surface".to_string(),
3118 TokenValue::Adaptive {
3119 light: "#FFFFFF".to_string(),
3120 dark: "#121212".to_string(),
3121 },
3122 );
3123 tokens.color.insert(
3124 "text".to_string(),
3125 TokenValue::Adaptive {
3126 light: "#000000".to_string(),
3127 dark: "#FFFFFF".to_string(),
3128 },
3129 );
3130 tokens.color.insert(
3132 "surface_elevated".to_string(),
3133 TokenValue::Adaptive {
3134 light: "#FFFFFF".to_string(),
3135 dark: "#1A1A24".to_string(),
3136 },
3137 );
3138 tokens.color.insert(
3139 "surface_overlay".to_string(),
3140 TokenValue::Adaptive {
3141 light: "#FFFFFF".to_string(),
3142 dark: "#1E1E2E".to_string(),
3143 },
3144 );
3145 tokens.color.insert(
3146 "border".to_string(),
3147 TokenValue::Adaptive {
3148 light: "#D0D0D8".to_string(),
3149 dark: "#2A2A3A".to_string(),
3150 },
3151 );
3152 tokens.color.insert(
3153 "border_strong".to_string(),
3154 TokenValue::Adaptive {
3155 light: "#A0A0B0".to_string(),
3156 dark: "#3A3A50".to_string(),
3157 },
3158 );
3159 tokens.color.insert(
3160 "text_muted".to_string(),
3161 TokenValue::Adaptive {
3162 light: "#606070".to_string(),
3163 dark: "#8080A0".to_string(),
3164 },
3165 );
3166 tokens.color.insert(
3167 "text_dim".to_string(),
3168 TokenValue::Adaptive {
3169 light: "#9090A0".to_string(),
3170 dark: "#505070".to_string(),
3171 },
3172 );
3173 tokens.color.insert(
3174 "accent".to_string(),
3175 TokenValue::Single {
3176 value: "#00FFFF".to_string(), },
3178 );
3179 tokens.color.insert(
3180 "accent_hover".to_string(),
3181 TokenValue::Single {
3182 value: "#33FFFF".to_string(),
3183 },
3184 );
3185 tokens.color.insert(
3186 "success".to_string(),
3187 TokenValue::Single {
3188 value: "#00E676".to_string(),
3189 },
3190 );
3191 tokens.color.insert(
3192 "warning".to_string(),
3193 TokenValue::Single {
3194 value: "#FFB300".to_string(),
3195 },
3196 );
3197 tokens.color.insert(
3198 "error".to_string(),
3199 TokenValue::Single {
3200 value: "#FF5252".to_string(),
3201 },
3202 );
3203 tokens.color.insert(
3204 "info".to_string(),
3205 TokenValue::Single {
3206 value: "#448AFF".to_string(),
3207 },
3208 );
3209 tokens.color.insert(
3210 "hover".to_string(),
3211 TokenValue::Adaptive {
3212 light: "#F0F0F5".to_string(),
3213 dark: "#252535".to_string(),
3214 },
3215 );
3216 tokens.color.insert(
3217 "active".to_string(),
3218 TokenValue::Adaptive {
3219 light: "#E0E0EB".to_string(),
3220 dark: "#303045".to_string(),
3221 },
3222 );
3223 tokens.color.insert(
3224 "disabled".to_string(),
3225 TokenValue::Adaptive {
3226 light: "#E8E8F0".to_string(),
3227 dark: "#1A1A28".to_string(),
3228 },
3229 );
3230 tokens.color.insert(
3231 "disabled_text".to_string(),
3232 TokenValue::Adaptive {
3233 light: "#B0B0C0".to_string(),
3234 dark: "#404060".to_string(),
3235 },
3236 );
3237 tokens.color.insert(
3238 "focus_ring".to_string(),
3239 TokenValue::Single {
3240 value: "#00FFFF".to_string(),
3241 },
3242 );
3243 tokens.color.insert(
3244 "shadow".to_string(),
3245 TokenValue::Adaptive {
3246 light: "#00000020".to_string(),
3247 dark: "#00000060".to_string(),
3248 },
3249 );
3250 tokens.color.insert(
3251 "code_bg".to_string(),
3252 TokenValue::Adaptive {
3253 light: "#F5F5FA".to_string(),
3254 dark: "#0D0D18".to_string(),
3255 },
3256 );
3257 tokens.bifrost.insert(
3259 "blur".to_string(),
3260 TokenValue::Single {
3261 value: "25.0".to_string(),
3262 },
3263 );
3264 tokens.bifrost.insert(
3265 "saturation".to_string(),
3266 TokenValue::Single {
3267 value: "1.2".to_string(),
3268 },
3269 );
3270 tokens.bifrost.insert(
3271 "opacity".to_string(),
3272 TokenValue::Single {
3273 value: "0.65".to_string(),
3274 },
3275 );
3276 tokens.gungnir.insert(
3278 "intensity".to_string(),
3279 TokenValue::Single {
3280 value: "1.0".to_string(),
3281 },
3282 );
3283 tokens.gungnir.insert(
3284 "radius".to_string(),
3285 TokenValue::Single {
3286 value: "15.0".to_string(),
3287 },
3288 );
3289 tokens.mjolnir.insert(
3291 "clip_angle".to_string(),
3292 TokenValue::Single {
3293 value: "12.0".to_string(),
3294 },
3295 );
3296 tokens.mjolnir.insert(
3297 "border_width".to_string(),
3298 TokenValue::Single {
3299 value: "2.0".to_string(),
3300 },
3301 );
3302 tokens.anim.insert(
3304 "stiffness".to_string(),
3305 TokenValue::Single {
3306 value: "170.0".to_string(),
3307 },
3308 );
3309 tokens.anim.insert(
3310 "damping".to_string(),
3311 TokenValue::Single {
3312 value: "26.0".to_string(),
3313 },
3314 );
3315 tokens.anim.insert(
3316 "mass".to_string(),
3317 TokenValue::Single {
3318 value: "1.0".to_string(),
3319 },
3320 );
3321 tokens.accessibility.insert(
3323 "reduce_motion".to_string(),
3324 TokenValue::Single {
3325 value: "false".to_string(),
3326 },
3327 );
3328 tokens
3329}
3330pub struct Environment<K: EnvKey> {
3332 _marker: std::marker::PhantomData<K>,
3333}
3334impl<K: EnvKey> Default for Environment<K> {
3335 fn default() -> Self {
3336 Self::new()
3337 }
3338}
3339impl<K: EnvKey> Environment<K> {
3340 pub fn new() -> Self {
3342 Self {
3343 _marker: std::marker::PhantomData,
3344 }
3345 }
3346 pub fn get(&self) -> K::Value {
3348 if let Some(env_store) = ENVIRONMENT.get() {
3349 let env_lock = env_store.lock().unwrap();
3350 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
3351 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
3352 return typed_val.clone();
3353 } else {
3354 log::warn!(
3355 "Environment: Downcast failed for key type {:?}",
3356 std::any::type_name::<K>()
3357 );
3358 }
3359 } else {
3360 log::debug!(
3361 "Environment: Key not found: {:?}. Returning default.",
3362 std::any::type_name::<K>()
3363 );
3364 }
3365 } else {
3366 log::debug!(
3367 "Environment: Store not initialized. Key: {:?}. Returning default.",
3368 std::any::type_name::<K>()
3369 );
3370 }
3371 K::default_value()
3372 }
3373}
3374pub mod env {
3376 pub fn insert<K: super::EnvKey>(value: K::Value) {
3378 let store = super::ENVIRONMENT
3379 .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
3380 let mut env_map = store.lock().unwrap();
3381 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
3382 }
3383 pub fn remove<K: super::EnvKey>() {
3385 if let Some(store) = super::ENVIRONMENT.get() {
3386 let mut env_map = store.lock().unwrap();
3387 env_map.remove(&std::any::TypeId::of::<K>());
3388 }
3389 }
3390}
3391#[derive(Debug, Clone, Copy, PartialEq)]
3394pub struct Size {
3395 pub width: f32,
3396 pub height: f32,
3397}
3398
3399impl Size {
3400 pub const ZERO: Self = Self {
3401 width: 0.0,
3402 height: 0.0,
3403 };
3404
3405 pub fn new(width: f32, height: f32) -> Self {
3406 Self { width, height }
3407 }
3408}
3409
3410#[derive(Debug, Clone, Copy, PartialEq)]
3412pub struct EdgeInsets {
3413 pub top: f32,
3414 pub leading: f32,
3415 pub bottom: f32,
3416 pub trailing: f32,
3417}
3418
3419impl EdgeInsets {
3420 pub fn all(value: f32) -> Self {
3422 Self {
3423 top: value,
3424 leading: value,
3425 bottom: value,
3426 trailing: value,
3427 }
3428 }
3429
3430 pub fn vertical(value: f32) -> Self {
3432 Self {
3433 top: value,
3434 leading: 0.0,
3435 bottom: value,
3436 trailing: 0.0,
3437 }
3438 }
3439
3440 pub fn horizontal(value: f32) -> Self {
3442 Self {
3443 top: 0.0,
3444 leading: value,
3445 bottom: 0.0,
3446 trailing: value,
3447 }
3448 }
3449}
3450
3451#[derive(Debug, Clone, Copy, PartialEq)]
3453pub struct FrameModifier {
3454 pub width: Option<f32>,
3455 pub height: Option<f32>,
3456}
3457
3458impl Default for FrameModifier {
3459 fn default() -> Self {
3460 Self::new()
3461 }
3462}
3463
3464impl FrameModifier {
3465 pub fn new() -> Self {
3466 Self {
3467 width: None,
3468 height: None,
3469 }
3470 }
3471
3472 pub fn width(mut self, width: f32) -> Self {
3473 self.width = Some(width);
3474 self
3475 }
3476
3477 pub fn height(mut self, height: f32) -> Self {
3478 self.height = Some(height);
3479 self
3480 }
3481
3482 pub fn size(mut self, width: f32, height: f32) -> Self {
3483 self.width = Some(width);
3484 self.height = Some(height);
3485 self
3486 }
3487}
3488
3489impl ViewModifier for FrameModifier {
3490 fn modify<V: View>(self, content: V) -> impl View {
3491 ModifiedView::new(content, self)
3492 }
3493}
3494
3495#[derive(Debug, Clone, Copy, PartialEq)]
3497pub struct FlexModifier {
3498 pub weight: f32,
3499}
3500
3501impl ViewModifier for FlexModifier {
3502 fn modify<V: View>(self, content: V) -> impl View {
3503 ModifiedView::new(content, self)
3504 }
3505
3506 fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
3507 self.weight
3508 }
3509}
3510
3511#[derive(Debug, Clone, Copy, PartialEq)]
3513pub struct OffsetModifier {
3514 pub x: f32,
3515 pub y: f32,
3516}
3517
3518impl OffsetModifier {
3519 pub fn new(x: f32, y: f32) -> Self {
3520 Self { x, y }
3521 }
3522}
3523
3524impl ViewModifier for OffsetModifier {
3525 fn modify<V: View>(self, content: V) -> impl View {
3526 ModifiedView::new(content, self)
3527 }
3528}
3529
3530#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3532pub struct ZIndexModifier {
3533 pub z_index: i32,
3534}
3535
3536impl ZIndexModifier {
3537 pub fn new(z_index: i32) -> Self {
3538 Self { z_index }
3539 }
3540}
3541
3542impl ViewModifier for ZIndexModifier {
3543 fn modify<V: View>(self, content: V) -> impl View {
3544 ModifiedView::new(content, self)
3545 }
3546}
3547
3548#[derive(Debug, Clone, Copy, PartialEq, Default)]
3550pub struct LayoutConstraints {
3551 pub min_width: Option<f32>,
3552 pub max_width: Option<f32>,
3553 pub min_height: Option<f32>,
3554 pub max_height: Option<f32>,
3555}
3556
3557#[derive(Debug, Clone, Copy, PartialEq)]
3559pub struct LayoutModifier {
3560 pub constraints: LayoutConstraints,
3561}
3562
3563impl LayoutModifier {
3564 pub fn new(constraints: LayoutConstraints) -> Self {
3565 Self { constraints }
3566 }
3567}
3568
3569impl ViewModifier for LayoutModifier {
3570 fn modify<V: View>(self, content: V) -> impl View {
3571 ModifiedView::new(content, self)
3572 }
3573}
3574
3575#[derive(Debug, Clone, Copy, PartialEq)]
3577pub struct SafeAreaModifier {
3578 pub ignores: bool,
3579}
3580
3581impl ViewModifier for SafeAreaModifier {
3582 fn modify<V: View>(self, content: V) -> impl View {
3583 ModifiedView::new(content, self)
3584 }
3585}
3586
3587#[derive(Debug, Clone, Copy, PartialEq)]
3589pub struct ElevationModifier {
3590 pub level: f32,
3591}
3592
3593impl ViewModifier for ElevationModifier {
3594 fn modify<V: View>(self, content: V) -> impl View {
3595 ModifiedView::new(content, self)
3596 }
3597
3598 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
3599 if self.level > 0.0 {
3600 let radius = self.level * 2.0;
3601 let offset_y = self.level * 0.5;
3602 let shadow_color = [0.0, 0.0, 0.0, 0.3];
3603 renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
3604 view.render(renderer, rect);
3605 renderer.pop_shadow();
3606 } else {
3607 view.render(renderer, rect);
3608 }
3609 }
3610}
3611
3612pub mod layout {
3614 use super::*;
3615
3616 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3619 pub struct LayoutKey {
3620 pub view_hash: u64,
3621 pub generation: u64,
3622 }
3623
3624 pub struct LayoutCache {
3626 pub safe_area: SafeArea,
3627 size_cache: HashMap<(u64, u32, u32), Size>, generation: u64,
3632 }
3633
3634 impl Default for LayoutCache {
3635 fn default() -> Self {
3636 Self::new()
3637 }
3638 }
3639
3640 impl LayoutCache {
3641 pub fn new() -> Self {
3642 Self {
3643 safe_area: SafeArea::default(),
3644 size_cache: HashMap::new(),
3645 generation: 0,
3646 }
3647 }
3648
3649 pub fn generation(&self) -> u64 {
3651 self.generation
3652 }
3653
3654 pub fn invalidate(&mut self) {
3658 self.generation = self.generation.wrapping_add(1);
3659 }
3660
3661 pub fn is_valid(&self, key: LayoutKey, current_gen: u64) -> bool {
3664 key.generation == current_gen && key.generation == self.generation
3665 }
3666
3667 pub fn clear(&mut self) {
3668 self.safe_area = SafeArea::default();
3669 self.size_cache.clear();
3670 }
3671
3672 pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
3673 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
3674 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
3675 self.size_cache.get(&(view_hash, pw, ph)).copied()
3676 }
3677
3678 pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: Size) {
3679 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
3680 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
3681 self.size_cache.insert((view_hash, pw, ph), size);
3682 }
3683
3684 pub fn invalidate_view(&mut self, view_hash: u64) {
3686 self.size_cache.retain(|&(hash, _, _), _| hash != view_hash);
3687 }
3688 }
3689
3690 #[derive(Debug, Clone, Copy, PartialEq)]
3692 pub struct SizeProposal {
3693 pub width: Option<f32>,
3694 pub height: Option<f32>,
3695 }
3696
3697 impl SizeProposal {
3698 pub fn unspecified() -> Self {
3699 Self {
3700 width: None,
3701 height: None,
3702 }
3703 }
3704
3705 pub fn width(width: f32) -> Self {
3706 Self {
3707 width: Some(width),
3708 height: None,
3709 }
3710 }
3711
3712 pub fn height(height: f32) -> Self {
3713 Self {
3714 width: None,
3715 height: Some(height),
3716 }
3717 }
3718
3719 pub fn tight(width: f32, height: f32) -> Self {
3720 Self {
3721 width: Some(width),
3722 height: Some(height),
3723 }
3724 }
3725
3726 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
3727 Self { width, height }
3728 }
3729 }
3730
3731 pub trait LayoutView: Send {
3733 fn size_that_fits(
3735 &self,
3736 proposal: SizeProposal,
3737 subviews: &[&dyn LayoutView],
3738 cache: &mut LayoutCache,
3739 ) -> Size;
3740
3741 fn place_subviews(
3743 &self,
3744 bounds: Rect,
3745 subviews: &mut [&mut dyn LayoutView],
3746 cache: &mut LayoutCache,
3747 );
3748
3749 fn flex_weight(&self) -> f32 {
3751 0.0
3752 }
3753
3754 fn debug_layout(&self, indent: usize) -> String {
3757 let prefix = " ".repeat(indent);
3758 format!("{}LayoutView", prefix)
3759 }
3760 }
3761 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
3763 pub struct EdgeInsets {
3764 pub top: f32,
3765 pub leading: f32,
3766 pub bottom: f32,
3767 pub trailing: f32,
3768 }
3769
3770 impl EdgeInsets {
3771 pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
3772 Self {
3773 top,
3774 leading,
3775 bottom,
3776 trailing,
3777 }
3778 }
3779
3780 pub fn all(value: f32) -> Self {
3781 Self {
3782 top: value,
3783 leading: value,
3784 bottom: value,
3785 trailing: value,
3786 }
3787 }
3788 }
3789
3790 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
3792 pub struct SafeArea {
3793 pub insets: EdgeInsets,
3794 }
3795
3796 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
3798 pub struct Rect {
3799 pub x: f32,
3800 pub y: f32,
3801 pub width: f32,
3802 pub height: f32,
3803 }
3804
3805 impl Rect {
3806 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
3807 Self {
3808 x,
3809 y,
3810 width,
3811 height,
3812 }
3813 }
3814
3815 pub fn inset(&self, amount: f32) -> Self {
3816 Self {
3817 x: self.x + amount,
3818 y: self.y + amount,
3819 width: (self.width - amount * 2.0).max(0.0),
3820 height: (self.height - amount * 2.0).max(0.0),
3821 }
3822 }
3823
3824 pub fn offset(&self, dx: f32, dy: f32) -> Self {
3825 Self {
3826 x: self.x + dx,
3827 y: self.y + dy,
3828 ..*self
3829 }
3830 }
3831
3832 pub fn zero() -> Self {
3833 Self {
3834 x: 0.0,
3835 y: 0.0,
3836 width: 0.0,
3837 height: 0.0,
3838 }
3839 }
3840
3841 pub fn contains(&self, x: f32, y: f32) -> bool {
3842 x >= self.x && x <= self.x + self.width && y >= self.y && y <= self.y + self.height
3843 }
3844
3845 pub fn size(&self) -> Size {
3846 Size {
3847 width: self.width,
3848 height: self.height,
3849 }
3850 }
3851
3852 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
3854 if n == 0 {
3855 return vec![];
3856 }
3857 let item_width = self.width / n as f32;
3858 (0..n)
3859 .map(|i| Rect {
3860 x: self.x + i as f32 * item_width,
3861 y: self.y,
3862 width: item_width,
3863 height: self.height,
3864 })
3865 .collect()
3866 }
3867
3868 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
3870 if n == 0 {
3871 return vec![];
3872 }
3873 let item_height = self.height / n as f32;
3874 (0..n)
3875 .map(|i| Rect {
3876 x: self.x,
3877 y: self.y + i as f32 * item_height,
3878 width: self.width,
3879 height: item_height,
3880 })
3881 .collect()
3882 }
3883 }
3884}
3885
3886pub use layout::{LayoutCache, LayoutKey, LayoutView, Rect, SizeProposal};
3888pub mod agents;
3891pub mod animation;
3892pub mod gpu;
3893pub mod material;
3894pub mod runtime;
3895pub mod scene_graph;
3896pub mod sdf_shadow;
3897
3898pub use scene_graph::{NodeId, bifrost_registry};
3899pub use material::DrawMaterial;
3900
3901pub trait AssetManager: Send + Sync {
3905 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
3907
3908 fn preload_image(&self, url: &str);
3910}
3911
3912#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
3914pub enum Event {
3915 PointerDown {
3916 x: f32,
3917 y: f32,
3918 button: u32,
3919 },
3920 PointerUp {
3921 x: f32,
3922 y: f32,
3923 button: u32,
3924 },
3925 PointerMove {
3926 x: f32,
3927 y: f32,
3928 },
3929 PointerClick {
3930 x: f32,
3931 y: f32,
3932 button: u32,
3933 },
3934 PointerEnter,
3935 PointerLeave,
3936 PointerWheel {
3939 x: f32,
3940 y: f32,
3941 delta_x: f32,
3942 delta_y: f32,
3943 },
3944 PointerDoubleClick {
3946 x: f32,
3947 y: f32,
3948 button: u32,
3949 },
3950 DragStart {
3952 x: f32,
3953 y: f32,
3954 button: u32,
3955 },
3956 DragMove {
3958 x: f32,
3959 y: f32,
3960 },
3961 DragEnd {
3963 x: f32,
3964 y: f32,
3965 },
3966 KeyDown {
3967 key: String,
3968 },
3969 KeyUp {
3970 key: String,
3971 },
3972 FocusIn,
3974 FocusOut,
3976 Copy,
3978 Cut,
3980 Paste(String),
3982 Ime(String),
3984 TouchStart {
3986 x: f32,
3987 y: f32,
3988 touch_id: u64,
3989 },
3990 TouchMove {
3992 x: f32,
3993 y: f32,
3994 touch_id: u64,
3995 },
3996 TouchEnd {
3998 x: f32,
3999 y: f32,
4000 touch_id: u64,
4001 },
4002 TouchCancel {
4004 touch_id: u64,
4005 },
4006 GesturePinch {
4008 scale: f32,
4009 velocity: f32,
4010 },
4011 GestureSwipe {
4013 dx: f32,
4014 dy: f32,
4015 velocity_x: f32,
4016 velocity_y: f32,
4017 },
4018}
4019
4020impl Event {
4021 pub fn name(&self) -> &'static str {
4023 match self {
4024 Self::PointerDown { .. } => "pointerdown",
4025 Self::PointerUp { .. } => "pointerup",
4026 Self::PointerMove { .. } => "pointermove",
4027 Self::PointerClick { .. } => "pointerclick",
4028 Self::PointerEnter => "pointerenter",
4029 Self::PointerLeave => "pointerleave",
4030 Self::PointerWheel { .. } => "pointerwheel",
4031 Self::PointerDoubleClick { .. } => "pointerdoubleclick",
4032 Self::DragStart { .. } => "dragstart",
4033 Self::DragMove { .. } => "dragmove",
4034 Self::DragEnd { .. } => "dragend",
4035 Self::KeyDown { .. } => "keydown",
4036 Self::KeyUp { .. } => "keyup",
4037 Self::FocusIn => "focusin",
4038 Self::FocusOut => "focusout",
4039 Self::Copy => "copy",
4040 Self::Cut => "cut",
4041 Self::Paste(_) => "paste",
4042 Self::Ime(_) => "ime",
4043 Self::TouchStart { .. } => "touchstart",
4044 Self::TouchMove { .. } => "touchmove",
4045 Self::TouchEnd { .. } => "touchend",
4046 Self::TouchCancel { .. } => "touchcancel",
4047 Self::GesturePinch { .. } => "gesturepinch",
4048 Self::GestureSwipe { .. } => "gestureswipe",
4049 }
4050 }
4051}
4052
4053#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4055pub enum EventResponse {
4056 Handled,
4057 Ignored,
4058}
4059
4060pub struct DefaultAssetManager {
4062 cache: AssetCache,
4063}
4064type AssetCache = Arc<arc_swap::ArcSwap<HashMap<String, AssetState<Arc<Vec<u8>>>>>>;
4065
4066impl Default for DefaultAssetManager {
4067 fn default() -> Self {
4068 Self::new()
4069 }
4070}
4071
4072impl DefaultAssetManager {
4073 pub fn new() -> Self {
4074 Self {
4075 cache: Arc::new(arc_swap::ArcSwap::from_pointee(HashMap::new())),
4076 }
4077 }
4078}
4079
4080impl AssetManager for DefaultAssetManager {
4081 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
4082 if let Some(state) = self.cache.load().get(url) {
4083 return state.clone();
4084 }
4085
4086 self.cache.rcu(|map| {
4087 let mut m = (**map).clone();
4088 m.entry(url.to_string()).or_insert(AssetState::Loading);
4089 m
4090 });
4091 AssetState::Loading
4092 }
4093
4094 fn preload_image(&self, _url: &str) {}
4095}
4096
4097use std::future::Future;
4098
4099pub struct Suspense<T: Clone + Send + Sync + 'static> {
4102 inner: State<AssetState<T>>,
4103}
4104
4105impl<T: Clone + Send + Sync + 'static> Default for Suspense<T> {
4106 fn default() -> Self {
4107 Self::new()
4108 }
4109}
4110
4111impl<T: Clone + Send + Sync + 'static> Suspense<T> {
4112 pub fn new() -> Self {
4113 Self {
4114 inner: State::new(AssetState::Loading),
4115 }
4116 }
4117
4118 pub fn new_async<F>(future: F) -> Self
4119 where
4120 F: Future<Output = Result<T, String>> + Send + 'static,
4121 {
4122 let suspense = Self::new();
4123 let suspense_clone = suspense.clone();
4124
4125 #[cfg(not(target_arch = "wasm32"))]
4126 {
4127 if let Ok(handle) = tokio::runtime::Handle::try_current() {
4129 handle.spawn(async move {
4130 let result = future.await;
4131 match result {
4132 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
4133 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
4134 }
4135 });
4136 } else {
4137 std::thread::spawn(move || {
4138 let rt = tokio::runtime::Builder::new_current_thread()
4139 .enable_all()
4140 .build()
4141 .unwrap();
4142 rt.block_on(async {
4143 let result = future.await;
4144 match result {
4145 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
4146 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
4147 }
4148 });
4149 });
4150 }
4151 }
4152 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
4153 {
4154 wasm_bindgen_futures::spawn_local(async move {
4155 let result = future.await;
4156 match result {
4157 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
4158 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
4159 }
4160 });
4161 }
4162
4163 suspense
4164 }
4165
4166 pub fn ready(value: T) -> Self {
4167 Self {
4168 inner: State::new(AssetState::Ready(value)),
4169 }
4170 }
4171
4172 pub fn error(message: impl Into<String>) -> Self {
4173 Self {
4174 inner: State::new(AssetState::Error(message.into())),
4175 }
4176 }
4177
4178 pub fn get(&self) -> AssetState<T> {
4179 self.inner.get()
4180 }
4181
4182 pub fn get_ref(&self) -> AssetState<T> {
4183 self.inner.get()
4184 }
4185
4186 pub fn is_loading(&self) -> bool {
4187 matches!(self.get(), AssetState::Loading)
4188 }
4189
4190 pub fn is_ready(&self) -> bool {
4191 matches!(self.get(), AssetState::Ready(_))
4192 }
4193
4194 pub fn is_error(&self) -> bool {
4195 matches!(self.get(), AssetState::Error(_))
4196 }
4197
4198 pub fn ready_value(&self) -> Option<T> {
4199 match self.get() {
4200 AssetState::Ready(value) => Some(value),
4201 _ => None,
4202 }
4203 }
4204
4205 pub fn error_message(&self) -> Option<String> {
4206 match self.get() {
4207 AssetState::Error(message) => Some(message),
4208 _ => None,
4209 }
4210 }
4211
4212 pub fn subscribe<F: Fn(&AssetState<T>) + Send + Sync + 'static>(&self, callback: F) {
4213 self.inner.subscribe(callback)
4214 }
4215
4216 pub fn inner_state(&self) -> &State<AssetState<T>> {
4217 &self.inner
4218 }
4219}
4220
4221impl<T: Clone + Send + Sync + 'static> Clone for Suspense<T> {
4222 fn clone(&self) -> Self {
4223 Self {
4224 inner: self.inner.clone(),
4225 }
4226 }
4227}
4228
4229impl<T: Clone + Send + Sync + 'static> From<T> for Suspense<T> {
4230 fn from(value: T) -> Self {
4231 Self::ready(value)
4232 }
4233}
4234
4235impl<T: Clone + Send + Sync + 'static> From<Result<T, String>> for Suspense<T> {
4236 fn from(result: Result<T, String>) -> Self {
4237 match result {
4238 Ok(value) => Self::ready(value),
4239 Err(error) => Self::error(error),
4240 }
4241 }
4242}
4243
4244#[cfg(test)]
4245mod phase1_test;
4246
4247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4249pub enum BerserkerMode {
4250 Normal,
4251 Rage, Frenzy, GodMode, }
4255
4256pub trait Seer: Send + Sync {
4259 fn predict(&self, context: &str) -> String;
4261 fn whispers(&self) -> Vec<String>;
4263}