1use serde::{Deserialize, Serialize};
35use std::collections::HashMap;
36use std::str::FromStr;
37
38pub mod security;
39
40#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
42pub struct ComponentErrorState {
43 pub has_error: bool,
44 pub error_message: Option<String>,
45 pub error_location: Option<String>,
46}
47impl ComponentErrorState {
48 pub fn clear() -> Self {
49 Self::default()
50 }
51
52 pub fn error(message: impl Into<String>, location: impl Into<String>) -> Self {
53 Self {
54 has_error: true,
55 error_message: Some(message.into()),
56 error_location: Some(location.into()),
57 }
58 }
59}
60
61#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
63pub struct KnowledgeState {
64 pub thoughts: Vec<String>,
65 pub actions: Vec<String>,
66 pub context: HashMap<String, String>,
67 pub last_query_results: Vec<KnowledgeId>,
68 pub fragments: std::collections::HashMap<KnowledgeId, KnowledgeFragment>,
69 #[serde(skip)]
71 pub component_states: HashMap<u64, Arc<std::sync::RwLock<dyn std::any::Any + Send + Sync>>>,
72}
73pub type KnowledgeId = String;
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct KnowledgeFragment {
80 pub id: String,
82 pub summary: String,
84 pub source: String,
86 pub created_at: u64,
88 pub accessed_count: u32,
90 pub content: Option<String>,
92}
93
94impl KnowledgeFragment {
95 pub fn new(id: String, summary: String, source: String) -> Self {
96 Self {
97 id,
98 summary,
99 source,
100 created_at: 0,
101 accessed_count: 0,
102 content: None,
103 }
104 }
105}
106
107#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
108pub struct AssetKey(pub String);
109
110impl EnvKey for AssetKey {
111 type Value = Arc<dyn AssetManager>;
112 fn default_value() -> Self::Value {
113 Arc::new(DefaultAssetManager::new())
114 }
115}
116
117#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
119pub enum AssetState<T> {
120 Loading,
121 Ready(T),
122 Error(String),
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127#[serde(untagged)]
128pub enum TokenValue {
129 Single { value: String },
131 Adaptive { light: String, dark: String },
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct YggdrasilTokens {
138 pub color: HashMap<String, TokenValue>,
139 pub font: HashMap<String, TokenValue>,
140 pub spacing: HashMap<String, TokenValue>,
141 pub radius: HashMap<String, TokenValue>,
142 pub shadow: HashMap<String, TokenValue>,
143 pub border: HashMap<String, TokenValue>,
144 pub anim: HashMap<String, TokenValue>,
145 pub bifrost: HashMap<String, TokenValue>,
146 pub gungnir: HashMap<String, TokenValue>,
147 pub mjolnir: HashMap<String, TokenValue>,
148 pub accessibility: HashMap<String, TokenValue>,
149}
150
151impl Default for YggdrasilTokens {
152 fn default() -> Self {
153 Self::new()
154 }
155}
156
157
158
159impl YggdrasilTokens {
160 pub fn new() -> Self {
161 Self {
162 color: HashMap::new(),
163 font: HashMap::new(),
164 spacing: HashMap::new(),
165 radius: HashMap::new(),
166 shadow: HashMap::new(),
167 border: HashMap::new(),
168 anim: HashMap::new(),
169 bifrost: HashMap::new(),
170 gungnir: HashMap::new(),
171 mjolnir: HashMap::new(),
172 accessibility: HashMap::new(),
173 }
174 }
175
176 pub fn get_color(&self, key: &str, is_dark: bool) -> Option<String> {
178 self.color.get(key).map(|token| match token {
179 TokenValue::Single { value } => value.clone(),
180 TokenValue::Adaptive { light, dark } => {
181 if is_dark {
182 dark.clone()
183 } else {
184 light.clone()
185 }
186 }
187 })
188 }
189
190 pub fn get<T: FromStr>(&self, category: &str, key: &str, is_dark: bool) -> Option<T> {
192 let map = match category {
193 "color" => &self.color,
194 "font" => &self.font,
195 "spacing" => &self.spacing,
196 "radius" => &self.radius,
197 "shadow" => &self.shadow,
198 "border" => &self.border,
199 "anim" => &self.anim,
200 "bifrost" => &self.bifrost,
201 "gungnir" => &self.gungnir,
202 "mjolnir" => &self.mjolnir,
203 "accessibility" => &self.accessibility,
204 _ => return None,
205 };
206
207 map.get(key).and_then(|token| match token {
208 TokenValue::Single { value } => value.parse().ok(),
209 TokenValue::Adaptive { light, dark } => {
210 let value = if is_dark { dark } else { light };
211 value.parse().ok()
212 }
213 })
214 }
215}
216
217pub trait View: Sized + Send {
218 type Body: View;
221
222 fn body(self) -> Self::Body;
223
224 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
227
228 fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
231 Size::ZERO
232 }
233
234 fn layout(&self) -> Option<&dyn layout::LayoutView> {
236 None
237 }
238
239 fn flex_weight(&self) -> f32 {
241 0.0
242 }
243
244 fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
246 ModifiedView::new(self, m)
247 }
248
249 fn bifrost(
251 self,
252 blur: f32,
253 saturation: f32,
254 opacity: f32,
255 ) -> ModifiedView<Self, BifrostModifier> {
256 self.modifier(BifrostModifier {
257 blur,
258 saturation,
259 opacity,
260 })
261 }
262
263 fn gungnir(
265 self,
266 color: impl Into<String>,
267 radius: f32,
268 intensity: f32,
269 ) -> ModifiedView<Self, GungnirModifier> {
270 self.modifier(GungnirModifier {
271 color: color.into(),
272 radius,
273 intensity,
274 })
275 }
276
277 fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
279 self.modifier(MjolnirSliceModifier { angle, offset })
280 }
281
282 fn mjolnir_shatter(
284 self,
285 pieces: u32,
286 force: f32,
287 ) -> ModifiedView<Self, MjolnirShatterModifier> {
288 self.modifier(MjolnirShatterModifier { pieces, force })
289 }
290
291 fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
293 self.modifier(BifrostBridgeModifier { id: id.into() })
294 }
295
296 fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
298 self.modifier(BackgroundModifier { color })
299 }
300
301 fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
303 self.modifier(PaddingModifier { amount })
304 }
305
306 fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
308 self.modifier(OpacityModifier {
309 opacity: opacity.clamp(0.0, 1.0),
310 })
311 }
312
313 fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
315 self.modifier(ForegroundColorModifier { color })
316 }
317
318 fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
320 self.modifier(FrameModifier { width, height })
321 }
322
323 fn flex(self, weight: f32) -> ModifiedView<Self, FlexModifier> {
325 self.modifier(FlexModifier { weight })
326 }
327
328 fn safe_area_padding(self) -> ModifiedView<Self, SafeAreaModifier> {
330 self.modifier(SafeAreaModifier { ignores: false })
331 }
332
333 fn ignores_safe_area(self) -> ModifiedView<Self, SafeAreaModifier> {
335 self.modifier(SafeAreaModifier { ignores: true })
336 }
337
338 fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
340 self.modifier(ClipModifier)
341 }
342
343 fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
345 self.modifier(BorderModifier { color, width })
346 }
347
348 fn elevation(self, level: f32) -> ModifiedView<Self, ElevationModifier> {
350 self.modifier(ElevationModifier { level })
351 }
352
353 fn on_appear<F: Fn() + Send + Sync + 'static>(
355 self,
356 action: F,
357 ) -> ModifiedView<Self, LifecycleModifier> {
358 self.modifier(LifecycleModifier {
359 on_appear: Some(Arc::new(action)),
360 on_disappear: None,
361 })
362 }
363
364 fn on_disappear<F: Fn() + Send + Sync + 'static>(
366 self,
367 action: F,
368 ) -> ModifiedView<Self, LifecycleModifier> {
369 self.modifier(LifecycleModifier {
370 on_appear: None,
371 on_disappear: Some(Arc::new(action)),
372 })
373 }
374
375 fn on_click<F: Fn() + Send + Sync + 'static>(
377 self,
378 action: F,
379 ) -> ModifiedView<Self, OnClickModifier> {
380 self.modifier(OnClickModifier {
381 action: Arc::new(action),
382 })
383 }
384
385 fn on_pointer_enter<F: Fn() + Send + Sync + 'static>(
387 self,
388 action: F,
389 ) -> ModifiedView<Self, OnPointerEnterModifier> {
390 self.modifier(OnPointerEnterModifier {
391 action: Arc::new(action),
392 })
393 }
394
395 fn on_pointer_leave<F: Fn() + Send + Sync + 'static>(
397 self,
398 action: F,
399 ) -> ModifiedView<Self, OnPointerLeaveModifier> {
400 self.modifier(OnPointerLeaveModifier {
401 action: Arc::new(action),
402 })
403 }
404
405 fn on_pointer_move<F: Fn(f32, f32) + Send + Sync + 'static>(
407 self,
408 action: F,
409 ) -> ModifiedView<Self, OnPointerMoveModifier> {
410 self.modifier(OnPointerMoveModifier {
411 action: Arc::new(action),
412 })
413 }
414
415 fn on_pointer_down<F: Fn() + Send + Sync + 'static>(
417 self,
418 action: F,
419 ) -> ModifiedView<Self, OnPointerDownModifier> {
420 self.modifier(OnPointerDownModifier {
421 action: Arc::new(action),
422 })
423 }
424
425 fn on_pointer_up<F: Fn() + Send + Sync + 'static>(
427 self,
428 action: F,
429 ) -> ModifiedView<Self, OnPointerUpModifier> {
430 self.modifier(OnPointerUpModifier {
431 action: Arc::new(action),
432 })
433 }
434
435 fn erase(self) -> AnyView
437 where
438 Self: 'static,
439 {
440 AnyView::new(self)
441 }
442}
443
444pub trait ErasedView: Send {
446 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect);
447 fn name(&self) -> &'static str;
448 fn flex_weight_erased(&self) -> f32;
449 fn layout_erased(&self) -> Option<&dyn layout::LayoutView>;
450}
451
452impl<V: View + 'static> ErasedView for V {
453 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
454 self.render(renderer, rect);
455 }
456
457 fn name(&self) -> &'static str {
458 std::any::type_name::<V>()
459 }
460
461 fn flex_weight_erased(&self) -> f32 {
462 self.flex_weight()
463 }
464
465 fn layout_erased(&self) -> Option<&dyn layout::LayoutView> {
466 self.layout()
467 }
468}
469
470pub struct AnyView {
472 inner: Box<dyn ErasedView>,
473}
474
475impl AnyView {
476 pub fn new<V: View + 'static>(view: V) -> Self {
477 Self {
478 inner: Box::new(view),
479 }
480 }
481}
482
483impl View for AnyView {
484 type Body = Never;
485 fn body(self) -> Self::Body {
486 unreachable!()
487 }
488
489 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
490 renderer.push_vnode(rect, self.inner.name());
491 self.inner.render_erased(renderer, rect);
492 renderer.pop_vnode();
493 }
494
495 fn flex_weight(&self) -> f32 {
496 self.inner.flex_weight_erased()
497 }
498
499 fn layout(&self) -> Option<&dyn layout::LayoutView> {
500 self.inner.layout_erased()
501 }
502}
503
504#[derive(Debug, Clone, PartialEq)]
508pub struct BifrostBridgeModifier {
509 pub id: String,
510}
511
512impl ViewModifier for BifrostBridgeModifier {
513 fn modify<V: View>(self, content: V) -> impl View {
514 ModifiedView::new(content, self)
515 }
516
517 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
518 renderer.register_shared_element(&self.id, rect);
520 }
521}
522
523#[derive(Debug, Clone, Copy, PartialEq)]
526pub struct MjolnirSliceModifier {
527 pub angle: f32,
528 pub offset: f32,
529}
530
531impl ViewModifier for MjolnirSliceModifier {
532 fn modify<V: View>(self, content: V) -> impl View {
533 ModifiedView::new(content, self)
534 }
535
536 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
537 renderer.push_mjolnir_slice(self.angle, self.offset);
538 }
539
540 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
541 renderer.pop_mjolnir_slice();
542 }
543}
544
545#[derive(Debug, Clone, Copy, PartialEq)]
548pub struct MjolnirShatterModifier {
549 pub pieces: u32,
550 pub force: f32,
551}
552
553impl ViewModifier for MjolnirShatterModifier {
554 fn modify<V: View>(self, content: V) -> impl View {
555 ModifiedView::new(content, self)
556 }
557
558 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
559 let pieces = self.pieces.max(1);
561 for i in 0..pieces {
562 let progress = i as f32 / pieces as f32;
563 let next_progress = (i + 1) as f32 / pieces as f32;
564
565 let angle_start = progress * 360.0;
566 let angle_end = next_progress * 360.0;
567
568 renderer.push_mjolnir_slice(angle_start, 0.0);
570 renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
571
572 let mid_angle = (angle_start + angle_end) / 2.0;
574 let rad = mid_angle.to_radians();
575 let dx = rad.cos() * self.force;
576 let dy = rad.sin() * self.force;
577
578 let shard_rect = Rect {
579 x: rect.x + dx,
580 y: rect.y + dy,
581 ..rect
582 };
583
584 view.render(renderer, shard_rect);
585
586 renderer.pop_mjolnir_slice();
587 renderer.pop_mjolnir_slice();
588 }
589 }
590}
591
592#[derive(Debug, Clone, Copy, PartialEq)]
595pub struct BifrostModifier {
596 pub blur: f32,
597 pub saturation: f32,
598 pub opacity: f32,
599}
600
601impl ViewModifier for BifrostModifier {
602 fn modify<V: View>(self, content: V) -> impl View {
603 ModifiedView::new(content, self)
604 }
605
606 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
607 renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
608 }
609}
610
611#[derive(Debug, Clone, Copy, PartialEq)]
613pub struct BackgroundModifier {
614 pub color: [f32; 4],
615}
616
617impl ViewModifier for BackgroundModifier {
618 fn modify<V: View>(self, content: V) -> impl View {
619 ModifiedView::new(content, self)
620 }
621
622 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
623 renderer.fill_rect(rect, self.color);
624 }
625}
626
627#[derive(Debug, Clone, Copy, PartialEq)]
629pub struct PaddingModifier {
630 pub amount: f32,
631}
632
633impl ViewModifier for PaddingModifier {
634 fn modify<V: View>(self, content: V) -> impl View {
635 ModifiedView::new(content, self)
636 }
637
638 fn transform_rect(&self, rect: Rect) -> Rect {
639 Rect {
640 x: rect.x + self.amount,
641 y: rect.y + self.amount,
642 width: (rect.width - 2.0 * self.amount).max(0.0),
643 height: (rect.height - 2.0 * self.amount).max(0.0),
644 }
645 }
646
647 fn transform_proposal(&self, mut proposal: SizeProposal) -> SizeProposal {
648 if let Some(w) = proposal.width {
649 proposal.width = Some((w - 2.0 * self.amount).max(0.0));
650 }
651 if let Some(h) = proposal.height {
652 proposal.height = Some((h - 2.0 * self.amount).max(0.0));
653 }
654 proposal
655 }
656
657 fn transform_size(&self, mut size: Size) -> Size {
658 size.width += 2.0 * self.amount;
659 size.height += 2.0 * self.amount;
660 size
661 }
662}
663
664#[derive(Debug, Clone, PartialEq)]
667pub struct GungnirModifier {
668 pub color: String,
669 pub radius: f32,
670 pub intensity: f32,
671}
672
673impl ViewModifier for GungnirModifier {
674 fn modify<V: View>(self, content: V) -> impl View {
675 ModifiedView::new(content, self)
676 }
677
678 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
679 renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
681 }
682}
683
684#[derive(Debug, Clone, Copy, PartialEq)]
686pub struct GungnirPulseModifier {
687 pub color: [f32; 4],
688 pub radius: f32,
689 pub speed: f32,
690}
691
692impl ViewModifier for GungnirPulseModifier {
693 fn modify<V: View>(self, content: V) -> impl View {
694 ModifiedView::new(content, self)
695 }
696
697 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
698 let time = std::time::SystemTime::now()
699 .duration_since(std::time::UNIX_EPOCH)
700 .unwrap_or_default()
701 .as_secs_f32();
702
703 let intensity = (time * self.speed).sin() * 0.5 + 0.5;
706 let mut color = self.color;
707 color[3] *= intensity;
708
709 renderer.stroke_rect(rect, color, self.radius);
711 }
712}
713
714#[derive(Debug, Clone, Copy, PartialEq)]
716pub struct SleipnirParams {
717 pub stiffness: f32,
718 pub damping: f32,
719 pub mass: f32,
720}
721
722impl SleipnirParams {
723 pub fn snappy() -> Self { Self { stiffness: 230.0, damping: 22.0, mass: 1.0 } }
724 pub fn fluid() -> Self { Self { stiffness: 170.0, damping: 26.0, mass: 1.0 } }
725 pub fn heavy() -> Self { Self { stiffness: 90.0, damping: 20.0, mass: 1.0 } }
726 pub fn bouncy() -> Self { Self { stiffness: 190.0, damping: 14.0, mass: 1.0 } }
727}
728
729impl Default for SleipnirParams {
730 fn default() -> Self { Self::fluid() }
731}
732
733#[derive(Debug, Clone, Copy, PartialEq)]
734struct SolverState {
735 x: f32,
736 v: f32,
737}
738
739#[derive(Debug, Clone, Copy, PartialEq)]
742pub struct SleipnirSolver {
743 params: SleipnirParams,
744 target: f32,
745 state: SolverState,
746}
747
748impl SleipnirSolver {
749 pub fn new(params: SleipnirParams, target: f32, current: f32) -> Self {
751 Self {
752 params,
753 target,
754 state: SolverState { x: current, v: 0.0 },
755 }
756 }
757
758 pub fn tick(&mut self, dt: f32) -> f32 {
760 if dt <= 0.0 { return self.state.x; }
761
762 let mut remaining = dt;
764 let step = 1.0 / 120.0;
765
766 while remaining > 0.0 {
767 let d = remaining.min(step);
768 self.step(d);
769 remaining -= d;
770 }
771
772 self.state.x
773 }
774
775 fn step(&mut self, dt: f32) {
776 let a = self.evaluate(self.state, 0.0, SolverState { x: 0.0, v: 0.0 });
777 let b = self.evaluate(self.state, dt * 0.5, a);
778 let c = self.evaluate(self.state, dt * 0.5, b);
779 let d = self.evaluate(self.state, dt, c);
780
781 let dxdt = 1.0 / 6.0 * (a.x + 2.0 * (b.x + c.x) + d.x);
782 let dvdt = 1.0 / 6.0 * (a.v + 2.0 * (b.v + c.v) + d.v);
783
784 self.state.x += dxdt * dt;
785 self.state.v += dvdt * dt;
786 }
787
788 fn evaluate(&self, initial: SolverState, dt: f32, d: SolverState) -> SolverState {
789 let state = SolverState {
790 x: initial.x + d.x * dt,
791 v: initial.v + d.v * dt,
792 };
793 let force = -self.params.stiffness * (state.x - self.target) - self.params.damping * state.v;
794 let mass = self.params.mass.max(0.001);
795 SolverState { x: state.v, v: force / mass }
796 }
797
798 pub fn is_settled(&self) -> bool {
799 (self.state.x - self.target).abs() < 0.001 && self.state.v.abs() < 0.001
800 }
801
802 pub fn set_target(&mut self, target: f32) {
803 self.target = target;
804 }
805
806 pub fn current_value(&self) -> f32 {
807 self.state.x
808 }
809}
810
811#[derive(Debug, Clone, PartialEq)]
813pub struct SleipnirModifier {
814 pub id: u64,
815 pub target: f32,
816 pub params: SleipnirParams,
817}
818
819impl ViewModifier for SleipnirModifier {
820 fn modify<V: View>(self, content: V) -> impl View {
821 ModifiedView::new(content, self)
822 }
823
824 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
825 let state = load_system_state();
826
827 let solver_lock_opt = state.get_component_state::<SleipnirSolver>(self.id);
829
830 let current_val;
831
832 if let Some(lock) = solver_lock_opt {
833 let mut solver = lock.write().unwrap();
835 solver.set_target(self.target);
836 current_val = solver.tick(renderer.delta_time());
837
838 if !solver.is_settled() {
840 renderer.request_redraw();
841 }
842 } else {
843 let solver = SleipnirSolver::new(
845 self.params,
846 self.target,
847 self.target );
849
850 get_system_state().rcu(|old| {
852 let mut new_state = (**old).clone();
853 new_state.set_component_state(self.id, solver);
854 new_state
855 });
856
857 current_val = self.target;
858 }
859
860 renderer.push_transform([0.0, current_val], [1.0, 1.0], 0.0);
862 view.render(renderer, rect);
863 renderer.pop_transform();
864 }
865}
866
867#[derive(Debug, Clone, Copy, PartialEq)]
870pub struct TransformModifier {
871 pub translation: [f32; 2],
872 pub scale: [f32; 2],
873 pub rotation: f32,
874}
875
876impl Default for TransformModifier {
877 fn default() -> Self {
878 Self::new()
879 }
880}
881
882impl TransformModifier {
883 pub fn new() -> Self {
884 Self {
885 translation: [0.0, 0.0],
886 scale: [1.0, 1.0],
887 rotation: 0.0,
888 }
889 }
890
891 pub fn translate(mut self, x: f32, y: f32) -> Self {
892 self.translation = [x, y];
893 self
894 }
895
896 pub fn scale(mut self, x: f32, y: f32) -> Self {
897 self.scale = [x, y];
898 self
899 }
900
901 pub fn rotate(mut self, radians: f32) -> Self {
902 self.rotation = radians;
903 self
904 }
905}
906
907impl ViewModifier for TransformModifier {
908 fn modify<V: View>(self, content: V) -> impl View {
909 ModifiedView::new(content, self)
910 }
911
912 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
913 renderer.push_transform(self.translation, self.scale, self.rotation);
914 view.render(renderer, rect);
915 renderer.pop_transform();
916 }
917}
918
919#[derive(Clone)]
922pub struct LifecycleModifier {
923 pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
924 pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
925}
926
927impl ViewModifier for LifecycleModifier {
928 fn modify<V: View>(self, content: V) -> impl View {
929 ModifiedView::new(content, self)
930 }
931}
932
933#[derive(Debug, Clone, Copy, PartialEq)]
936pub struct OpacityModifier {
937 pub opacity: f32,
938}
939
940impl ViewModifier for OpacityModifier {
941 fn modify<V: View>(self, content: V) -> impl View {
942 ModifiedView::new(content, self)
943 }
944
945 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
946 renderer.push_opacity(self.opacity);
947 }
948
949 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
950 renderer.pop_opacity();
951 }
952}
953
954#[derive(Clone)]
956pub struct OnClickModifier {
957 pub action: Arc<dyn Fn() + Send + Sync>,
958}
959
960impl ViewModifier for OnClickModifier {
961 fn modify<V: View>(self, content: V) -> impl View {
962 ModifiedView::new(content, self)
963 }
964
965 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
966 let action = self.action.clone();
967 renderer.register_handler(
968 "pointerclick",
969 std::sync::Arc::new(move |event| {
970 if let Event::PointerClick { .. } = event {
971 (action)();
972 }
973 }),
974 );
975 }
976}
977
978#[derive(Clone)]
980pub struct OnPointerEnterModifier {
981 pub action: Arc<dyn Fn() + Send + Sync>,
982}
983
984impl ViewModifier for OnPointerEnterModifier {
985 fn modify<V: View>(self, content: V) -> impl View {
986 ModifiedView::new(content, self)
987 }
988
989 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
990 let action = self.action.clone();
991 renderer.register_handler(
992 "pointerenter",
993 std::sync::Arc::new(move |event| {
994 if let Event::PointerEnter = event {
995 (action)();
996 }
997 }),
998 );
999 }
1000}
1001
1002#[derive(Clone)]
1004pub struct OnPointerLeaveModifier {
1005 pub action: Arc<dyn Fn() + Send + Sync>,
1006}
1007
1008impl ViewModifier for OnPointerLeaveModifier {
1009 fn modify<V: View>(self, content: V) -> impl View {
1010 ModifiedView::new(content, self)
1011 }
1012
1013 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1014 let action = self.action.clone();
1015 renderer.register_handler(
1016 "pointerleave",
1017 std::sync::Arc::new(move |event| {
1018 if let Event::PointerLeave = event {
1019 (action)();
1020 }
1021 }),
1022 );
1023 }
1024}
1025
1026#[derive(Clone)]
1028pub struct OnPointerMoveModifier {
1029 pub action: Arc<dyn Fn(f32, f32) + Send + Sync>,
1030}
1031
1032impl ViewModifier for OnPointerMoveModifier {
1033 fn modify<V: View>(self, content: V) -> impl View {
1034 ModifiedView::new(content, self)
1035 }
1036
1037 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1038 let action = self.action.clone();
1039 renderer.register_handler(
1040 "pointermove",
1041 std::sync::Arc::new(move |event| {
1042 if let Event::PointerMove { x, y } = event {
1043 (action)(x, y);
1044 }
1045 }),
1046 );
1047 }
1048}
1049
1050#[derive(Clone)]
1052pub struct OnPointerDownModifier {
1053 pub action: Arc<dyn Fn() + Send + Sync>,
1054}
1055
1056impl ViewModifier for OnPointerDownModifier {
1057 fn modify<V: View>(self, content: V) -> impl View {
1058 ModifiedView::new(content, self)
1059 }
1060
1061 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1062 let action = self.action.clone();
1063 renderer.register_handler(
1064 "pointerdown",
1065 std::sync::Arc::new(move |event| {
1066 if let Event::PointerDown { .. } = event {
1067 (action)();
1068 }
1069 }),
1070 );
1071 }
1072}
1073
1074#[derive(Clone)]
1076pub struct OnPointerUpModifier {
1077 pub action: Arc<dyn Fn() + Send + Sync>,
1078}
1079
1080impl ViewModifier for OnPointerUpModifier {
1081 fn modify<V: View>(self, content: V) -> impl View {
1082 ModifiedView::new(content, self)
1083 }
1084
1085 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1086 let action = self.action.clone();
1087 renderer.register_handler(
1088 "pointerup",
1089 std::sync::Arc::new(move |event| {
1090 if let Event::PointerUp { .. } = event {
1091 (action)();
1092 }
1093 }),
1094 );
1095 }
1096}
1097
1098#[derive(Debug, Clone, Copy, PartialEq)]
1101pub struct ForegroundColorModifier {
1102 pub color: [f32; 4],
1103}
1104
1105impl ViewModifier for ForegroundColorModifier {
1106 fn modify<V: View>(self, content: V) -> impl View {
1107 ModifiedView::new(content, self)
1108 }
1109}
1110
1111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1114pub struct ClipModifier;
1115
1116impl ViewModifier for ClipModifier {
1117 fn modify<V: View>(self, content: V) -> impl View {
1118 ModifiedView::new(content, self)
1119 }
1120
1121 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1122 renderer.push_clip_rect(rect);
1123 }
1124
1125 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1126 renderer.pop_clip_rect();
1127 }
1128}
1129
1130#[derive(Debug, Clone, Copy, PartialEq)]
1132pub struct BorderModifier {
1133 pub color: [f32; 4],
1134 pub width: f32,
1135}
1136
1137impl ViewModifier for BorderModifier {
1138 fn modify<V: View>(self, content: V) -> impl View {
1139 ModifiedView::new(content, self)
1140 }
1141
1142 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1143 renderer.stroke_rect(rect, self.color, self.width);
1144 }
1145}
1146
1147#[doc(hidden)]
1149pub enum Never {}
1150
1151impl View for Never {
1152 type Body = Never;
1153 fn body(self) -> Never {
1154 unreachable!()
1155 }
1156}
1157
1158pub struct ModifiedView<V, M> {
1162 view: V,
1163 modifier: M,
1164}
1165
1166impl<V: View, M: ViewModifier> ModifiedView<V, M> {
1167 #[doc(hidden)]
1168 pub fn new(view: V, modifier: M) -> Self {
1169 Self { view, modifier }
1170 }
1171}
1172
1173impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
1174 type Body = ModifiedView<V::Body, M>;
1175
1176 fn body(self) -> Self::Body {
1177 ModifiedView {
1178 view: self.view.body(),
1179 modifier: self.modifier.clone(),
1180 }
1181 }
1182
1183 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1184 self.modifier.render_view(&self.view, renderer, rect);
1185 }
1186
1187 fn intrinsic_size(&self, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1188 self.modifier.measure_view(&self.view, renderer, proposal)
1189 }
1190
1191 fn flex_weight(&self) -> f32 {
1192 self.modifier.child_flex_weight(&self.view)
1193 }
1194
1195 fn layout(&self) -> Option<&dyn layout::LayoutView> {
1196 self.modifier.layout().or_else(|| self.view.layout())
1197 }
1198}
1199
1200pub trait ViewModifier: Send + Clone {
1201 fn modify<V: View>(self, content: V) -> impl View;
1202
1203 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1205
1206 fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1208
1209 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1212 self.render(renderer, rect);
1213 let child_rect = self.transform_rect(rect);
1214 view.render(renderer, child_rect);
1215 self.post_render(renderer, rect);
1216 }
1217
1218 fn transform_rect(&self, rect: Rect) -> Rect {
1219 rect
1220 }
1221
1222 fn transform_proposal(&self, proposal: SizeProposal) -> SizeProposal {
1224 proposal
1225 }
1226
1227 fn transform_size(&self, size: Size) -> Size {
1229 size
1230 }
1231
1232 fn measure_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1234 let child_proposal = self.transform_proposal(proposal);
1235 let child_size = view.intrinsic_size(renderer, child_proposal);
1236 self.transform_size(child_size)
1237 }
1238
1239 fn child_flex_weight<V: View>(&self, view: &V) -> f32 {
1241 view.flex_weight()
1242 }
1243
1244 fn layout(&self) -> Option<&dyn layout::LayoutView> {
1245 None
1246 }
1247}
1248
1249#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1251pub struct TelemetryData {
1252 pub frame_time_ms: f32,
1253 pub p99_frame_time_ms: f32,
1255 pub frame_jitter_ms: f32,
1257 pub hardware_stall_detected: bool,
1259
1260 pub input_time_ms: f32,
1262 pub state_flush_time_ms: f32,
1263 pub layout_time_ms: f32,
1264 pub draw_time_ms: f32,
1265 pub gpu_submit_time_ms: f32,
1266
1267 pub draw_calls: u32,
1268 pub vertices: u32,
1269
1270 pub vram_usage_mb: f32,
1272 pub vram_textures_mb: f32,
1273 pub vram_buffers_mb: f32,
1274 pub vram_pipelines_mb: f32,
1275}
1276
1277#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1279pub struct FrameBudget {
1280 pub target_ms: f32,
1282 pub allow_degradation: bool,
1285}
1286
1287impl Default for FrameBudget {
1288 fn default() -> Self {
1289 Self {
1290 target_ms: 16.0,
1291 allow_degradation: true,
1292 }
1293 }
1294}
1295
1296pub trait ElapsedTime {
1305 fn elapsed_time(&self) -> f32;
1307
1308 fn delta_time(&self) -> f32;
1310}
1311
1312pub trait Renderer: ElapsedTime + Send {
1320 fn request_redraw(&mut self) {}
1323
1324 fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
1326 fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
1327 fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
1329
1330 fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1332 fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
1333 fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1335 fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
1337 fn fill_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4]) {}
1339 fn stroke_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4], _stroke_width: f32) {}
1341
1342 fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
1344 fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
1346
1347 fn draw_texture(&mut self, _texture_id: u32, _rect: Rect) {}
1350 fn draw_image(&mut self, _image_name: &str, _rect: Rect) {}
1352 fn load_image(&mut self, _name: &str, _data: &[u8]) {}
1354
1355 fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
1358 fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
1360
1361 fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
1364
1365 fn draw_linear_gradient(
1368 &mut self,
1369 _rect: Rect,
1370 _start_color: [f32; 4],
1371 _end_color: [f32; 4],
1372 _angle: f32,
1373 ) {
1374 }
1375 fn draw_radial_gradient(
1377 &mut self,
1378 _rect: Rect,
1379 _inner_color: [f32; 4],
1380 _outer_color: [f32; 4],
1381 ) {
1382 }
1383 fn draw_drop_shadow(
1385 &mut self,
1386 _rect: Rect,
1387 _radius: f32,
1388 _color: [f32; 4],
1389 _blur: f32,
1390 _spread: f32,
1391 ) {
1392 }
1393 fn stroke_dashed_rounded_rect(
1395 &mut self,
1396 _rect: Rect,
1397 _radius: f32,
1398 _color: [f32; 4],
1399 _width: f32,
1400 _dash: f32,
1401 _gap: f32,
1402 ) {
1403 }
1404 fn draw_9slice(
1406 &mut self,
1407 _image_name: &str,
1408 _rect: Rect,
1409 _left: f32,
1410 _top: f32,
1411 _right: f32,
1412 _bottom: f32,
1413 ) {
1414 }
1415
1416 fn push_clip_rect(&mut self, _rect: Rect) {}
1420 fn pop_clip_rect(&mut self) {}
1422
1423 fn push_opacity(&mut self, _opacity: f32) {}
1427 fn pop_opacity(&mut self) {}
1429
1430 fn set_theme(&mut self, _theme: ColorTheme) {}
1432 fn set_rage(&mut self, _rage: f32) {}
1433 fn set_berserker_mode(&mut self, _state: BerserkerMode) {}
1434 fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
1435
1436 fn bifrost(&mut self, _rect: Rect, _blur: f32, _saturation: f32, _opacity: f32) {}
1439 fn gungnir(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32, _intensity: f32) {}
1441 fn push_mjolnir_slice(&mut self, _angle: f32, _offset: f32) {}
1443 fn pop_mjolnir_slice(&mut self) {}
1444 fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1446 fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1447 fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
1449
1450 fn set_aria_role(&mut self, _role: &str) {}
1452 fn set_aria_label(&mut self, _label: &str) {}
1453
1454 fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
1456
1457 fn set_key(&mut self, _key: &str) {}
1459
1460 fn get_telemetry(&self) -> TelemetryData {
1463 TelemetryData::default()
1464 }
1465
1466 fn push_shadow(&mut self, _radius: f32, _color: [f32; 4], _offset: [f32; 2]) {}
1469 fn pop_shadow(&mut self) {}
1471
1472 fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
1475 fn pop_vnode(&mut self) {}
1477 fn register_handler(
1479 &mut self,
1480 _event_type: &str,
1481 _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
1482 ) {
1483 }
1484
1485 fn set_z_index(&mut self, _z: f32) {}
1489 fn get_z_index(&self) -> f32 {
1491 0.0
1492 }
1493
1494 fn load_svg(&mut self, _name: &str, _svg_data: &[u8]) {}
1497 fn draw_svg(&mut self, _name: &str, _rect: Rect) {}
1499
1500 fn push_transform(&mut self, _translation: [f32; 2], _scale: [f32; 2], _rotation: f32) {}
1505 fn pop_transform(&mut self) {}
1507 fn query_layout(&self, _node_id: scene_graph::NodeId) -> Option<Rect> {
1509 None
1510 }
1511 fn set_debug_layout(&mut self, _enabled: bool) {}
1513 fn get_debug_layout(&self) -> bool {
1515 false
1516 }
1517}
1518#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
1520pub enum RenderTier {
1521 Tier1GPU = 0,
1523 Tier2GPU = 1,
1525 Tier3Fallback = 2,
1527}
1528use bytemuck::{Pod, Zeroable};
1532#[repr(C)]
1534#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1535pub struct ColorTheme {
1536 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
1538 pub glass_base: [f32; 4],
1539 pub glass_edge: [f32; 4],
1540 pub rune_glow: [f32; 4],
1541 pub ember_core: [f32; 4],
1542 pub background_deep: [f32; 4],
1543 pub glass_blur_strength: f32,
1544 pub shatter_edge_width: f32,
1545 pub neon_bloom_radius: f32,
1546 pub rune_opacity: f32, pub _pad: [f32; 3], pub _pad2: f32,
1550}
1551impl ColorTheme {
1552 pub fn cyberpunk_viking() -> Self {
1553 Self {
1554 primary_neon: [0.0, 1.0, 0.95, 1.2],
1555 shatter_neon: [1.0, 0.0, 0.75, 1.5],
1556 glass_base: [0.04, 0.04, 0.06, 0.82],
1557 glass_edge: [0.0, 0.45, 0.55, 0.6],
1558 rune_glow: [0.75, 0.98, 1.0, 0.9],
1559 ember_core: [0.95, 0.12, 0.12, 1.0],
1560 background_deep: [0.01, 0.01, 0.03, 1.0],
1561 glass_blur_strength: 0.6,
1562 shatter_edge_width: 1.8,
1563 neon_bloom_radius: 0.022,
1564 rune_opacity: 0.55,
1565 _pad: [0.0; 3],
1566 _pad2: 0.0,
1567 }
1568 }
1569 pub fn vibrant_glass() -> Self {
1570 Self {
1571 primary_neon: [0.0, 1.0, 0.95, 1.2],
1572 shatter_neon: [1.0, 0.0, 0.75, 1.5],
1573 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],
1576 ember_core: [1.0, 0.4, 0.1, 1.0],
1577 background_deep: [0.05, 0.05, 0.1, 1.0],
1578 glass_blur_strength: 0.9,
1579 shatter_edge_width: 1.8,
1580 neon_bloom_radius: 0.022,
1581 rune_opacity: 0.55,
1582 _pad: [0.0; 3],
1583 _pad2: 0.0,
1584 }
1585 }
1586}
1587impl Default for ColorTheme {
1588 fn default() -> Self {
1589 Self::vibrant_glass()
1590 }
1591}
1592#[repr(C)]
1594#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1595pub struct SceneUniforms {
1596 pub view: glam::Mat4,
1597 pub proj: glam::Mat4,
1598 pub time: f32,
1599 pub delta_time: f32,
1600 pub resolution: [f32; 2],
1601 pub mouse: [f32; 2],
1602 pub mouse_velocity: [f32; 2],
1603 pub shatter_origin: [f32; 2],
1604 pub shatter_time: f32,
1605 pub shatter_force: f32,
1606 pub berzerker_rage: f32,
1607 pub berzerker_mode: u32,
1608 pub scroll_offset: f32,
1609 pub scale_factor: f32,
1610}
1611impl SceneUniforms {
1612 pub fn new(width: f32, height: f32) -> Self {
1613 Self {
1614 view: glam::Mat4::IDENTITY,
1615 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
1616 time: 0.0,
1617 delta_time: 0.016,
1618 resolution: [width, height],
1619 mouse: [0.5, 0.5],
1620 mouse_velocity: [0.0, 0.0],
1621 shatter_origin: [0.5, 0.5],
1622 shatter_time: -100.0,
1623 shatter_force: 0.0,
1624 berzerker_rage: 0.0,
1625 berzerker_mode: 0,
1626 scroll_offset: 0.0,
1627 scale_factor: 1.0,
1628 }
1629 }
1630}
1631#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1633pub struct Mesh {
1634 pub vertices: Vec<[f32; 3]>,
1635 pub normals: Vec<[f32; 3]>,
1636 pub indices: Vec<u32>,
1637}
1638impl Mesh {
1639 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
1640 let mut cursor = std::io::Cursor::new(data);
1641 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
1642 Ok((Vec::new(), Default::default()))
1643 })?;
1644 let mut meshes = Vec::new();
1645 for m in models {
1646 let mesh = m.mesh;
1647 let vertices: Vec<[f32; 3]> = mesh
1648 .positions
1649 .chunks(3)
1650 .map(|c| [c[0], c[1], c[2]])
1651 .collect();
1652 let normals = if mesh.normals.is_empty() {
1653 vec![[0.0, 0.0, 1.0]; vertices.len()]
1654 } else {
1655 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
1656 };
1657 meshes.push(Mesh {
1658 vertices,
1659 normals,
1660 indices: mesh.indices,
1661 });
1662 }
1663 Ok(meshes)
1664 }
1665 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
1666 let mut cursor = std::io::Cursor::new(data);
1667 let stl = stl_io::read_stl(&mut cursor)?;
1668 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
1669 let mut indices = Vec::new();
1670 for face in stl.faces {
1671 indices.push(face.vertices[0] as u32);
1672 indices.push(face.vertices[1] as u32);
1673 indices.push(face.vertices[2] as u32);
1674 }
1675 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
1676 Ok(Mesh {
1677 vertices,
1678 normals,
1679 indices,
1680 })
1681 }
1682}
1683pub trait FrameRenderer<E = ()>: Renderer {
1686 fn begin_frame(&mut self) -> E;
1687 fn render_frame(&mut self) {
1688 }
1690 fn end_frame(&mut self, encoder: E);
1691}
1692use std::sync::Arc;
1693#[derive(Clone)]
1695pub struct State<T: Clone + Send + Sync + 'static> {
1696 swap: Arc<arc_swap::ArcSwap<T>>,
1697 metadata_swap: Arc<arc_swap::ArcSwap<Option<agents::MutationMetadata>>>,
1698 #[cfg(not(target_arch = "wasm32"))]
1699 tvar: Arc<stm::TVar<T>>,
1700 #[cfg(not(target_arch = "wasm32"))]
1701 metadata_tvar: Arc<stm::TVar<Option<agents::MutationMetadata>>>,
1702 subscribers: Arc<std::sync::Mutex<Vec<Box<dyn Fn(&T) + Send + Sync>>>>,
1703 version: Arc<std::sync::atomic::AtomicU64>,
1704 resolution: agents::ConflictResolution,
1705}
1706impl<T: Clone + Send + Sync + 'static> State<T> {
1707 pub fn new(value: T) -> Self {
1709 #[cfg(not(target_arch = "wasm32"))]
1710 let tvar = Arc::new(stm::TVar::new(value.clone()));
1711 #[cfg(not(target_arch = "wasm32"))]
1712 let metadata_tvar = Arc::new(stm::TVar::new(None));
1713 Self {
1714 swap: Arc::new(arc_swap::ArcSwap::from_pointee(value)),
1715 metadata_swap: Arc::new(arc_swap::ArcSwap::new(Arc::new(None))),
1716 #[cfg(not(target_arch = "wasm32"))]
1717 tvar,
1718 #[cfg(not(target_arch = "wasm32"))]
1719 metadata_tvar,
1720 subscribers: Arc::new(std::sync::Mutex::new(Vec::new())),
1721 version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
1722 resolution: agents::ConflictResolution::default(),
1723 }
1724 }
1725 pub fn with_resolution(mut self, resolution: agents::ConflictResolution) -> Self {
1727 self.resolution = resolution;
1728 self
1729 }
1730 pub fn get(&self) -> T {
1732 (**self.swap.load()).clone()
1733 }
1734 pub fn set(&self, value: T) {
1736 #[cfg(not(target_arch = "wasm32"))]
1737 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
1738 let new_meta = agents::get_current_mutation_metadata();
1739 let existing_meta = self.metadata_tvar.read(tx)?;
1740 let mut skip = false;
1741 if self.resolution == agents::ConflictResolution::PriorityWins
1742 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
1743 && new_m.priority < old_m.priority {
1744 skip = true;
1745 }
1746 if !skip {
1747 self.tvar.write(tx, value.clone())?;
1748 self.metadata_tvar.write(tx, new_meta)?;
1749 Ok((false, value.clone(), new_meta))
1750 } else {
1751 Ok((true, self.tvar.read(tx)?, existing_meta))
1752 }
1753 });
1754 #[cfg(target_arch = "wasm32")]
1755 let (was_skipped, final_val, final_meta) = (false, value, agents::get_current_mutation_metadata());
1756 if was_skipped {
1757 if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
1758 agents::notify_conflict(agents::ConflictEvent {
1759 agent_id: new_m.agent_id,
1760 priority: new_m.priority,
1761 existing_agent_id: old_m.agent_id,
1762 existing_priority: old_m.priority,
1763 timestamp_ms: new_m.timestamp_ms,
1764 });
1765 }
1766 return;
1767 }
1768 self.swap.store(Arc::new(final_val.clone()));
1769 self.metadata_swap.store(Arc::new(final_meta));
1770 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
1771 let subs = Arc::clone(&self.subscribers);
1772 if crate::is_batching() {
1773 crate::enqueue_batch_task(Box::new(move || {
1774 let s = subs.lock().unwrap();
1775 for cb in s.iter() {
1776 cb(&final_val);
1777 }
1778 }));
1779 } else {
1780 let s = subs.lock().unwrap();
1781 for cb in s.iter() {
1782 cb(&final_val);
1783 }
1784 }
1785 }
1786 pub fn mutate<F: Fn(&T) -> T>(&self, f: F) {
1787 #[cfg(not(target_arch = "wasm32"))]
1788 {
1789 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
1790 let new_meta = agents::get_current_mutation_metadata();
1791 let existing_meta = self.metadata_tvar.read(tx)?;
1792 let mut skip = false;
1793 if self.resolution == agents::ConflictResolution::PriorityWins
1794 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
1795 && new_m.priority < old_m.priority {
1796 skip = true;
1797 }
1798 if !skip {
1799 let current = self.tvar.read(tx)?;
1800 let next = f(¤t);
1801 self.tvar.write(tx, next.clone())?;
1802 self.metadata_tvar.write(tx, new_meta)?;
1803 Ok((false, next, new_meta))
1804 } else {
1805 Ok((true, self.tvar.read(tx)?, existing_meta))
1806 }
1807 });
1808 if was_skipped {
1809 if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
1810 agents::notify_conflict(agents::ConflictEvent {
1811 agent_id: new_m.agent_id,
1812 priority: new_m.priority,
1813 existing_agent_id: old_m.agent_id,
1814 existing_priority: old_m.priority,
1815 timestamp_ms: new_m.timestamp_ms,
1816 });
1817 }
1818 return;
1819 }
1820 self.swap.store(Arc::new(final_val.clone()));
1821 self.metadata_swap.store(Arc::new(final_meta));
1822 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
1823 let subs = Arc::clone(&self.subscribers);
1824 if crate::is_batching() {
1825 crate::enqueue_batch_task(Box::new(move || {
1826 let s = subs.lock().unwrap();
1827 for cb in s.iter() {
1828 cb(&final_val);
1829 }
1830 }));
1831 } else {
1832 let s = subs.lock().unwrap();
1833 for cb in s.iter() {
1834 cb(&final_val);
1835 }
1836 }
1837 }
1838 #[cfg(target_arch = "wasm32")]
1839 {
1840 self.set(f(&self.get()));
1841 }
1842 }
1843 pub fn version(&self) -> u64 {
1845 self.version.load(std::sync::atomic::Ordering::Acquire)
1846 }
1847 pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
1849 self.subscribers.lock().unwrap().push(Box::new(callback));
1850 }
1851}
1852use crate::runtime::NodeStateSnapshot;
1853use std::sync::atomic::{AtomicBool, Ordering};
1854use std::sync::OnceLock;
1855pub static SYSTEM_STATE: OnceLock<Arc<arc_swap::ArcSwap<KnowledgeState>>> = OnceLock::new();
1857#[cfg(not(target_arch = "wasm32"))]
1858static KNOWLEDGE_TVAR: OnceLock<stm::TVar<KnowledgeState>> = OnceLock::new();
1859static IS_BATCHING: AtomicBool = AtomicBool::new(false);
1860pub static IS_RENDERING: AtomicBool = AtomicBool::new(false);
1861pub static LAYOUT_DIRTY: AtomicBool = AtomicBool::new(false);
1862static BATCH_QUEUE: OnceLock<std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync>>>> = OnceLock::new();
1863pub fn is_batching() -> bool {
1865 IS_BATCHING.load(Ordering::Acquire)
1866}
1867pub fn is_rendering() -> bool {
1869 IS_RENDERING.load(Ordering::Acquire)
1870}
1871pub fn begin_render_phase() {
1873 IS_RENDERING.store(true, Ordering::Release);
1874}
1875pub fn end_render_phase() {
1877 IS_RENDERING.store(false, Ordering::Release);
1878}
1879pub fn enqueue_batch_task(task: Box<dyn FnOnce() + Send + Sync>) {
1881 let mut queue = BATCH_QUEUE
1882 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
1883 .lock()
1884 .unwrap();
1885 queue.push(task);
1886}
1887pub fn batch<F: FnOnce()>(f: F) {
1891 if IS_BATCHING.swap(true, Ordering::AcqRel) {
1892 f();
1894 return;
1895 }
1896 f();
1897 IS_BATCHING.store(false, Ordering::Release);
1898 let mut queue = BATCH_QUEUE
1899 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
1900 .lock()
1901 .unwrap();
1902 let tasks: Vec<_> = queue.drain(..).collect();
1903 drop(queue);
1904 for task in tasks {
1905 task();
1906 }
1907}
1908pub fn get_system_state() -> Arc<arc_swap::ArcSwap<KnowledgeState>> {
1910 SYSTEM_STATE
1911 .get_or_init(|| Arc::new(arc_swap::ArcSwap::from_pointee(KnowledgeState::default())))
1912 .clone()
1913}
1914pub fn load_system_state() -> arc_swap::Guard<Arc<KnowledgeState>> {
1915 get_system_state().load()
1916}
1917pub fn update_system_state<F>(f: F)
1918where
1919 F: Fn(&KnowledgeState) -> KnowledgeState,
1920{
1921 if is_rendering() {
1922 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1923 }
1924 LAYOUT_DIRTY.store(true, Ordering::SeqCst);
1925 let swap = get_system_state();
1926 let current = swap.load();
1927 let new_state = Arc::new(f(¤t));
1928 swap.store(Arc::clone(&new_state));
1929 #[cfg(not(target_arch = "wasm32"))]
1930 {
1931 let tvar = KNOWLEDGE_TVAR
1932 .get_or_init(|| stm::TVar::new((*new_state).clone()));
1933 stm::atomically(|tx| tvar.write(tx, (*new_state).clone()));
1934 }
1935}
1936pub fn transact_system_state<F>(f: F)
1937where
1938 F: Fn(&KnowledgeState) -> KnowledgeState,
1939{
1940 #[cfg(not(target_arch = "wasm32"))]
1941 {
1942 if is_rendering() {
1943 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1944 }
1945 let tvar = KNOWLEDGE_TVAR
1946 .get_or_init(|| {
1947 stm::TVar::new((**get_system_state().load()).clone())
1948 })
1949 .clone();
1950 let new_state = stm::atomically(move |tx| {
1951 let current = tvar.read(tx)?;
1952 let next = f(¤t);
1953 tvar.write(tx, next.clone())?;
1954 Ok(next)
1955 });
1956 get_system_state().store(Arc::new(new_state));
1957 }
1958 #[cfg(target_arch = "wasm32")]
1959 {
1960 if is_rendering() {
1961 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1962 }
1963 update_system_state(f);
1964 }
1965}
1966impl KnowledgeState {
1967 pub fn new() -> Self {
1969 Self::default()
1970 }
1971 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
1973 self.component_states
1974 .insert(id, Arc::new(std::sync::RwLock::new(state)));
1975 }
1976pub fn get_component_state<T: 'static + Send + Sync>(
1978 &self,
1979 id: u64,
1980 ) -> Option<Arc<std::sync::RwLock<T>>> {
1981 let lock = self.component_states.get(&id)?;
1982 let _inner: &std::sync::RwLock<dyn std::any::Any + Send + Sync> = lock;
1984 None }
1988 pub fn remember(&mut self, fragment: KnowledgeFragment) {
1990 self.fragments.insert(fragment.id.clone(), fragment);
1991 }
1992 pub fn process_query(&mut self, query: &str) {
1994 let query_lower = query.to_lowercase();
1995 let mut results: Vec<(f32, String)> = self
1996 .fragments
1997 .iter()
1998 .map(|(id, frag)| {
1999 let mut score = 0.0;
2000 if frag.summary.to_lowercase().contains(&query_lower) {
2001 score += 1.0;
2002 }
2003 if frag.source.to_lowercase().contains(&query_lower) {
2004 score += 0.5;
2005 }
2006 (score, id.clone())
2007 })
2008 .filter(|(score, _)| *score > 0.0)
2009 .collect();
2010 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
2012 self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
2013 }
2014 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
2016 let mut snapshots = Vec::new();
2017 for frag in self.fragments.values() {
2019 if let Ok(val) = serde_json::to_value(frag) {
2020 snapshots.push(NodeStateSnapshot { id: 0, state: val });
2021 }
2022 }
2023 snapshots
2024 }
2025}
2026#[derive(Clone)]
2028pub struct Binding<T: Clone + Send + Sync + 'static> {
2029 swap: Arc<arc_swap::ArcSwap<T>>,
2030 #[cfg(not(target_arch = "wasm32"))]
2031 tvar: Arc<stm::TVar<T>>,
2032 version: Arc<std::sync::atomic::AtomicU64>,
2033}
2034impl<T: Clone + Send + Sync + 'static> Binding<T> {
2035 pub fn from_state(state: &State<T>) -> Self {
2037 Self {
2038 swap: Arc::clone(&state.swap),
2039 #[cfg(not(target_arch = "wasm32"))]
2040 tvar: Arc::clone(&state.tvar),
2041 version: Arc::clone(&state.version),
2042 }
2043 }
2044 pub fn get(&self) -> T {
2046 (**self.swap.load()).clone()
2047 }
2048 pub fn set(&self, value: T) {
2050 self.swap.store(Arc::new(value.clone()));
2051 #[cfg(not(target_arch = "wasm32"))]
2052 {
2053 let tvar = Arc::clone(&self.tvar);
2054 let v = value.clone();
2055 stm::atomically(move |tx| tvar.write(tx, v.clone()));
2056 }
2057 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2058 }
2059 pub fn version(&self) -> u64 {
2061 self.version.load(std::sync::atomic::Ordering::Acquire)
2062 }
2063}
2064#[cfg(not(target_arch = "wasm32"))]
2065pub fn transact_pair<A, B, F>(state_a: &State<A>, state_b: &State<B>, f: F)
2066where
2067 A: Clone + Send + Sync + 'static,
2068 B: Clone + Send + Sync + 'static,
2069 F: Fn(&A, &B) -> (A, B),
2070{
2071 let tvar_a = Arc::clone(&state_a.tvar);
2072 let tvar_b = Arc::clone(&state_b.tvar);
2073 let (new_a, new_b) = stm::atomically(move |tx| {
2074 let a = tvar_a.read(tx)?;
2075 let b = tvar_b.read(tx)?;
2076 let (na, nb) = f(&a, &b);
2077 tvar_a.write(tx, na.clone())?;
2078 tvar_b.write(tx, nb.clone())?;
2079 Ok((na, nb))
2080 });
2081 state_a.swap.store(Arc::new(new_a.clone()));
2082 state_b.swap.store(Arc::new(new_b.clone()));
2083 state_a.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2084 state_b.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2085 let subs_a = Arc::clone(&state_a.subscribers);
2086 let subs_b = Arc::clone(&state_b.subscribers);
2087 if crate::is_batching() {
2088 crate::enqueue_batch_task(Box::new(move || {
2089 {
2090 let s = subs_a.lock().unwrap();
2091 for cb in s.iter() { cb(&new_a); }
2092 }
2093 {
2094 let s = subs_b.lock().unwrap();
2095 for cb in s.iter() { cb(&new_b); }
2096 }
2097 }));
2098 } else {
2099 {
2100 let s = subs_a.lock().unwrap();
2101 for cb in s.iter() { cb(&new_a); }
2102 }
2103 {
2104 let s = subs_b.lock().unwrap();
2105 for cb in s.iter() { cb(&new_b); }
2106 }
2107 }
2108}
2109use std::any::TypeId;
2110use std::sync::Mutex;
2111pub(crate) static ENVIRONMENT: OnceLock<
2113 Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
2114> = OnceLock::new();
2115pub trait EnvKey: 'static + Send + Sync {
2119 type Value: Clone + Send + Sync + 'static;
2121 fn default_value() -> Self::Value;
2123}
2124pub struct YggdrasilKey;
2126impl EnvKey for YggdrasilKey {
2127 type Value = YggdrasilTokens;
2128 fn default_value() -> Self::Value {
2129 default_tokens()
2130 }
2131}
2132#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2135pub enum Appearance {
2136 Light,
2137 Dark,
2138}
2139#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2141pub enum Orientation {
2142 Horizontal,
2143 Vertical,
2144}
2145#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2147pub enum Alignment {
2148 #[default]
2149 Center,
2150 Leading,
2151 Trailing,
2152 Top,
2153 Bottom,
2154}
2155#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2157pub enum Distribution {
2158 #[default]
2159 Fill,
2160 Center,
2161 Leading,
2162 Trailing,
2163 SpaceBetween,
2164 SpaceAround,
2165 SpaceEvenly,
2166}
2167#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2169pub struct Color {
2170 pub r: f32,
2171 pub g: f32,
2172 pub b: f32,
2173 pub a: f32,
2174}
2175impl Color {
2176 pub const BLACK: Color = Color {
2177 r: 0.0,
2178 g: 0.0,
2179 b: 0.0,
2180 a: 1.0,
2181 };
2182 pub const WHITE: Color = Color {
2183 r: 1.0,
2184 g: 1.0,
2185 b: 1.0,
2186 a: 1.0,
2187 };
2188 pub const TRANSPARENT: Color = Color {
2189 r: 0.0,
2190 g: 0.0,
2191 b: 0.0,
2192 a: 0.0,
2193 };
2194 pub const RED: Color = Color {
2195 r: 1.0,
2196 g: 0.0,
2197 b: 0.0,
2198 a: 1.0,
2199 };
2200 pub const GREEN: Color = Color {
2201 r: 0.0,
2202 g: 1.0,
2203 b: 0.0,
2204 a: 1.0,
2205 };
2206 pub const BLUE: Color = Color {
2207 r: 0.0,
2208 g: 0.0,
2209 b: 1.0,
2210 a: 1.0,
2211 };
2212 pub fn relative_luminance(&self) -> f32 {
2214 fn res(c: f32) -> f32 {
2215 if c <= 0.03928 {
2216 c / 12.92
2217 } else {
2218 ((c + 0.055) / 1.055).powf(2.4)
2219 }
2220 }
2221 0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
2222 }
2223 pub fn contrast_ratio(&self, other: &Color) -> f32 {
2225 let l1 = self.relative_luminance();
2226 let l2 = other.relative_luminance();
2227 if l1 > l2 {
2228 (l1 + 0.05) / (l2 + 0.05)
2229 } else {
2230 (l2 + 0.05) / (l1 + 0.05)
2231 }
2232 }
2233 pub const CYAN: Color = Color {
2234 r: 0.0,
2235 g: 1.0,
2236 b: 1.0,
2237 a: 1.0,
2238 };
2239 pub const YELLOW: Color = Color {
2240 r: 1.0,
2241 g: 1.0,
2242 b: 0.0,
2243 a: 1.0,
2244 };
2245 pub const MAGENTA: Color = Color {
2246 r: 1.0,
2247 g: 0.0,
2248 b: 1.0,
2249 a: 1.0,
2250 };
2251 pub const GRAY: Color = Color {
2252 r: 0.5,
2253 g: 0.5,
2254 b: 0.5,
2255 a: 1.0,
2256 };
2257 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
2259 Self { r, g, b, a }
2260 }
2261 pub fn as_array(&self) -> [f32; 4] {
2263 [self.r, self.g, self.b, self.a]
2264 }
2265}
2266impl View for Color {
2267 type Body = Never;
2268 fn body(self) -> Self::Body {
2269 unreachable!()
2270 }
2271 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
2272 renderer.fill_rect(rect, self.as_array());
2273 }
2274}
2275pub struct AppearanceKey;
2277impl EnvKey for AppearanceKey {
2278 type Value = Appearance;
2279 fn default_value() -> Self::Value {
2280 Appearance::Dark }
2282}
2283pub struct StyleResolver;
2285impl StyleResolver {
2286 pub fn color(key: &str) -> String {
2288 let tokens = Environment::<YggdrasilKey>::new().get();
2289 let appearance = Environment::<AppearanceKey>::new().get();
2290 let is_dark = appearance == Appearance::Dark;
2291 tokens
2292 .get_color(key, is_dark)
2293 .unwrap_or_else(|| "#FF00FF".to_string()) }
2295 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
2297 let tokens = Environment::<YggdrasilKey>::new().get();
2298 let appearance = Environment::<AppearanceKey>::new().get();
2299 let is_dark = appearance == Appearance::Dark;
2300 tokens.get(category, key, is_dark)
2301 }
2302}
2303pub fn default_tokens() -> YggdrasilTokens {
2305 let mut tokens = YggdrasilTokens::new();
2306 tokens.color.insert(
2308 "background".to_string(),
2309 TokenValue::Single {
2310 value: "#000000".to_string(), },
2312 );
2313 tokens.color.insert(
2314 "primary".to_string(),
2315 TokenValue::Single {
2316 value: "#00FFFF".to_string(), },
2318 );
2319 tokens.color.insert(
2320 "secondary".to_string(),
2321 TokenValue::Single {
2322 value: "#FF00FF".to_string(), },
2324 );
2325 tokens.color.insert(
2326 "surface".to_string(),
2327 TokenValue::Adaptive {
2328 light: "#FFFFFF".to_string(),
2329 dark: "#121212".to_string(),
2330 },
2331 );
2332 tokens.color.insert(
2333 "text".to_string(),
2334 TokenValue::Adaptive {
2335 light: "#000000".to_string(),
2336 dark: "#FFFFFF".to_string(),
2337 },
2338 );
2339 tokens.bifrost.insert(
2341 "blur".to_string(),
2342 TokenValue::Single {
2343 value: "25.0".to_string(),
2344 },
2345 );
2346 tokens.bifrost.insert(
2347 "saturation".to_string(),
2348 TokenValue::Single {
2349 value: "1.2".to_string(),
2350 },
2351 );
2352 tokens.bifrost.insert(
2353 "opacity".to_string(),
2354 TokenValue::Single {
2355 value: "0.65".to_string(),
2356 },
2357 );
2358 tokens.gungnir.insert(
2360 "intensity".to_string(),
2361 TokenValue::Single {
2362 value: "1.0".to_string(),
2363 },
2364 );
2365 tokens.gungnir.insert(
2366 "radius".to_string(),
2367 TokenValue::Single {
2368 value: "15.0".to_string(),
2369 },
2370 );
2371 tokens.mjolnir.insert(
2373 "clip_angle".to_string(),
2374 TokenValue::Single {
2375 value: "12.0".to_string(),
2376 },
2377 );
2378 tokens.mjolnir.insert(
2379 "border_width".to_string(),
2380 TokenValue::Single {
2381 value: "2.0".to_string(),
2382 },
2383 );
2384 tokens.anim.insert(
2386 "stiffness".to_string(),
2387 TokenValue::Single {
2388 value: "170.0".to_string(),
2389 },
2390 );
2391 tokens.anim.insert(
2392 "damping".to_string(),
2393 TokenValue::Single {
2394 value: "26.0".to_string(),
2395 },
2396 );
2397 tokens.anim.insert(
2398 "mass".to_string(),
2399 TokenValue::Single {
2400 value: "1.0".to_string(),
2401 },
2402 );
2403 tokens.accessibility.insert(
2405 "reduce_motion".to_string(),
2406 TokenValue::Single {
2407 value: "false".to_string(),
2408 },
2409 );
2410 tokens
2411}
2412pub struct Environment<K: EnvKey> {
2414 _marker: std::marker::PhantomData<K>,
2415}
2416impl<K: EnvKey> Default for Environment<K> {
2417 fn default() -> Self {
2418 Self::new()
2419 }
2420}
2421impl<K: EnvKey> Environment<K> {
2422 pub fn new() -> Self {
2424 Self {
2425 _marker: std::marker::PhantomData,
2426 }
2427 }
2428 pub fn get(&self) -> K::Value {
2430 if let Some(env_store) = ENVIRONMENT.get() {
2431 let env_lock = env_store.lock().unwrap();
2432 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
2433 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
2434 return typed_val.clone();
2435 } else {
2436 log::warn!("Environment: Downcast failed for key type {:?}", std::any::type_name::<K>());
2437 }
2438 } else {
2439 log::debug!("Environment: Key not found: {:?}. Returning default.", std::any::type_name::<K>());
2440 }
2441 } else {
2442 log::debug!("Environment: Store not initialized. Key: {:?}. Returning default.", std::any::type_name::<K>());
2443 }
2444 K::default_value()
2445 }
2446}
2447pub mod env {
2449 pub fn insert<K: super::EnvKey>(value: K::Value) {
2451 let store = super::ENVIRONMENT.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
2452 let mut env_map = store.lock().unwrap();
2453 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
2454 }
2455 pub fn remove<K: super::EnvKey>() {
2457 if let Some(store) = super::ENVIRONMENT.get() {
2458 let mut env_map = store.lock().unwrap();
2459 env_map.remove(&std::any::TypeId::of::<K>());
2460 }
2461 }
2462}
2463#[derive(Debug, Clone, Copy, PartialEq)]
2466pub struct Size {
2467 pub width: f32,
2468 pub height: f32,
2469}
2470
2471impl Size {
2472 pub const ZERO: Self = Self { width: 0.0, height: 0.0 };
2473
2474 pub fn new(width: f32, height: f32) -> Self {
2475 Self { width, height }
2476 }
2477}
2478
2479#[derive(Debug, Clone, Copy, PartialEq)]
2481pub struct EdgeInsets {
2482 pub top: f32,
2483 pub leading: f32,
2484 pub bottom: f32,
2485 pub trailing: f32,
2486}
2487
2488impl EdgeInsets {
2489 pub fn all(value: f32) -> Self {
2491 Self {
2492 top: value,
2493 leading: value,
2494 bottom: value,
2495 trailing: value,
2496 }
2497 }
2498
2499 pub fn vertical(value: f32) -> Self {
2501 Self {
2502 top: value,
2503 leading: 0.0,
2504 bottom: value,
2505 trailing: 0.0,
2506 }
2507 }
2508
2509 pub fn horizontal(value: f32) -> Self {
2511 Self {
2512 top: 0.0,
2513 leading: value,
2514 bottom: 0.0,
2515 trailing: value,
2516 }
2517 }
2518}
2519
2520#[derive(Debug, Clone, Copy, PartialEq)]
2522pub struct FrameModifier {
2523 pub width: Option<f32>,
2524 pub height: Option<f32>,
2525}
2526
2527impl Default for FrameModifier {
2528 fn default() -> Self {
2529 Self::new()
2530 }
2531}
2532
2533impl FrameModifier {
2534 pub fn new() -> Self {
2535 Self {
2536 width: None,
2537 height: None,
2538 }
2539 }
2540
2541 pub fn width(mut self, width: f32) -> Self {
2542 self.width = Some(width);
2543 self
2544 }
2545
2546 pub fn height(mut self, height: f32) -> Self {
2547 self.height = Some(height);
2548 self
2549 }
2550
2551 pub fn size(mut self, width: f32, height: f32) -> Self {
2552 self.width = Some(width);
2553 self.height = Some(height);
2554 self
2555 }
2556}
2557
2558impl ViewModifier for FrameModifier {
2559 fn modify<V: View>(self, content: V) -> impl View {
2560 ModifiedView::new(content, self)
2561 }
2562}
2563
2564#[derive(Debug, Clone, Copy, PartialEq)]
2566pub struct FlexModifier {
2567 pub weight: f32,
2568}
2569
2570impl ViewModifier for FlexModifier {
2571 fn modify<V: View>(self, content: V) -> impl View {
2572 ModifiedView::new(content, self)
2573 }
2574
2575 fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
2576 self.weight
2577 }
2578}
2579
2580#[derive(Debug, Clone, Copy, PartialEq)]
2582pub struct OffsetModifier {
2583 pub x: f32,
2584 pub y: f32,
2585}
2586
2587impl OffsetModifier {
2588 pub fn new(x: f32, y: f32) -> Self {
2589 Self { x, y }
2590 }
2591}
2592
2593impl ViewModifier for OffsetModifier {
2594 fn modify<V: View>(self, content: V) -> impl View {
2595 ModifiedView::new(content, self)
2596 }
2597}
2598
2599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2601pub struct ZIndexModifier {
2602 pub z_index: i32,
2603}
2604
2605impl ZIndexModifier {
2606 pub fn new(z_index: i32) -> Self {
2607 Self { z_index }
2608 }
2609}
2610
2611impl ViewModifier for ZIndexModifier {
2612 fn modify<V: View>(self, content: V) -> impl View {
2613 ModifiedView::new(content, self)
2614 }
2615}
2616
2617#[derive(Debug, Clone, Copy, PartialEq, Default)]
2619pub struct LayoutConstraints {
2620 pub min_width: Option<f32>,
2621 pub max_width: Option<f32>,
2622 pub min_height: Option<f32>,
2623 pub max_height: Option<f32>,
2624}
2625
2626#[derive(Debug, Clone, Copy, PartialEq)]
2628pub struct LayoutModifier {
2629 pub constraints: LayoutConstraints,
2630}
2631
2632impl LayoutModifier {
2633 pub fn new(constraints: LayoutConstraints) -> Self {
2634 Self { constraints }
2635 }
2636}
2637
2638impl ViewModifier for LayoutModifier {
2639 fn modify<V: View>(self, content: V) -> impl View {
2640 ModifiedView::new(content, self)
2641 }
2642}
2643
2644#[derive(Debug, Clone, Copy, PartialEq)]
2646pub struct SafeAreaModifier {
2647 pub ignores: bool,
2648}
2649
2650impl ViewModifier for SafeAreaModifier {
2651 fn modify<V: View>(self, content: V) -> impl View {
2652 ModifiedView::new(content, self)
2653 }
2654}
2655
2656#[derive(Debug, Clone, Copy, PartialEq)]
2658pub struct ElevationModifier {
2659 pub level: f32,
2660}
2661
2662impl ViewModifier for ElevationModifier {
2663 fn modify<V: View>(self, content: V) -> impl View {
2664 ModifiedView::new(content, self)
2665 }
2666
2667 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
2668 if self.level > 0.0 {
2669 let radius = self.level * 2.0;
2670 let offset_y = self.level * 0.5;
2671 let shadow_color = [0.0, 0.0, 0.0, 0.3];
2672 renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
2673 view.render(renderer, rect);
2674 renderer.pop_shadow();
2675 } else {
2676 view.render(renderer, rect);
2677 }
2678 }
2679}
2680
2681pub mod layout {
2683 use super::*;
2684
2685 pub struct LayoutCache {
2687 pub safe_area: SafeArea,
2688 size_cache: HashMap<(u64, u32, u32), Size>, }
2690
2691 impl Default for LayoutCache {
2692 fn default() -> Self {
2693 Self::new()
2694 }
2695 }
2696
2697 impl LayoutCache {
2698 pub fn new() -> Self {
2699 Self {
2700 safe_area: SafeArea::default(),
2701 size_cache: HashMap::new(),
2702 }
2703 }
2704
2705 pub fn clear(&mut self) {
2706 self.safe_area = SafeArea::default();
2707 self.size_cache.clear();
2708 }
2709
2710 pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
2711 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2712 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2713 self.size_cache.get(&(view_hash, pw, ph)).copied()
2714 }
2715
2716 pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: Size) {
2717 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2718 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2719 self.size_cache.insert((view_hash, pw, ph), size);
2720 }
2721
2722 pub fn invalidate_view(&mut self, view_hash: u64) {
2724 self.size_cache.retain(|&(hash, _, _), _| hash != view_hash);
2725 }
2726 }
2727
2728 #[derive(Debug, Clone, Copy, PartialEq)]
2730 pub struct SizeProposal {
2731 pub width: Option<f32>,
2732 pub height: Option<f32>,
2733 }
2734
2735 impl SizeProposal {
2736 pub fn unspecified() -> Self {
2737 Self {
2738 width: None,
2739 height: None,
2740 }
2741 }
2742
2743 pub fn width(width: f32) -> Self {
2744 Self {
2745 width: Some(width),
2746 height: None,
2747 }
2748 }
2749
2750 pub fn height(height: f32) -> Self {
2751 Self {
2752 width: None,
2753 height: Some(height),
2754 }
2755 }
2756
2757 pub fn tight(width: f32, height: f32) -> Self {
2758 Self {
2759 width: Some(width),
2760 height: Some(height),
2761 }
2762 }
2763
2764 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
2765 Self { width, height }
2766 }
2767 }
2768
2769 pub trait LayoutView: Send {
2771 fn size_that_fits(
2773 &self,
2774 proposal: SizeProposal,
2775 subviews: &[&dyn LayoutView],
2776 cache: &mut LayoutCache,
2777 ) -> Size;
2778
2779 fn place_subviews(
2781 &self,
2782 bounds: Rect,
2783 subviews: &mut [&mut dyn LayoutView],
2784 cache: &mut LayoutCache,
2785 );
2786
2787 fn flex_weight(&self) -> f32 {
2789 0.0
2790 }
2791 }
2792 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2794 pub struct EdgeInsets {
2795 pub top: f32,
2796 pub leading: f32,
2797 pub bottom: f32,
2798 pub trailing: f32,
2799 }
2800
2801 impl EdgeInsets {
2802 pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
2803 Self { top, leading, bottom, trailing }
2804 }
2805
2806 pub fn all(value: f32) -> Self {
2807 Self {
2808 top: value,
2809 leading: value,
2810 bottom: value,
2811 trailing: value,
2812 }
2813 }
2814 }
2815
2816 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2818 pub struct SafeArea {
2819 pub insets: EdgeInsets,
2820 }
2821
2822 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2824 pub struct Rect {
2825 pub x: f32,
2826 pub y: f32,
2827 pub width: f32,
2828 pub height: f32,
2829 }
2830
2831 impl Rect {
2832 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
2833 Self {
2834 x,
2835 y,
2836 width,
2837 height,
2838 }
2839 }
2840
2841 pub fn zero() -> Self {
2842 Self {
2843 x: 0.0,
2844 y: 0.0,
2845 width: 0.0,
2846 height: 0.0,
2847 }
2848 }
2849
2850 pub fn contains(&self, x: f32, y: f32) -> bool {
2851 x >= self.x && x <= self.x + self.width && y >= self.y && y <= self.y + self.height
2852 }
2853
2854 pub fn size(&self) -> Size {
2855 Size {
2856 width: self.width,
2857 height: self.height,
2858 }
2859 }
2860
2861 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
2863 if n == 0 {
2864 return vec![];
2865 }
2866 let item_width = self.width / n as f32;
2867 (0..n)
2868 .map(|i| Rect {
2869 x: self.x + i as f32 * item_width,
2870 y: self.y,
2871 width: item_width,
2872 height: self.height,
2873 })
2874 .collect()
2875 }
2876
2877 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
2879 if n == 0 {
2880 return vec![];
2881 }
2882 let item_height = self.height / n as f32;
2883 (0..n)
2884 .map(|i| Rect {
2885 x: self.x,
2886 y: self.y + i as f32 * item_height,
2887 width: self.width,
2888 height: item_height,
2889 })
2890 .collect()
2891 }
2892 }
2893}
2894
2895pub use layout::{LayoutCache, LayoutView, Rect, SizeProposal};
2897pub mod runtime;
2900pub mod scene_graph;
2901pub mod agents;
2902pub mod material;
2903
2904
2905pub use scene_graph::{NodeId, bifrost_registry};
2906
2907pub trait AssetManager: Send + Sync {
2911 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
2913
2914 fn preload_image(&self, url: &str);
2916}
2917
2918#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2920pub enum Event {
2921 PointerDown { x: f32, y: f32 },
2922 PointerUp { x: f32, y: f32 },
2923 PointerMove { x: f32, y: f32 },
2924 PointerClick { x: f32, y: f32 },
2925 PointerEnter,
2926 PointerLeave,
2927 KeyDown { key: String },
2928 KeyUp { key: String },
2929 Ime(String),
2931}
2932
2933impl Event {
2934 pub fn name(&self) -> &'static str {
2936 match self {
2937 Self::PointerDown { .. } => "pointerdown",
2938 Self::PointerUp { .. } => "pointerup",
2939 Self::PointerMove { .. } => "pointermove",
2940 Self::PointerClick { .. } => "pointerclick",
2941 Self::PointerEnter => "pointerenter",
2942 Self::PointerLeave => "pointerleave",
2943 Self::KeyDown { .. } => "keydown",
2944 Self::KeyUp { .. } => "keyup",
2945 Self::Ime(_) => "ime",
2946 }
2947 }
2948}
2949
2950#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2952pub enum EventResponse {
2953 Handled,
2954 Ignored,
2955}
2956
2957pub struct DefaultAssetManager {
2959 cache: Arc<arc_swap::ArcSwap<HashMap<String, AssetState<Arc<Vec<u8>>>>>>,
2960}
2961
2962impl Default for DefaultAssetManager {
2963 fn default() -> Self {
2964 Self::new()
2965 }
2966}
2967
2968impl DefaultAssetManager {
2969 pub fn new() -> Self {
2970 Self {
2971 cache: Arc::new(arc_swap::ArcSwap::from_pointee(HashMap::new())),
2972 }
2973 }
2974}
2975
2976impl AssetManager for DefaultAssetManager {
2977 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
2978 if let Some(state) = self.cache.load().get(url) {
2979 return state.clone();
2980 }
2981
2982 self.cache.rcu(|map| {
2983 let mut m = (**map).clone();
2984 m.entry(url.to_string()).or_insert(AssetState::Loading);
2985 m
2986 });
2987 AssetState::Loading
2988 }
2989
2990 fn preload_image(&self, _url: &str) {}
2991}
2992
2993use std::future::Future;
2994
2995pub struct Suspense<T: Clone + Send + Sync + 'static> {
2998 inner: State<AssetState<T>>,
2999}
3000
3001impl<T: Clone + Send + Sync + 'static> Default for Suspense<T> {
3002 fn default() -> Self {
3003 Self::new()
3004 }
3005}
3006
3007impl<T: Clone + Send + Sync + 'static> Suspense<T> {
3008 pub fn new() -> Self {
3009 Self {
3010 inner: State::new(AssetState::Loading),
3011 }
3012 }
3013
3014 pub fn new_async<F>(future: F) -> Self
3015 where
3016 F: Future<Output = Result<T, String>> + Send + 'static,
3017 {
3018 let suspense = Self::new();
3019 let suspense_clone = suspense.clone();
3020
3021 #[cfg(not(target_arch = "wasm32"))]
3022 {
3023 if let Ok(handle) = tokio::runtime::Handle::try_current() {
3025 handle.spawn(async move {
3026 let result = future.await;
3027 match result {
3028 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3029 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3030 }
3031 });
3032 } else {
3033 std::thread::spawn(move || {
3034 let rt = tokio::runtime::Builder::new_current_thread()
3035 .enable_all()
3036 .build()
3037 .unwrap();
3038 rt.block_on(async {
3039 let result = future.await;
3040 match result {
3041 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3042 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3043 }
3044 });
3045 });
3046 }
3047 }
3048 #[cfg(target_arch = "wasm32")]
3049 {
3050 wasm_bindgen_futures::spawn_local(async move {
3051 let result = future.await;
3052 match result {
3053 Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
3054 Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
3055 }
3056 });
3057 }
3058
3059 suspense
3060 }
3061
3062 pub fn ready(value: T) -> Self {
3063 Self {
3064 inner: State::new(AssetState::Ready(value)),
3065 }
3066 }
3067
3068 pub fn error(message: impl Into<String>) -> Self {
3069 Self {
3070 inner: State::new(AssetState::Error(message.into())),
3071 }
3072 }
3073
3074 pub fn get(&self) -> AssetState<T> {
3075 self.inner.get()
3076 }
3077
3078 pub fn get_ref(&self) -> AssetState<T> {
3079 self.inner.get()
3080 }
3081
3082 pub fn is_loading(&self) -> bool {
3083 matches!(self.get(), AssetState::Loading)
3084 }
3085
3086 pub fn is_ready(&self) -> bool {
3087 matches!(self.get(), AssetState::Ready(_))
3088 }
3089
3090 pub fn is_error(&self) -> bool {
3091 matches!(self.get(), AssetState::Error(_))
3092 }
3093
3094 pub fn ready_value(&self) -> Option<T> {
3095 match self.get() {
3096 AssetState::Ready(value) => Some(value),
3097 _ => None,
3098 }
3099 }
3100
3101 pub fn error_message(&self) -> Option<String> {
3102 match self.get() {
3103 AssetState::Error(message) => Some(message),
3104 _ => None,
3105 }
3106 }
3107
3108 pub fn subscribe<F: Fn(&AssetState<T>) + Send + Sync + 'static>(&self, callback: F) {
3109 self.inner.subscribe(callback)
3110 }
3111
3112 pub fn inner_state(&self) -> &State<AssetState<T>> {
3113 &self.inner
3114 }
3115}
3116
3117impl<T: Clone + Send + Sync + 'static> Clone for Suspense<T> {
3118 fn clone(&self) -> Self {
3119 Self {
3120 inner: self.inner.clone(),
3121 }
3122 }
3123}
3124
3125impl<T: Clone + Send + Sync + 'static> From<T> for Suspense<T> {
3126 fn from(value: T) -> Self {
3127 Self::ready(value)
3128 }
3129}
3130
3131impl<T: Clone + Send + Sync + 'static> From<Result<T, String>> for Suspense<T> {
3132 fn from(result: Result<T, String>) -> Self {
3133 match result {
3134 Ok(value) => Self::ready(value),
3135 Err(error) => Self::error(error),
3136 }
3137 }
3138}
3139
3140#[cfg(test)]
3141mod phase1_test;
3142
3143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3145pub enum BerserkerMode {
3146 Normal,
3147 Rage, Frenzy, GodMode, }
3151
3152pub trait Seer: Send + Sync {
3155 fn predict(&self, context: &str) -> String;
3157 fn whispers(&self) -> Vec<String>;
3159}