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
1254 pub input_time_ms: f32,
1256 pub state_flush_time_ms: f32,
1257 pub layout_time_ms: f32,
1258 pub draw_time_ms: f32,
1259 pub gpu_submit_time_ms: f32,
1260
1261 pub draw_calls: u32,
1262 pub vertices: u32,
1263
1264 pub vram_usage_mb: f32,
1266 pub vram_textures_mb: f32,
1267 pub vram_buffers_mb: f32,
1268 pub vram_pipelines_mb: f32,
1269}
1270
1271#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1273pub struct FrameBudget {
1274 pub target_ms: f32,
1276 pub allow_degradation: bool,
1279}
1280
1281impl Default for FrameBudget {
1282 fn default() -> Self {
1283 Self {
1284 target_ms: 16.0,
1285 allow_degradation: true,
1286 }
1287 }
1288}
1289
1290pub trait ElapsedTime {
1299 fn elapsed_time(&self) -> f32;
1301
1302 fn delta_time(&self) -> f32;
1304}
1305
1306pub trait Renderer: ElapsedTime + Send {
1314 fn request_redraw(&mut self) {}
1317
1318 fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
1320 fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
1321 fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
1323
1324 fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1326 fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
1327 fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1329 fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
1331 fn fill_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4]) {}
1333 fn stroke_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4], _stroke_width: f32) {}
1335
1336 fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
1338 fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
1340
1341 fn draw_texture(&mut self, _texture_id: u32, _rect: Rect) {}
1344 fn draw_image(&mut self, _image_name: &str, _rect: Rect) {}
1346 fn load_image(&mut self, _name: &str, _data: &[u8]) {}
1348
1349 fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
1352 fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
1354
1355 fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
1358
1359 fn draw_linear_gradient(
1362 &mut self,
1363 _rect: Rect,
1364 _start_color: [f32; 4],
1365 _end_color: [f32; 4],
1366 _angle: f32,
1367 ) {
1368 }
1369 fn draw_radial_gradient(
1371 &mut self,
1372 _rect: Rect,
1373 _inner_color: [f32; 4],
1374 _outer_color: [f32; 4],
1375 ) {
1376 }
1377 fn draw_drop_shadow(
1379 &mut self,
1380 _rect: Rect,
1381 _radius: f32,
1382 _color: [f32; 4],
1383 _blur: f32,
1384 _spread: f32,
1385 ) {
1386 }
1387 fn stroke_dashed_rounded_rect(
1389 &mut self,
1390 _rect: Rect,
1391 _radius: f32,
1392 _color: [f32; 4],
1393 _width: f32,
1394 _dash: f32,
1395 _gap: f32,
1396 ) {
1397 }
1398 fn draw_9slice(
1400 &mut self,
1401 _image_name: &str,
1402 _rect: Rect,
1403 _left: f32,
1404 _top: f32,
1405 _right: f32,
1406 _bottom: f32,
1407 ) {
1408 }
1409
1410 fn push_clip_rect(&mut self, _rect: Rect) {}
1414 fn pop_clip_rect(&mut self) {}
1416
1417 fn push_opacity(&mut self, _opacity: f32) {}
1421 fn pop_opacity(&mut self) {}
1423
1424 fn set_theme(&mut self, _theme: ColorTheme) {}
1426 fn set_rage(&mut self, _rage: f32) {}
1427 fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
1428
1429 fn bifrost(&mut self, _rect: Rect, _blur: f32, _saturation: f32, _opacity: f32) {}
1432 fn gungnir(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32, _intensity: f32) {}
1434 fn push_mjolnir_slice(&mut self, _angle: f32, _offset: f32) {}
1436 fn pop_mjolnir_slice(&mut self) {}
1437 fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1439 fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1440 fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
1442
1443 fn set_aria_role(&mut self, _role: &str) {}
1445 fn set_aria_label(&mut self, _label: &str) {}
1446
1447 fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
1449
1450 fn set_key(&mut self, _key: &str) {}
1452
1453 fn get_telemetry(&self) -> TelemetryData {
1456 TelemetryData::default()
1457 }
1458
1459 fn push_shadow(&mut self, _radius: f32, _color: [f32; 4], _offset: [f32; 2]) {}
1462 fn pop_shadow(&mut self) {}
1464
1465 fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
1468 fn pop_vnode(&mut self) {}
1470 fn register_handler(
1472 &mut self,
1473 _event_type: &str,
1474 _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
1475 ) {
1476 }
1477
1478 fn set_z_index(&mut self, _z: f32) {}
1482 fn get_z_index(&self) -> f32 {
1484 0.0
1485 }
1486
1487 fn load_svg(&mut self, _name: &str, _svg_data: &[u8]) {}
1490 fn draw_svg(&mut self, _name: &str, _rect: Rect) {}
1492
1493 fn push_transform(&mut self, _translation: [f32; 2], _scale: [f32; 2], _rotation: f32) {}
1498 fn pop_transform(&mut self) {}
1500 fn query_layout(&self, _node_id: scene_graph::NodeId) -> Option<Rect> {
1502 None
1503 }
1504 fn set_debug_layout(&mut self, _enabled: bool) {}
1506 fn get_debug_layout(&self) -> bool {
1508 false
1509 }
1510}
1511#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
1513pub enum RenderTier {
1514 Tier1GPU = 0,
1516 Tier2GPU = 1,
1518 Tier3Fallback = 2,
1520}
1521use bytemuck::{Pod, Zeroable};
1525#[repr(C)]
1527#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1528pub struct ColorTheme {
1529 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
1531 pub glass_base: [f32; 4],
1532 pub glass_edge: [f32; 4],
1533 pub rune_glow: [f32; 4],
1534 pub ember_core: [f32; 4],
1535 pub background_deep: [f32; 4],
1536 pub glass_blur_strength: f32,
1537 pub shatter_edge_width: f32,
1538 pub neon_bloom_radius: f32,
1539 pub rune_opacity: f32, pub _pad: [f32; 3], pub _pad2: f32,
1543}
1544impl ColorTheme {
1545 pub fn cyberpunk_viking() -> Self {
1546 Self {
1547 primary_neon: [0.0, 1.0, 0.95, 1.2],
1548 shatter_neon: [1.0, 0.0, 0.75, 1.5],
1549 glass_base: [0.04, 0.04, 0.06, 0.82],
1550 glass_edge: [0.0, 0.45, 0.55, 0.6],
1551 rune_glow: [0.75, 0.98, 1.0, 0.9],
1552 ember_core: [0.95, 0.12, 0.12, 1.0],
1553 background_deep: [0.01, 0.01, 0.03, 1.0],
1554 glass_blur_strength: 0.6,
1555 shatter_edge_width: 1.8,
1556 neon_bloom_radius: 0.022,
1557 rune_opacity: 0.55,
1558 _pad: [0.0; 3],
1559 _pad2: 0.0,
1560 }
1561 }
1562 pub fn vibrant_glass() -> Self {
1563 Self {
1564 primary_neon: [0.0, 1.0, 0.95, 1.2],
1565 shatter_neon: [1.0, 0.0, 0.75, 1.5],
1566 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],
1569 ember_core: [1.0, 0.4, 0.1, 1.0],
1570 background_deep: [0.05, 0.05, 0.1, 1.0],
1571 glass_blur_strength: 0.9,
1572 shatter_edge_width: 1.8,
1573 neon_bloom_radius: 0.022,
1574 rune_opacity: 0.55,
1575 _pad: [0.0; 3],
1576 _pad2: 0.0,
1577 }
1578 }
1579}
1580impl Default for ColorTheme {
1581 fn default() -> Self {
1582 Self::vibrant_glass()
1583 }
1584}
1585#[repr(C)]
1587#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1588pub struct SceneUniforms {
1589 pub view: glam::Mat4,
1590 pub proj: glam::Mat4,
1591 pub time: f32,
1592 pub delta_time: f32,
1593 pub resolution: [f32; 2],
1594 pub mouse: [f32; 2],
1595 pub mouse_velocity: [f32; 2],
1596 pub shatter_origin: [f32; 2],
1597 pub shatter_time: f32,
1598 pub shatter_force: f32,
1599 pub berzerker_rage: f32,
1600 pub scroll_offset: f32,
1601 pub scale_factor: f32,
1602 pub _pad: [f32; 1],
1604}
1605impl SceneUniforms {
1606 pub fn new(width: f32, height: f32) -> Self {
1607 Self {
1608 view: glam::Mat4::IDENTITY,
1609 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
1610 time: 0.0,
1611 delta_time: 0.016,
1612 resolution: [width, height],
1613 mouse: [0.5, 0.5],
1614 mouse_velocity: [0.0, 0.0],
1615 shatter_origin: [0.5, 0.5],
1616 shatter_time: -100.0,
1617 shatter_force: 0.0,
1618 berzerker_rage: 0.0,
1619 scroll_offset: 0.0,
1620 scale_factor: 1.0,
1621 _pad: [0.0; 1],
1622 }
1623 }
1624}
1625#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1627pub struct Mesh {
1628 pub vertices: Vec<[f32; 3]>,
1629 pub normals: Vec<[f32; 3]>,
1630 pub indices: Vec<u32>,
1631}
1632impl Mesh {
1633 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
1634 let mut cursor = std::io::Cursor::new(data);
1635 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
1636 Ok((Vec::new(), Default::default()))
1637 })?;
1638 let mut meshes = Vec::new();
1639 for m in models {
1640 let mesh = m.mesh;
1641 let vertices: Vec<[f32; 3]> = mesh
1642 .positions
1643 .chunks(3)
1644 .map(|c| [c[0], c[1], c[2]])
1645 .collect();
1646 let normals = if mesh.normals.is_empty() {
1647 vec![[0.0, 0.0, 1.0]; vertices.len()]
1648 } else {
1649 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
1650 };
1651 meshes.push(Mesh {
1652 vertices,
1653 normals,
1654 indices: mesh.indices,
1655 });
1656 }
1657 Ok(meshes)
1658 }
1659 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
1660 let mut cursor = std::io::Cursor::new(data);
1661 let stl = stl_io::read_stl(&mut cursor)?;
1662 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
1663 let mut indices = Vec::new();
1664 for face in stl.faces {
1665 indices.push(face.vertices[0] as u32);
1666 indices.push(face.vertices[1] as u32);
1667 indices.push(face.vertices[2] as u32);
1668 }
1669 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
1670 Ok(Mesh {
1671 vertices,
1672 normals,
1673 indices,
1674 })
1675 }
1676}
1677pub trait FrameRenderer<E = ()>: Renderer {
1680 fn begin_frame(&mut self) -> E;
1681 fn render_frame(&mut self) {
1682 }
1684 fn end_frame(&mut self, encoder: E);
1685}
1686use std::sync::Arc;
1687#[derive(Clone)]
1689pub struct State<T: Clone + Send + Sync + 'static> {
1690 swap: Arc<arc_swap::ArcSwap<T>>,
1691 metadata_swap: Arc<arc_swap::ArcSwap<Option<agents::MutationMetadata>>>,
1692 #[cfg(not(target_arch = "wasm32"))]
1693 tvar: Arc<stm::TVar<T>>,
1694 #[cfg(not(target_arch = "wasm32"))]
1695 metadata_tvar: Arc<stm::TVar<Option<agents::MutationMetadata>>>,
1696 subscribers: Arc<std::sync::Mutex<Vec<Box<dyn Fn(&T) + Send + Sync>>>>,
1697 version: Arc<std::sync::atomic::AtomicU64>,
1698 resolution: agents::ConflictResolution,
1699}
1700impl<T: Clone + Send + Sync + 'static> State<T> {
1701 pub fn new(value: T) -> Self {
1703 #[cfg(not(target_arch = "wasm32"))]
1704 let tvar = Arc::new(stm::TVar::new(value.clone()));
1705 #[cfg(not(target_arch = "wasm32"))]
1706 let metadata_tvar = Arc::new(stm::TVar::new(None));
1707 Self {
1708 swap: Arc::new(arc_swap::ArcSwap::from_pointee(value)),
1709 metadata_swap: Arc::new(arc_swap::ArcSwap::new(Arc::new(None))),
1710 #[cfg(not(target_arch = "wasm32"))]
1711 tvar,
1712 #[cfg(not(target_arch = "wasm32"))]
1713 metadata_tvar,
1714 subscribers: Arc::new(std::sync::Mutex::new(Vec::new())),
1715 version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
1716 resolution: agents::ConflictResolution::default(),
1717 }
1718 }
1719 pub fn with_resolution(mut self, resolution: agents::ConflictResolution) -> Self {
1721 self.resolution = resolution;
1722 self
1723 }
1724 pub fn get(&self) -> T {
1726 (**self.swap.load()).clone()
1727 }
1728 pub fn set(&self, value: T) {
1730 #[cfg(not(target_arch = "wasm32"))]
1731 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
1732 let new_meta = agents::get_current_mutation_metadata();
1733 let existing_meta = self.metadata_tvar.read(tx)?;
1734 let mut skip = false;
1735 if self.resolution == agents::ConflictResolution::PriorityWins
1736 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
1737 && new_m.priority < old_m.priority {
1738 skip = true;
1739 }
1740 if !skip {
1741 self.tvar.write(tx, value.clone())?;
1742 self.metadata_tvar.write(tx, new_meta)?;
1743 Ok((false, value.clone(), new_meta))
1744 } else {
1745 Ok((true, self.tvar.read(tx)?, existing_meta))
1746 }
1747 });
1748 #[cfg(target_arch = "wasm32")]
1749 let (was_skipped, final_val, final_meta) = (false, value, agents::get_current_mutation_metadata());
1750 if was_skipped {
1751 if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
1752 agents::notify_conflict(agents::ConflictEvent {
1753 agent_id: new_m.agent_id,
1754 priority: new_m.priority,
1755 existing_agent_id: old_m.agent_id,
1756 existing_priority: old_m.priority,
1757 timestamp_ms: new_m.timestamp_ms,
1758 });
1759 }
1760 return;
1761 }
1762 self.swap.store(Arc::new(final_val.clone()));
1763 self.metadata_swap.store(Arc::new(final_meta));
1764 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
1765 let subs = Arc::clone(&self.subscribers);
1766 if crate::is_batching() {
1767 crate::enqueue_batch_task(Box::new(move || {
1768 let s = subs.lock().unwrap();
1769 for cb in s.iter() {
1770 cb(&final_val);
1771 }
1772 }));
1773 } else {
1774 let s = subs.lock().unwrap();
1775 for cb in s.iter() {
1776 cb(&final_val);
1777 }
1778 }
1779 }
1780 pub fn mutate<F: Fn(&T) -> T>(&self, f: F) {
1781 #[cfg(not(target_arch = "wasm32"))]
1782 {
1783 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
1784 let new_meta = agents::get_current_mutation_metadata();
1785 let existing_meta = self.metadata_tvar.read(tx)?;
1786 let mut skip = false;
1787 if self.resolution == agents::ConflictResolution::PriorityWins
1788 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
1789 && new_m.priority < old_m.priority {
1790 skip = true;
1791 }
1792 if !skip {
1793 let current = self.tvar.read(tx)?;
1794 let next = f(¤t);
1795 self.tvar.write(tx, next.clone())?;
1796 self.metadata_tvar.write(tx, new_meta)?;
1797 Ok((false, next, new_meta))
1798 } else {
1799 Ok((true, self.tvar.read(tx)?, existing_meta))
1800 }
1801 });
1802 if was_skipped {
1803 if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
1804 agents::notify_conflict(agents::ConflictEvent {
1805 agent_id: new_m.agent_id,
1806 priority: new_m.priority,
1807 existing_agent_id: old_m.agent_id,
1808 existing_priority: old_m.priority,
1809 timestamp_ms: new_m.timestamp_ms,
1810 });
1811 }
1812 return;
1813 }
1814 self.swap.store(Arc::new(final_val.clone()));
1815 self.metadata_swap.store(Arc::new(final_meta));
1816 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
1817 let subs = Arc::clone(&self.subscribers);
1818 if crate::is_batching() {
1819 crate::enqueue_batch_task(Box::new(move || {
1820 let s = subs.lock().unwrap();
1821 for cb in s.iter() {
1822 cb(&final_val);
1823 }
1824 }));
1825 } else {
1826 let s = subs.lock().unwrap();
1827 for cb in s.iter() {
1828 cb(&final_val);
1829 }
1830 }
1831 }
1832 #[cfg(target_arch = "wasm32")]
1833 {
1834 self.set(f(&self.get()));
1835 }
1836 }
1837 pub fn version(&self) -> u64 {
1839 self.version.load(std::sync::atomic::Ordering::Acquire)
1840 }
1841 pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
1843 self.subscribers.lock().unwrap().push(Box::new(callback));
1844 }
1845}
1846use crate::runtime::NodeStateSnapshot;
1847use std::sync::atomic::{AtomicBool, Ordering};
1848use std::sync::OnceLock;
1849pub static SYSTEM_STATE: OnceLock<Arc<arc_swap::ArcSwap<KnowledgeState>>> = OnceLock::new();
1851#[cfg(not(target_arch = "wasm32"))]
1852static KNOWLEDGE_TVAR: OnceLock<stm::TVar<KnowledgeState>> = OnceLock::new();
1853static IS_BATCHING: AtomicBool = AtomicBool::new(false);
1854pub static IS_RENDERING: AtomicBool = AtomicBool::new(false);
1855pub static LAYOUT_DIRTY: AtomicBool = AtomicBool::new(false);
1856static BATCH_QUEUE: OnceLock<std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync>>>> = OnceLock::new();
1857pub fn is_batching() -> bool {
1859 IS_BATCHING.load(Ordering::Acquire)
1860}
1861pub fn is_rendering() -> bool {
1863 IS_RENDERING.load(Ordering::Acquire)
1864}
1865pub fn begin_render_phase() {
1867 IS_RENDERING.store(true, Ordering::Release);
1868}
1869pub fn end_render_phase() {
1871 IS_RENDERING.store(false, Ordering::Release);
1872}
1873pub fn enqueue_batch_task(task: Box<dyn FnOnce() + Send + Sync>) {
1875 let mut queue = BATCH_QUEUE
1876 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
1877 .lock()
1878 .unwrap();
1879 queue.push(task);
1880}
1881pub fn batch<F: FnOnce()>(f: F) {
1885 if IS_BATCHING.swap(true, Ordering::AcqRel) {
1886 f();
1888 return;
1889 }
1890 f();
1891 IS_BATCHING.store(false, Ordering::Release);
1892 let mut queue = BATCH_QUEUE
1893 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
1894 .lock()
1895 .unwrap();
1896 let tasks: Vec<_> = queue.drain(..).collect();
1897 drop(queue);
1898 for task in tasks {
1899 task();
1900 }
1901}
1902pub fn get_system_state() -> Arc<arc_swap::ArcSwap<KnowledgeState>> {
1904 SYSTEM_STATE
1905 .get_or_init(|| Arc::new(arc_swap::ArcSwap::from_pointee(KnowledgeState::default())))
1906 .clone()
1907}
1908pub fn load_system_state() -> arc_swap::Guard<Arc<KnowledgeState>> {
1909 get_system_state().load()
1910}
1911pub fn update_system_state<F>(f: F)
1912where
1913 F: Fn(&KnowledgeState) -> KnowledgeState,
1914{
1915 if is_rendering() {
1916 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1917 }
1918 LAYOUT_DIRTY.store(true, Ordering::SeqCst);
1919 let swap = get_system_state();
1920 let current = swap.load();
1921 let new_state = Arc::new(f(¤t));
1922 swap.store(Arc::clone(&new_state));
1923 #[cfg(not(target_arch = "wasm32"))]
1924 {
1925 let tvar = KNOWLEDGE_TVAR
1926 .get_or_init(|| stm::TVar::new((*new_state).clone()));
1927 stm::atomically(|tx| tvar.write(tx, (*new_state).clone()));
1928 }
1929}
1930pub fn transact_system_state<F>(f: F)
1931where
1932 F: Fn(&KnowledgeState) -> KnowledgeState,
1933{
1934 #[cfg(not(target_arch = "wasm32"))]
1935 {
1936 if is_rendering() {
1937 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1938 }
1939 let tvar = KNOWLEDGE_TVAR
1940 .get_or_init(|| {
1941 stm::TVar::new((**get_system_state().load()).clone())
1942 })
1943 .clone();
1944 let new_state = stm::atomically(move |tx| {
1945 let current = tvar.read(tx)?;
1946 let next = f(¤t);
1947 tvar.write(tx, next.clone())?;
1948 Ok(next)
1949 });
1950 get_system_state().store(Arc::new(new_state));
1951 }
1952 #[cfg(target_arch = "wasm32")]
1953 {
1954 if is_rendering() {
1955 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1956 }
1957 update_system_state(f);
1958 }
1959}
1960impl KnowledgeState {
1961 pub fn new() -> Self {
1963 Self::default()
1964 }
1965 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
1967 self.component_states
1968 .insert(id, Arc::new(std::sync::RwLock::new(state)));
1969 }
1970pub fn get_component_state<T: 'static + Send + Sync>(
1972 &self,
1973 id: u64,
1974 ) -> Option<Arc<std::sync::RwLock<T>>> {
1975 let lock = self.component_states.get(&id)?;
1976 let _inner: &std::sync::RwLock<dyn std::any::Any + Send + Sync> = lock;
1978 None }
1982 pub fn remember(&mut self, fragment: KnowledgeFragment) {
1984 self.fragments.insert(fragment.id.clone(), fragment);
1985 }
1986 pub fn process_query(&mut self, query: &str) {
1988 let query_lower = query.to_lowercase();
1989 let mut results: Vec<(f32, String)> = self
1990 .fragments
1991 .iter()
1992 .map(|(id, frag)| {
1993 let mut score = 0.0;
1994 if frag.summary.to_lowercase().contains(&query_lower) {
1995 score += 1.0;
1996 }
1997 if frag.source.to_lowercase().contains(&query_lower) {
1998 score += 0.5;
1999 }
2000 (score, id.clone())
2001 })
2002 .filter(|(score, _)| *score > 0.0)
2003 .collect();
2004 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
2006 self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
2007 }
2008 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
2010 let mut snapshots = Vec::new();
2011 for frag in self.fragments.values() {
2013 if let Ok(val) = serde_json::to_value(frag) {
2014 snapshots.push(NodeStateSnapshot { id: 0, state: val });
2015 }
2016 }
2017 snapshots
2018 }
2019}
2020#[derive(Clone)]
2022pub struct Binding<T: Clone + Send + Sync + 'static> {
2023 swap: Arc<arc_swap::ArcSwap<T>>,
2024 #[cfg(not(target_arch = "wasm32"))]
2025 tvar: Arc<stm::TVar<T>>,
2026 version: Arc<std::sync::atomic::AtomicU64>,
2027}
2028impl<T: Clone + Send + Sync + 'static> Binding<T> {
2029 pub fn from_state(state: &State<T>) -> Self {
2031 Self {
2032 swap: Arc::clone(&state.swap),
2033 #[cfg(not(target_arch = "wasm32"))]
2034 tvar: Arc::clone(&state.tvar),
2035 version: Arc::clone(&state.version),
2036 }
2037 }
2038 pub fn get(&self) -> T {
2040 (**self.swap.load()).clone()
2041 }
2042 pub fn set(&self, value: T) {
2044 self.swap.store(Arc::new(value.clone()));
2045 #[cfg(not(target_arch = "wasm32"))]
2046 {
2047 let tvar = Arc::clone(&self.tvar);
2048 let v = value.clone();
2049 stm::atomically(move |tx| tvar.write(tx, v.clone()));
2050 }
2051 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2052 }
2053 pub fn version(&self) -> u64 {
2055 self.version.load(std::sync::atomic::Ordering::Acquire)
2056 }
2057}
2058#[cfg(not(target_arch = "wasm32"))]
2059pub fn transact_pair<A, B, F>(state_a: &State<A>, state_b: &State<B>, f: F)
2060where
2061 A: Clone + Send + Sync + 'static,
2062 B: Clone + Send + Sync + 'static,
2063 F: Fn(&A, &B) -> (A, B),
2064{
2065 let tvar_a = Arc::clone(&state_a.tvar);
2066 let tvar_b = Arc::clone(&state_b.tvar);
2067 let (new_a, new_b) = stm::atomically(move |tx| {
2068 let a = tvar_a.read(tx)?;
2069 let b = tvar_b.read(tx)?;
2070 let (na, nb) = f(&a, &b);
2071 tvar_a.write(tx, na.clone())?;
2072 tvar_b.write(tx, nb.clone())?;
2073 Ok((na, nb))
2074 });
2075 state_a.swap.store(Arc::new(new_a.clone()));
2076 state_b.swap.store(Arc::new(new_b.clone()));
2077 state_a.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2078 state_b.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2079 let subs_a = Arc::clone(&state_a.subscribers);
2080 let subs_b = Arc::clone(&state_b.subscribers);
2081 if crate::is_batching() {
2082 crate::enqueue_batch_task(Box::new(move || {
2083 {
2084 let s = subs_a.lock().unwrap();
2085 for cb in s.iter() { cb(&new_a); }
2086 }
2087 {
2088 let s = subs_b.lock().unwrap();
2089 for cb in s.iter() { cb(&new_b); }
2090 }
2091 }));
2092 } else {
2093 {
2094 let s = subs_a.lock().unwrap();
2095 for cb in s.iter() { cb(&new_a); }
2096 }
2097 {
2098 let s = subs_b.lock().unwrap();
2099 for cb in s.iter() { cb(&new_b); }
2100 }
2101 }
2102}
2103use std::any::TypeId;
2104use std::sync::Mutex;
2105pub(crate) static ENVIRONMENT: OnceLock<
2107 Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
2108> = OnceLock::new();
2109pub trait EnvKey: 'static + Send + Sync {
2113 type Value: Clone + Send + Sync + 'static;
2115 fn default_value() -> Self::Value;
2117}
2118pub struct YggdrasilKey;
2120impl EnvKey for YggdrasilKey {
2121 type Value = YggdrasilTokens;
2122 fn default_value() -> Self::Value {
2123 default_tokens()
2124 }
2125}
2126#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2129pub enum Appearance {
2130 Light,
2131 Dark,
2132}
2133#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2135pub enum Orientation {
2136 Horizontal,
2137 Vertical,
2138}
2139#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2141pub enum Alignment {
2142 #[default]
2143 Center,
2144 Leading,
2145 Trailing,
2146 Top,
2147 Bottom,
2148}
2149#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2151pub enum Distribution {
2152 #[default]
2153 Fill,
2154 Center,
2155 Leading,
2156 Trailing,
2157 SpaceBetween,
2158 SpaceAround,
2159 SpaceEvenly,
2160}
2161#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2163pub struct Color {
2164 pub r: f32,
2165 pub g: f32,
2166 pub b: f32,
2167 pub a: f32,
2168}
2169impl Color {
2170 pub const BLACK: Color = Color {
2171 r: 0.0,
2172 g: 0.0,
2173 b: 0.0,
2174 a: 1.0,
2175 };
2176 pub const WHITE: Color = Color {
2177 r: 1.0,
2178 g: 1.0,
2179 b: 1.0,
2180 a: 1.0,
2181 };
2182 pub const TRANSPARENT: Color = Color {
2183 r: 0.0,
2184 g: 0.0,
2185 b: 0.0,
2186 a: 0.0,
2187 };
2188 pub const RED: Color = Color {
2189 r: 1.0,
2190 g: 0.0,
2191 b: 0.0,
2192 a: 1.0,
2193 };
2194 pub const GREEN: Color = Color {
2195 r: 0.0,
2196 g: 1.0,
2197 b: 0.0,
2198 a: 1.0,
2199 };
2200 pub const BLUE: Color = Color {
2201 r: 0.0,
2202 g: 0.0,
2203 b: 1.0,
2204 a: 1.0,
2205 };
2206 pub fn relative_luminance(&self) -> f32 {
2208 fn res(c: f32) -> f32 {
2209 if c <= 0.03928 {
2210 c / 12.92
2211 } else {
2212 ((c + 0.055) / 1.055).powf(2.4)
2213 }
2214 }
2215 0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
2216 }
2217 pub fn contrast_ratio(&self, other: &Color) -> f32 {
2219 let l1 = self.relative_luminance();
2220 let l2 = other.relative_luminance();
2221 if l1 > l2 {
2222 (l1 + 0.05) / (l2 + 0.05)
2223 } else {
2224 (l2 + 0.05) / (l1 + 0.05)
2225 }
2226 }
2227 pub const CYAN: Color = Color {
2228 r: 0.0,
2229 g: 1.0,
2230 b: 1.0,
2231 a: 1.0,
2232 };
2233 pub const YELLOW: Color = Color {
2234 r: 1.0,
2235 g: 1.0,
2236 b: 0.0,
2237 a: 1.0,
2238 };
2239 pub const MAGENTA: Color = Color {
2240 r: 1.0,
2241 g: 0.0,
2242 b: 1.0,
2243 a: 1.0,
2244 };
2245 pub const GRAY: Color = Color {
2246 r: 0.5,
2247 g: 0.5,
2248 b: 0.5,
2249 a: 1.0,
2250 };
2251 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
2253 Self { r, g, b, a }
2254 }
2255 pub fn as_array(&self) -> [f32; 4] {
2257 [self.r, self.g, self.b, self.a]
2258 }
2259}
2260impl View for Color {
2261 type Body = Never;
2262 fn body(self) -> Self::Body {
2263 unreachable!()
2264 }
2265 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
2266 renderer.fill_rect(rect, self.as_array());
2267 }
2268}
2269pub struct AppearanceKey;
2271impl EnvKey for AppearanceKey {
2272 type Value = Appearance;
2273 fn default_value() -> Self::Value {
2274 Appearance::Dark }
2276}
2277pub struct StyleResolver;
2279impl StyleResolver {
2280 pub fn color(key: &str) -> String {
2282 let tokens = Environment::<YggdrasilKey>::new().get();
2283 let appearance = Environment::<AppearanceKey>::new().get();
2284 let is_dark = appearance == Appearance::Dark;
2285 tokens
2286 .get_color(key, is_dark)
2287 .unwrap_or_else(|| "#FF00FF".to_string()) }
2289 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
2291 let tokens = Environment::<YggdrasilKey>::new().get();
2292 let appearance = Environment::<AppearanceKey>::new().get();
2293 let is_dark = appearance == Appearance::Dark;
2294 tokens.get(category, key, is_dark)
2295 }
2296}
2297pub fn default_tokens() -> YggdrasilTokens {
2299 let mut tokens = YggdrasilTokens::new();
2300 tokens.color.insert(
2302 "background".to_string(),
2303 TokenValue::Single {
2304 value: "#000000".to_string(), },
2306 );
2307 tokens.color.insert(
2308 "primary".to_string(),
2309 TokenValue::Single {
2310 value: "#00FFFF".to_string(), },
2312 );
2313 tokens.color.insert(
2314 "secondary".to_string(),
2315 TokenValue::Single {
2316 value: "#FF00FF".to_string(), },
2318 );
2319 tokens.color.insert(
2320 "surface".to_string(),
2321 TokenValue::Adaptive {
2322 light: "#FFFFFF".to_string(),
2323 dark: "#121212".to_string(),
2324 },
2325 );
2326 tokens.color.insert(
2327 "text".to_string(),
2328 TokenValue::Adaptive {
2329 light: "#000000".to_string(),
2330 dark: "#FFFFFF".to_string(),
2331 },
2332 );
2333 tokens.bifrost.insert(
2335 "blur".to_string(),
2336 TokenValue::Single {
2337 value: "25.0".to_string(),
2338 },
2339 );
2340 tokens.bifrost.insert(
2341 "saturation".to_string(),
2342 TokenValue::Single {
2343 value: "1.2".to_string(),
2344 },
2345 );
2346 tokens.bifrost.insert(
2347 "opacity".to_string(),
2348 TokenValue::Single {
2349 value: "0.65".to_string(),
2350 },
2351 );
2352 tokens.gungnir.insert(
2354 "intensity".to_string(),
2355 TokenValue::Single {
2356 value: "1.0".to_string(),
2357 },
2358 );
2359 tokens.gungnir.insert(
2360 "radius".to_string(),
2361 TokenValue::Single {
2362 value: "15.0".to_string(),
2363 },
2364 );
2365 tokens.mjolnir.insert(
2367 "clip_angle".to_string(),
2368 TokenValue::Single {
2369 value: "12.0".to_string(),
2370 },
2371 );
2372 tokens.mjolnir.insert(
2373 "border_width".to_string(),
2374 TokenValue::Single {
2375 value: "2.0".to_string(),
2376 },
2377 );
2378 tokens.anim.insert(
2380 "stiffness".to_string(),
2381 TokenValue::Single {
2382 value: "170.0".to_string(),
2383 },
2384 );
2385 tokens.anim.insert(
2386 "damping".to_string(),
2387 TokenValue::Single {
2388 value: "26.0".to_string(),
2389 },
2390 );
2391 tokens.anim.insert(
2392 "mass".to_string(),
2393 TokenValue::Single {
2394 value: "1.0".to_string(),
2395 },
2396 );
2397 tokens.accessibility.insert(
2399 "reduce_motion".to_string(),
2400 TokenValue::Single {
2401 value: "false".to_string(),
2402 },
2403 );
2404 tokens
2405}
2406pub struct Environment<K: EnvKey> {
2408 _marker: std::marker::PhantomData<K>,
2409}
2410impl<K: EnvKey> Default for Environment<K> {
2411 fn default() -> Self {
2412 Self::new()
2413 }
2414}
2415impl<K: EnvKey> Environment<K> {
2416 pub fn new() -> Self {
2418 Self {
2419 _marker: std::marker::PhantomData,
2420 }
2421 }
2422 pub fn get(&self) -> K::Value {
2424 if let Some(env_store) = ENVIRONMENT.get() {
2425 let env_lock = env_store.lock().unwrap();
2426 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
2427 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
2428 return typed_val.clone();
2429 } else {
2430 log::warn!("Environment: Downcast failed for key type {:?}", std::any::type_name::<K>());
2431 }
2432 } else {
2433 log::debug!("Environment: Key not found: {:?}. Returning default.", std::any::type_name::<K>());
2434 }
2435 } else {
2436 log::debug!("Environment: Store not initialized. Key: {:?}. Returning default.", std::any::type_name::<K>());
2437 }
2438 K::default_value()
2439 }
2440}
2441pub mod env {
2443 pub fn insert<K: super::EnvKey>(value: K::Value) {
2445 let store = super::ENVIRONMENT.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
2446 let mut env_map = store.lock().unwrap();
2447 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
2448 }
2449 pub fn remove<K: super::EnvKey>() {
2451 if let Some(store) = super::ENVIRONMENT.get() {
2452 let mut env_map = store.lock().unwrap();
2453 env_map.remove(&std::any::TypeId::of::<K>());
2454 }
2455 }
2456}
2457#[derive(Debug, Clone, Copy, PartialEq)]
2460pub struct Size {
2461 pub width: f32,
2462 pub height: f32,
2463}
2464
2465impl Size {
2466 pub const ZERO: Self = Self { width: 0.0, height: 0.0 };
2467
2468 pub fn new(width: f32, height: f32) -> Self {
2469 Self { width, height }
2470 }
2471}
2472
2473#[derive(Debug, Clone, Copy, PartialEq)]
2475pub struct EdgeInsets {
2476 pub top: f32,
2477 pub leading: f32,
2478 pub bottom: f32,
2479 pub trailing: f32,
2480}
2481
2482impl EdgeInsets {
2483 pub fn all(value: f32) -> Self {
2485 Self {
2486 top: value,
2487 leading: value,
2488 bottom: value,
2489 trailing: value,
2490 }
2491 }
2492
2493 pub fn vertical(value: f32) -> Self {
2495 Self {
2496 top: value,
2497 leading: 0.0,
2498 bottom: value,
2499 trailing: 0.0,
2500 }
2501 }
2502
2503 pub fn horizontal(value: f32) -> Self {
2505 Self {
2506 top: 0.0,
2507 leading: value,
2508 bottom: 0.0,
2509 trailing: value,
2510 }
2511 }
2512}
2513
2514#[derive(Debug, Clone, Copy, PartialEq)]
2516pub struct FrameModifier {
2517 pub width: Option<f32>,
2518 pub height: Option<f32>,
2519}
2520
2521impl Default for FrameModifier {
2522 fn default() -> Self {
2523 Self::new()
2524 }
2525}
2526
2527impl FrameModifier {
2528 pub fn new() -> Self {
2529 Self {
2530 width: None,
2531 height: None,
2532 }
2533 }
2534
2535 pub fn width(mut self, width: f32) -> Self {
2536 self.width = Some(width);
2537 self
2538 }
2539
2540 pub fn height(mut self, height: f32) -> Self {
2541 self.height = Some(height);
2542 self
2543 }
2544
2545 pub fn size(mut self, width: f32, height: f32) -> Self {
2546 self.width = Some(width);
2547 self.height = Some(height);
2548 self
2549 }
2550}
2551
2552impl ViewModifier for FrameModifier {
2553 fn modify<V: View>(self, content: V) -> impl View {
2554 ModifiedView::new(content, self)
2555 }
2556}
2557
2558#[derive(Debug, Clone, Copy, PartialEq)]
2560pub struct FlexModifier {
2561 pub weight: f32,
2562}
2563
2564impl ViewModifier for FlexModifier {
2565 fn modify<V: View>(self, content: V) -> impl View {
2566 ModifiedView::new(content, self)
2567 }
2568
2569 fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
2570 self.weight
2571 }
2572}
2573
2574#[derive(Debug, Clone, Copy, PartialEq)]
2576pub struct OffsetModifier {
2577 pub x: f32,
2578 pub y: f32,
2579}
2580
2581impl OffsetModifier {
2582 pub fn new(x: f32, y: f32) -> Self {
2583 Self { x, y }
2584 }
2585}
2586
2587impl ViewModifier for OffsetModifier {
2588 fn modify<V: View>(self, content: V) -> impl View {
2589 ModifiedView::new(content, self)
2590 }
2591}
2592
2593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2595pub struct ZIndexModifier {
2596 pub z_index: i32,
2597}
2598
2599impl ZIndexModifier {
2600 pub fn new(z_index: i32) -> Self {
2601 Self { z_index }
2602 }
2603}
2604
2605impl ViewModifier for ZIndexModifier {
2606 fn modify<V: View>(self, content: V) -> impl View {
2607 ModifiedView::new(content, self)
2608 }
2609}
2610
2611#[derive(Debug, Clone, Copy, PartialEq, Default)]
2613pub struct LayoutConstraints {
2614 pub min_width: Option<f32>,
2615 pub max_width: Option<f32>,
2616 pub min_height: Option<f32>,
2617 pub max_height: Option<f32>,
2618}
2619
2620#[derive(Debug, Clone, Copy, PartialEq)]
2622pub struct LayoutModifier {
2623 pub constraints: LayoutConstraints,
2624}
2625
2626impl LayoutModifier {
2627 pub fn new(constraints: LayoutConstraints) -> Self {
2628 Self { constraints }
2629 }
2630}
2631
2632impl ViewModifier for LayoutModifier {
2633 fn modify<V: View>(self, content: V) -> impl View {
2634 ModifiedView::new(content, self)
2635 }
2636}
2637
2638#[derive(Debug, Clone, Copy, PartialEq)]
2640pub struct SafeAreaModifier {
2641 pub ignores: bool,
2642}
2643
2644impl ViewModifier for SafeAreaModifier {
2645 fn modify<V: View>(self, content: V) -> impl View {
2646 ModifiedView::new(content, self)
2647 }
2648}
2649
2650#[derive(Debug, Clone, Copy, PartialEq)]
2652pub struct ElevationModifier {
2653 pub level: f32,
2654}
2655
2656impl ViewModifier for ElevationModifier {
2657 fn modify<V: View>(self, content: V) -> impl View {
2658 ModifiedView::new(content, self)
2659 }
2660
2661 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
2662 if self.level > 0.0 {
2663 let radius = self.level * 2.0;
2664 let offset_y = self.level * 0.5;
2665 let shadow_color = [0.0, 0.0, 0.0, 0.3];
2666 renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
2667 view.render(renderer, rect);
2668 renderer.pop_shadow();
2669 } else {
2670 view.render(renderer, rect);
2671 }
2672 }
2673}
2674
2675pub mod layout {
2677 use super::*;
2678
2679 pub struct LayoutCache {
2681 pub safe_area: SafeArea,
2682 size_cache: HashMap<(u64, u32, u32), Size>, }
2684
2685 impl Default for LayoutCache {
2686 fn default() -> Self {
2687 Self::new()
2688 }
2689 }
2690
2691 impl LayoutCache {
2692 pub fn new() -> Self {
2693 Self {
2694 safe_area: SafeArea::default(),
2695 size_cache: HashMap::new(),
2696 }
2697 }
2698
2699 pub fn clear(&mut self) {
2700 self.safe_area = SafeArea::default();
2701 self.size_cache.clear();
2702 }
2703
2704 pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
2705 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2706 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2707 self.size_cache.get(&(view_hash, pw, ph)).copied()
2708 }
2709
2710 pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: 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.insert((view_hash, pw, ph), size);
2714 }
2715
2716 pub fn invalidate_view(&mut self, view_hash: u64) {
2718 self.size_cache.retain(|&(hash, _, _), _| hash != view_hash);
2719 }
2720 }
2721
2722 #[derive(Debug, Clone, Copy, PartialEq)]
2724 pub struct SizeProposal {
2725 pub width: Option<f32>,
2726 pub height: Option<f32>,
2727 }
2728
2729 impl SizeProposal {
2730 pub fn unspecified() -> Self {
2731 Self {
2732 width: None,
2733 height: None,
2734 }
2735 }
2736
2737 pub fn width(width: f32) -> Self {
2738 Self {
2739 width: Some(width),
2740 height: None,
2741 }
2742 }
2743
2744 pub fn height(height: f32) -> Self {
2745 Self {
2746 width: None,
2747 height: Some(height),
2748 }
2749 }
2750
2751 pub fn tight(width: f32, height: f32) -> Self {
2752 Self {
2753 width: Some(width),
2754 height: Some(height),
2755 }
2756 }
2757
2758 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
2759 Self { width, height }
2760 }
2761 }
2762
2763 pub trait LayoutView: Send {
2765 fn size_that_fits(
2767 &self,
2768 proposal: SizeProposal,
2769 subviews: &[&dyn LayoutView],
2770 cache: &mut LayoutCache,
2771 ) -> Size;
2772
2773 fn place_subviews(
2775 &self,
2776 bounds: Rect,
2777 subviews: &mut [&mut dyn LayoutView],
2778 cache: &mut LayoutCache,
2779 );
2780
2781 fn flex_weight(&self) -> f32 {
2783 0.0
2784 }
2785 }
2786 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2788 pub struct EdgeInsets {
2789 pub top: f32,
2790 pub leading: f32,
2791 pub bottom: f32,
2792 pub trailing: f32,
2793 }
2794
2795 impl EdgeInsets {
2796 pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
2797 Self { top, leading, bottom, trailing }
2798 }
2799
2800 pub fn all(value: f32) -> Self {
2801 Self {
2802 top: value,
2803 leading: value,
2804 bottom: value,
2805 trailing: value,
2806 }
2807 }
2808 }
2809
2810 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2812 pub struct SafeArea {
2813 pub insets: EdgeInsets,
2814 }
2815
2816 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2818 pub struct Rect {
2819 pub x: f32,
2820 pub y: f32,
2821 pub width: f32,
2822 pub height: f32,
2823 }
2824
2825 impl Rect {
2826 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
2827 Self {
2828 x,
2829 y,
2830 width,
2831 height,
2832 }
2833 }
2834
2835 pub fn zero() -> Self {
2836 Self {
2837 x: 0.0,
2838 y: 0.0,
2839 width: 0.0,
2840 height: 0.0,
2841 }
2842 }
2843
2844 pub fn contains(&self, x: f32, y: f32) -> bool {
2845 x >= self.x && x <= self.x + self.width && y >= self.y && y <= self.y + self.height
2846 }
2847
2848 pub fn size(&self) -> Size {
2849 Size {
2850 width: self.width,
2851 height: self.height,
2852 }
2853 }
2854
2855 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
2857 if n == 0 {
2858 return vec![];
2859 }
2860 let item_width = self.width / n as f32;
2861 (0..n)
2862 .map(|i| Rect {
2863 x: self.x + i as f32 * item_width,
2864 y: self.y,
2865 width: item_width,
2866 height: self.height,
2867 })
2868 .collect()
2869 }
2870
2871 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
2873 if n == 0 {
2874 return vec![];
2875 }
2876 let item_height = self.height / n as f32;
2877 (0..n)
2878 .map(|i| Rect {
2879 x: self.x,
2880 y: self.y + i as f32 * item_height,
2881 width: self.width,
2882 height: item_height,
2883 })
2884 .collect()
2885 }
2886 }
2887}
2888
2889pub use layout::{LayoutCache, LayoutView, Rect, SizeProposal};
2891pub mod runtime;
2894pub mod scene_graph;
2895pub mod agents;
2896pub mod material;
2897
2898
2899pub use scene_graph::{NodeId, bifrost_registry};
2900
2901pub trait AssetManager: Send + Sync {
2905 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
2907
2908 fn preload_image(&self, url: &str);
2910}
2911
2912#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2914pub enum Event {
2915 PointerDown { x: f32, y: f32 },
2916 PointerUp { x: f32, y: f32 },
2917 PointerMove { x: f32, y: f32 },
2918 PointerClick { x: f32, y: f32 },
2919 PointerEnter,
2920 PointerLeave,
2921 KeyDown { key: String },
2922 KeyUp { key: String },
2923 Ime(String),
2925}
2926
2927impl Event {
2928 pub fn name(&self) -> &'static str {
2930 match self {
2931 Self::PointerDown { .. } => "pointerdown",
2932 Self::PointerUp { .. } => "pointerup",
2933 Self::PointerMove { .. } => "pointermove",
2934 Self::PointerClick { .. } => "pointerclick",
2935 Self::PointerEnter => "pointerenter",
2936 Self::PointerLeave => "pointerleave",
2937 Self::KeyDown { .. } => "keydown",
2938 Self::KeyUp { .. } => "keyup",
2939 Self::Ime(_) => "ime",
2940 }
2941 }
2942}
2943
2944#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2946pub enum EventResponse {
2947 Handled,
2948 Ignored,
2949}
2950
2951pub struct DefaultAssetManager {
2953 cache: Arc<arc_swap::ArcSwap<HashMap<String, AssetState<Arc<Vec<u8>>>>>>,
2954}
2955
2956impl Default for DefaultAssetManager {
2957 fn default() -> Self {
2958 Self::new()
2959 }
2960}
2961
2962impl DefaultAssetManager {
2963 pub fn new() -> Self {
2964 Self {
2965 cache: Arc::new(arc_swap::ArcSwap::from_pointee(HashMap::new())),
2966 }
2967 }
2968}
2969
2970impl AssetManager for DefaultAssetManager {
2971 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
2972 if let Some(state) = self.cache.load().get(url) {
2973 return state.clone();
2974 }
2975
2976 self.cache.rcu(|map| {
2977 let mut m = (**map).clone();
2978 m.entry(url.to_string()).or_insert(AssetState::Loading);
2979 m
2980 });
2981 AssetState::Loading
2982 }
2983
2984 fn preload_image(&self, _url: &str) {}
2985}
2986
2987use std::future::Future;
2988
2989pub struct Suspense<T: Clone + Send + Sync + 'static> {
2992 inner: State<AssetState<T>>,
2993}
2994
2995impl<T: Clone + Send + Sync + 'static> Default for Suspense<T> {
2996 fn default() -> Self {
2997 Self::new()
2998 }
2999}
3000
3001impl<T: Clone + Send + Sync + 'static> Suspense<T> {
3002 pub fn new() -> Self {
3003 Self {
3004 inner: State::new(AssetState::Loading),
3005 }
3006 }
3007
3008 pub fn new_async<F>(_future: F) -> Self
3009 where
3010 F: Future<Output = Result<T, String>> + Send + 'static,
3011 {
3012 let suspense = Self::new();
3013 let _suspense_clone = suspense.clone();
3014
3015 #[cfg(not(target_arch = "wasm32"))]
3016 {
3017 std::thread::spawn(move || {
3018 let _rt = std::sync::Arc::new(std::sync::Mutex::new(_future));
3022 });
3024 }
3025 #[cfg(target_arch = "wasm32")]
3026 {
3027 }
3030
3031 suspense
3032 }
3033
3034 pub fn ready(value: T) -> Self {
3035 Self {
3036 inner: State::new(AssetState::Ready(value)),
3037 }
3038 }
3039
3040 pub fn error(message: impl Into<String>) -> Self {
3041 Self {
3042 inner: State::new(AssetState::Error(message.into())),
3043 }
3044 }
3045
3046 pub fn get(&self) -> AssetState<T> {
3047 self.inner.get()
3048 }
3049
3050 pub fn get_ref(&self) -> AssetState<T> {
3051 self.inner.get()
3052 }
3053
3054 pub fn is_loading(&self) -> bool {
3055 matches!(self.get(), AssetState::Loading)
3056 }
3057
3058 pub fn is_ready(&self) -> bool {
3059 matches!(self.get(), AssetState::Ready(_))
3060 }
3061
3062 pub fn is_error(&self) -> bool {
3063 matches!(self.get(), AssetState::Error(_))
3064 }
3065
3066 pub fn ready_value(&self) -> Option<T> {
3067 match self.get() {
3068 AssetState::Ready(value) => Some(value),
3069 _ => None,
3070 }
3071 }
3072
3073 pub fn error_message(&self) -> Option<String> {
3074 match self.get() {
3075 AssetState::Error(message) => Some(message),
3076 _ => None,
3077 }
3078 }
3079
3080 pub fn subscribe<F: Fn(&AssetState<T>) + Send + Sync + 'static>(&self, callback: F) {
3081 self.inner.subscribe(callback)
3082 }
3083
3084 pub fn inner_state(&self) -> &State<AssetState<T>> {
3085 &self.inner
3086 }
3087}
3088
3089impl<T: Clone + Send + Sync + 'static> Clone for Suspense<T> {
3090 fn clone(&self) -> Self {
3091 Self {
3092 inner: self.inner.clone(),
3093 }
3094 }
3095}
3096
3097impl<T: Clone + Send + Sync + 'static> From<T> for Suspense<T> {
3098 fn from(value: T) -> Self {
3099 Self::ready(value)
3100 }
3101}
3102
3103impl<T: Clone + Send + Sync + 'static> From<Result<T, String>> for Suspense<T> {
3104 fn from(result: Result<T, String>) -> Self {
3105 match result {
3106 Ok(value) => Self::ready(value),
3107 Err(error) => Self::error(error),
3108 }
3109 }
3110}
3111
3112#[cfg(test)]
3113mod phase1_test;