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}
450
451impl<V: View + 'static> ErasedView for V {
452 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
453 self.render(renderer, rect);
454 }
455
456 fn name(&self) -> &'static str {
457 std::any::type_name::<V>()
458 }
459
460 fn flex_weight_erased(&self) -> f32 {
461 self.flex_weight()
462 }
463}
464
465pub struct AnyView {
467 inner: Box<dyn ErasedView>,
468}
469
470impl AnyView {
471 pub fn new<V: View + 'static>(view: V) -> Self {
472 Self {
473 inner: Box::new(view),
474 }
475 }
476}
477
478impl View for AnyView {
479 type Body = Never;
480 fn body(self) -> Self::Body {
481 unreachable!()
482 }
483
484 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
485 renderer.push_vnode(rect, self.inner.name());
486 self.inner.render_erased(renderer, rect);
487 renderer.pop_vnode();
488 }
489
490 fn flex_weight(&self) -> f32 {
491 self.inner.flex_weight_erased()
492 }
493}
494
495#[derive(Debug, Clone, PartialEq)]
499pub struct BifrostBridgeModifier {
500 pub id: String,
501}
502
503impl ViewModifier for BifrostBridgeModifier {
504 fn modify<V: View>(self, content: V) -> impl View {
505 ModifiedView::new(content, self)
506 }
507
508 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
509 renderer.register_shared_element(&self.id, rect);
511 }
512}
513
514#[derive(Debug, Clone, Copy, PartialEq)]
517pub struct MjolnirSliceModifier {
518 pub angle: f32,
519 pub offset: f32,
520}
521
522impl ViewModifier for MjolnirSliceModifier {
523 fn modify<V: View>(self, content: V) -> impl View {
524 ModifiedView::new(content, self)
525 }
526
527 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
528 renderer.push_mjolnir_slice(self.angle, self.offset);
529 }
530
531 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
532 renderer.pop_mjolnir_slice();
533 }
534}
535
536#[derive(Debug, Clone, Copy, PartialEq)]
539pub struct MjolnirShatterModifier {
540 pub pieces: u32,
541 pub force: f32,
542}
543
544impl ViewModifier for MjolnirShatterModifier {
545 fn modify<V: View>(self, content: V) -> impl View {
546 ModifiedView::new(content, self)
547 }
548
549 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
550 let pieces = self.pieces.max(1);
552 for i in 0..pieces {
553 let progress = i as f32 / pieces as f32;
554 let next_progress = (i + 1) as f32 / pieces as f32;
555
556 let angle_start = progress * 360.0;
557 let angle_end = next_progress * 360.0;
558
559 renderer.push_mjolnir_slice(angle_start, 0.0);
561 renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
562
563 let mid_angle = (angle_start + angle_end) / 2.0;
565 let rad = mid_angle.to_radians();
566 let dx = rad.cos() * self.force;
567 let dy = rad.sin() * self.force;
568
569 let shard_rect = Rect {
570 x: rect.x + dx,
571 y: rect.y + dy,
572 ..rect
573 };
574
575 view.render(renderer, shard_rect);
576
577 renderer.pop_mjolnir_slice();
578 renderer.pop_mjolnir_slice();
579 }
580 }
581}
582
583#[derive(Debug, Clone, Copy, PartialEq)]
586pub struct BifrostModifier {
587 pub blur: f32,
588 pub saturation: f32,
589 pub opacity: f32,
590}
591
592impl ViewModifier for BifrostModifier {
593 fn modify<V: View>(self, content: V) -> impl View {
594 ModifiedView::new(content, self)
595 }
596
597 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
598 renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
599 }
600}
601
602#[derive(Debug, Clone, Copy, PartialEq)]
604pub struct BackgroundModifier {
605 pub color: [f32; 4],
606}
607
608impl ViewModifier for BackgroundModifier {
609 fn modify<V: View>(self, content: V) -> impl View {
610 ModifiedView::new(content, self)
611 }
612
613 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
614 renderer.fill_rect(rect, self.color);
615 }
616}
617
618#[derive(Debug, Clone, Copy, PartialEq)]
620pub struct PaddingModifier {
621 pub amount: f32,
622}
623
624impl ViewModifier for PaddingModifier {
625 fn modify<V: View>(self, content: V) -> impl View {
626 ModifiedView::new(content, self)
627 }
628
629 fn transform_rect(&self, rect: Rect) -> Rect {
630 Rect {
631 x: rect.x + self.amount,
632 y: rect.y + self.amount,
633 width: (rect.width - 2.0 * self.amount).max(0.0),
634 height: (rect.height - 2.0 * self.amount).max(0.0),
635 }
636 }
637
638 fn transform_proposal(&self, mut proposal: SizeProposal) -> SizeProposal {
639 if let Some(w) = proposal.width {
640 proposal.width = Some((w - 2.0 * self.amount).max(0.0));
641 }
642 if let Some(h) = proposal.height {
643 proposal.height = Some((h - 2.0 * self.amount).max(0.0));
644 }
645 proposal
646 }
647
648 fn transform_size(&self, mut size: Size) -> Size {
649 size.width += 2.0 * self.amount;
650 size.height += 2.0 * self.amount;
651 size
652 }
653}
654
655#[derive(Debug, Clone, PartialEq)]
658pub struct GungnirModifier {
659 pub color: String,
660 pub radius: f32,
661 pub intensity: f32,
662}
663
664impl ViewModifier for GungnirModifier {
665 fn modify<V: View>(self, content: V) -> impl View {
666 ModifiedView::new(content, self)
667 }
668
669 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
670 renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
672 }
673}
674
675#[derive(Debug, Clone, Copy, PartialEq)]
677pub struct GungnirPulseModifier {
678 pub color: [f32; 4],
679 pub radius: f32,
680 pub speed: f32,
681}
682
683impl ViewModifier for GungnirPulseModifier {
684 fn modify<V: View>(self, content: V) -> impl View {
685 ModifiedView::new(content, self)
686 }
687
688 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
689 let time = std::time::SystemTime::now()
690 .duration_since(std::time::UNIX_EPOCH)
691 .unwrap_or_default()
692 .as_secs_f32();
693
694 let intensity = (time * self.speed).sin() * 0.5 + 0.5;
697 let mut color = self.color;
698 color[3] *= intensity;
699
700 renderer.stroke_rect(rect, color, self.radius);
702 }
703}
704
705#[derive(Debug, Clone, Copy, PartialEq)]
707pub struct SleipnirParams {
708 pub stiffness: f32,
709 pub damping: f32,
710 pub mass: f32,
711}
712
713impl SleipnirParams {
714 pub fn snappy() -> Self { Self { stiffness: 230.0, damping: 22.0, mass: 1.0 } }
715 pub fn fluid() -> Self { Self { stiffness: 170.0, damping: 26.0, mass: 1.0 } }
716 pub fn heavy() -> Self { Self { stiffness: 90.0, damping: 20.0, mass: 1.0 } }
717 pub fn bouncy() -> Self { Self { stiffness: 190.0, damping: 14.0, mass: 1.0 } }
718}
719
720impl Default for SleipnirParams {
721 fn default() -> Self { Self::fluid() }
722}
723
724#[derive(Debug, Clone, Copy, PartialEq)]
725struct SolverState {
726 x: f32,
727 v: f32,
728}
729
730#[derive(Debug, Clone, Copy, PartialEq)]
733pub struct SleipnirSolver {
734 params: SleipnirParams,
735 target: f32,
736 state: SolverState,
737}
738
739impl SleipnirSolver {
740 pub fn new(params: SleipnirParams, target: f32, current: f32) -> Self {
742 Self {
743 params,
744 target,
745 state: SolverState { x: current, v: 0.0 },
746 }
747 }
748
749 pub fn tick(&mut self, dt: f32) -> f32 {
751 if dt <= 0.0 { return self.state.x; }
752
753 let mut remaining = dt;
755 let step = 1.0 / 120.0;
756
757 while remaining > 0.0 {
758 let d = remaining.min(step);
759 self.step(d);
760 remaining -= d;
761 }
762
763 self.state.x
764 }
765
766 fn step(&mut self, dt: f32) {
767 let a = self.evaluate(self.state, 0.0, SolverState { x: 0.0, v: 0.0 });
768 let b = self.evaluate(self.state, dt * 0.5, a);
769 let c = self.evaluate(self.state, dt * 0.5, b);
770 let d = self.evaluate(self.state, dt, c);
771
772 let dxdt = 1.0 / 6.0 * (a.x + 2.0 * (b.x + c.x) + d.x);
773 let dvdt = 1.0 / 6.0 * (a.v + 2.0 * (b.v + c.v) + d.v);
774
775 self.state.x += dxdt * dt;
776 self.state.v += dvdt * dt;
777 }
778
779 fn evaluate(&self, initial: SolverState, dt: f32, d: SolverState) -> SolverState {
780 let state = SolverState {
781 x: initial.x + d.x * dt,
782 v: initial.v + d.v * dt,
783 };
784 let force = -self.params.stiffness * (state.x - self.target) - self.params.damping * state.v;
785 let mass = self.params.mass.max(0.001);
786 SolverState { x: state.v, v: force / mass }
787 }
788
789 pub fn is_settled(&self) -> bool {
790 (self.state.x - self.target).abs() < 0.001 && self.state.v.abs() < 0.001
791 }
792
793 pub fn set_target(&mut self, target: f32) {
794 self.target = target;
795 }
796
797 pub fn current_value(&self) -> f32 {
798 self.state.x
799 }
800}
801
802#[derive(Debug, Clone, PartialEq)]
804pub struct SleipnirModifier {
805 pub id: u64,
806 pub target: f32,
807 pub params: SleipnirParams,
808}
809
810impl ViewModifier for SleipnirModifier {
811 fn modify<V: View>(self, content: V) -> impl View {
812 ModifiedView::new(content, self)
813 }
814
815 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
816 let state = load_system_state();
817
818 let solver_lock_opt = state.get_component_state::<SleipnirSolver>(self.id);
820
821 let current_val;
822
823 if let Some(lock) = solver_lock_opt {
824 let mut solver = lock.write().unwrap();
826 solver.set_target(self.target);
827 current_val = solver.tick(renderer.delta_time());
828
829 if !solver.is_settled() {
831 renderer.request_redraw();
832 }
833 } else {
834 let solver = SleipnirSolver::new(
836 self.params,
837 self.target,
838 self.target );
840
841 get_system_state().rcu(|old| {
843 let mut new_state = (**old).clone();
844 new_state.set_component_state(self.id, solver);
845 new_state
846 });
847
848 current_val = self.target;
849 }
850
851 renderer.push_transform([0.0, current_val], [1.0, 1.0], 0.0);
853 view.render(renderer, rect);
854 renderer.pop_transform();
855 }
856}
857
858#[derive(Debug, Clone, Copy, PartialEq)]
861pub struct TransformModifier {
862 pub translation: [f32; 2],
863 pub scale: [f32; 2],
864 pub rotation: f32,
865}
866
867impl Default for TransformModifier {
868 fn default() -> Self {
869 Self::new()
870 }
871}
872
873impl TransformModifier {
874 pub fn new() -> Self {
875 Self {
876 translation: [0.0, 0.0],
877 scale: [1.0, 1.0],
878 rotation: 0.0,
879 }
880 }
881
882 pub fn translate(mut self, x: f32, y: f32) -> Self {
883 self.translation = [x, y];
884 self
885 }
886
887 pub fn scale(mut self, x: f32, y: f32) -> Self {
888 self.scale = [x, y];
889 self
890 }
891
892 pub fn rotate(mut self, radians: f32) -> Self {
893 self.rotation = radians;
894 self
895 }
896}
897
898impl ViewModifier for TransformModifier {
899 fn modify<V: View>(self, content: V) -> impl View {
900 ModifiedView::new(content, self)
901 }
902
903 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
904 renderer.push_transform(self.translation, self.scale, self.rotation);
905 view.render(renderer, rect);
906 renderer.pop_transform();
907 }
908}
909
910#[derive(Clone)]
913pub struct LifecycleModifier {
914 pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
915 pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
916}
917
918impl ViewModifier for LifecycleModifier {
919 fn modify<V: View>(self, content: V) -> impl View {
920 ModifiedView::new(content, self)
921 }
922}
923
924#[derive(Debug, Clone, Copy, PartialEq)]
927pub struct OpacityModifier {
928 pub opacity: f32,
929}
930
931impl ViewModifier for OpacityModifier {
932 fn modify<V: View>(self, content: V) -> impl View {
933 ModifiedView::new(content, self)
934 }
935
936 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
937 renderer.push_opacity(self.opacity);
938 }
939
940 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
941 renderer.pop_opacity();
942 }
943}
944
945#[derive(Clone)]
947pub struct OnClickModifier {
948 pub action: Arc<dyn Fn() + Send + Sync>,
949}
950
951impl ViewModifier for OnClickModifier {
952 fn modify<V: View>(self, content: V) -> impl View {
953 ModifiedView::new(content, self)
954 }
955
956 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
957 let action = self.action.clone();
958 renderer.register_handler(
959 "pointerclick",
960 std::sync::Arc::new(move |event| {
961 if let Event::PointerClick { .. } = event {
962 (action)();
963 }
964 }),
965 );
966 }
967}
968
969#[derive(Clone)]
971pub struct OnPointerEnterModifier {
972 pub action: Arc<dyn Fn() + Send + Sync>,
973}
974
975impl ViewModifier for OnPointerEnterModifier {
976 fn modify<V: View>(self, content: V) -> impl View {
977 ModifiedView::new(content, self)
978 }
979
980 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
981 let action = self.action.clone();
982 renderer.register_handler(
983 "pointerenter",
984 std::sync::Arc::new(move |event| {
985 if let Event::PointerEnter = event {
986 (action)();
987 }
988 }),
989 );
990 }
991}
992
993#[derive(Clone)]
995pub struct OnPointerLeaveModifier {
996 pub action: Arc<dyn Fn() + Send + Sync>,
997}
998
999impl ViewModifier for OnPointerLeaveModifier {
1000 fn modify<V: View>(self, content: V) -> impl View {
1001 ModifiedView::new(content, self)
1002 }
1003
1004 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1005 let action = self.action.clone();
1006 renderer.register_handler(
1007 "pointerleave",
1008 std::sync::Arc::new(move |event| {
1009 if let Event::PointerLeave = event {
1010 (action)();
1011 }
1012 }),
1013 );
1014 }
1015}
1016
1017#[derive(Clone)]
1019pub struct OnPointerMoveModifier {
1020 pub action: Arc<dyn Fn(f32, f32) + Send + Sync>,
1021}
1022
1023impl ViewModifier for OnPointerMoveModifier {
1024 fn modify<V: View>(self, content: V) -> impl View {
1025 ModifiedView::new(content, self)
1026 }
1027
1028 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1029 let action = self.action.clone();
1030 renderer.register_handler(
1031 "pointermove",
1032 std::sync::Arc::new(move |event| {
1033 if let Event::PointerMove { x, y } = event {
1034 (action)(x, y);
1035 }
1036 }),
1037 );
1038 }
1039}
1040
1041#[derive(Clone)]
1043pub struct OnPointerDownModifier {
1044 pub action: Arc<dyn Fn() + Send + Sync>,
1045}
1046
1047impl ViewModifier for OnPointerDownModifier {
1048 fn modify<V: View>(self, content: V) -> impl View {
1049 ModifiedView::new(content, self)
1050 }
1051
1052 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1053 let action = self.action.clone();
1054 renderer.register_handler(
1055 "pointerdown",
1056 std::sync::Arc::new(move |event| {
1057 if let Event::PointerDown { .. } = event {
1058 (action)();
1059 }
1060 }),
1061 );
1062 }
1063}
1064
1065#[derive(Clone)]
1067pub struct OnPointerUpModifier {
1068 pub action: Arc<dyn Fn() + Send + Sync>,
1069}
1070
1071impl ViewModifier for OnPointerUpModifier {
1072 fn modify<V: View>(self, content: V) -> impl View {
1073 ModifiedView::new(content, self)
1074 }
1075
1076 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1077 let action = self.action.clone();
1078 renderer.register_handler(
1079 "pointerup",
1080 std::sync::Arc::new(move |event| {
1081 if let Event::PointerUp { .. } = event {
1082 (action)();
1083 }
1084 }),
1085 );
1086 }
1087}
1088
1089#[derive(Debug, Clone, Copy, PartialEq)]
1092pub struct ForegroundColorModifier {
1093 pub color: [f32; 4],
1094}
1095
1096impl ViewModifier for ForegroundColorModifier {
1097 fn modify<V: View>(self, content: V) -> impl View {
1098 ModifiedView::new(content, self)
1099 }
1100}
1101
1102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1105pub struct ClipModifier;
1106
1107impl ViewModifier for ClipModifier {
1108 fn modify<V: View>(self, content: V) -> impl View {
1109 ModifiedView::new(content, self)
1110 }
1111
1112 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1113 renderer.push_clip_rect(rect);
1114 }
1115
1116 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1117 renderer.pop_clip_rect();
1118 }
1119}
1120
1121#[derive(Debug, Clone, Copy, PartialEq)]
1123pub struct BorderModifier {
1124 pub color: [f32; 4],
1125 pub width: f32,
1126}
1127
1128impl ViewModifier for BorderModifier {
1129 fn modify<V: View>(self, content: V) -> impl View {
1130 ModifiedView::new(content, self)
1131 }
1132
1133 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1134 renderer.stroke_rect(rect, self.color, self.width);
1135 }
1136}
1137
1138#[doc(hidden)]
1140pub enum Never {}
1141
1142impl View for Never {
1143 type Body = Never;
1144 fn body(self) -> Never {
1145 unreachable!()
1146 }
1147}
1148
1149pub struct ModifiedView<V, M> {
1153 view: V,
1154 modifier: M,
1155}
1156
1157impl<V: View, M: ViewModifier> ModifiedView<V, M> {
1158 #[doc(hidden)]
1159 pub fn new(view: V, modifier: M) -> Self {
1160 Self { view, modifier }
1161 }
1162}
1163
1164impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
1165 type Body = ModifiedView<V::Body, M>;
1166
1167 fn body(self) -> Self::Body {
1168 ModifiedView {
1169 view: self.view.body(),
1170 modifier: self.modifier.clone(),
1171 }
1172 }
1173
1174 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1175 self.modifier.render_view(&self.view, renderer, rect);
1176 }
1177
1178 fn intrinsic_size(&self, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1179 self.modifier.measure_view(&self.view, renderer, proposal)
1180 }
1181
1182 fn flex_weight(&self) -> f32 {
1183 self.modifier.child_flex_weight(&self.view)
1184 }
1185}
1186
1187pub trait ViewModifier: Send + Clone {
1188 fn modify<V: View>(self, content: V) -> impl View;
1189
1190 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1192
1193 fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1195
1196 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1199 self.render(renderer, rect);
1200 let child_rect = self.transform_rect(rect);
1201 view.render(renderer, child_rect);
1202 self.post_render(renderer, rect);
1203 }
1204
1205 fn transform_rect(&self, rect: Rect) -> Rect {
1206 rect
1207 }
1208
1209 fn transform_proposal(&self, proposal: SizeProposal) -> SizeProposal {
1211 proposal
1212 }
1213
1214 fn transform_size(&self, size: Size) -> Size {
1216 size
1217 }
1218
1219 fn measure_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1221 let child_proposal = self.transform_proposal(proposal);
1222 let child_size = view.intrinsic_size(renderer, child_proposal);
1223 self.transform_size(child_size)
1224 }
1225
1226 fn child_flex_weight<V: View>(&self, view: &V) -> f32 {
1228 view.flex_weight()
1229 }
1230}
1231
1232#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1234pub struct TelemetryData {
1235 pub frame_time_ms: f32,
1236
1237 pub input_time_ms: f32,
1239 pub state_flush_time_ms: f32,
1240 pub layout_time_ms: f32,
1241 pub draw_time_ms: f32,
1242 pub gpu_submit_time_ms: f32,
1243
1244 pub draw_calls: u32,
1245 pub vertices: u32,
1246
1247 pub vram_usage_mb: f32,
1249 pub vram_textures_mb: f32,
1250 pub vram_buffers_mb: f32,
1251 pub vram_pipelines_mb: f32,
1252}
1253
1254#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1256pub struct FrameBudget {
1257 pub target_ms: f32,
1259 pub allow_degradation: bool,
1262}
1263
1264impl Default for FrameBudget {
1265 fn default() -> Self {
1266 Self {
1267 target_ms: 16.0,
1268 allow_degradation: true,
1269 }
1270 }
1271}
1272
1273pub trait ElapsedTime {
1282 fn elapsed_time(&self) -> f32;
1284
1285 fn delta_time(&self) -> f32;
1287}
1288
1289pub trait Renderer: ElapsedTime + Send {
1297 fn request_redraw(&mut self) {}
1300
1301 fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
1303 fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
1304 fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
1306
1307 fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1309 fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
1310 fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1312 fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
1314
1315 fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
1317 fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
1319
1320 fn draw_texture(&mut self, _texture_id: u32, _rect: Rect) {}
1323 fn draw_image(&mut self, _image_name: &str, _rect: Rect) {}
1325 fn load_image(&mut self, _name: &str, _data: &[u8]) {}
1327
1328 fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
1331 fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
1333
1334 fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
1337
1338 fn draw_linear_gradient(
1341 &mut self,
1342 _rect: Rect,
1343 _start_color: [f32; 4],
1344 _end_color: [f32; 4],
1345 _angle: f32,
1346 ) {
1347 }
1348 fn draw_radial_gradient(
1350 &mut self,
1351 _rect: Rect,
1352 _inner_color: [f32; 4],
1353 _outer_color: [f32; 4],
1354 ) {
1355 }
1356 fn draw_drop_shadow(
1358 &mut self,
1359 _rect: Rect,
1360 _radius: f32,
1361 _color: [f32; 4],
1362 _blur: f32,
1363 _spread: f32,
1364 ) {
1365 }
1366 fn stroke_dashed_rounded_rect(
1368 &mut self,
1369 _rect: Rect,
1370 _radius: f32,
1371 _color: [f32; 4],
1372 _width: f32,
1373 _dash: f32,
1374 _gap: f32,
1375 ) {
1376 }
1377 fn draw_9slice(
1379 &mut self,
1380 _image_name: &str,
1381 _rect: Rect,
1382 _left: f32,
1383 _top: f32,
1384 _right: f32,
1385 _bottom: f32,
1386 ) {
1387 }
1388
1389 fn push_clip_rect(&mut self, _rect: Rect) {}
1393 fn pop_clip_rect(&mut self) {}
1395
1396 fn push_opacity(&mut self, _opacity: f32) {}
1400 fn pop_opacity(&mut self) {}
1402
1403 fn set_theme(&mut self, _theme: ColorTheme) {}
1405 fn set_rage(&mut self, _rage: f32) {}
1406 fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
1407
1408 fn bifrost(&mut self, _rect: Rect, _blur: f32, _saturation: f32, _opacity: f32) {}
1411 fn gungnir(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32, _intensity: f32) {}
1413 fn push_mjolnir_slice(&mut self, _angle: f32, _offset: f32) {}
1415 fn pop_mjolnir_slice(&mut self) {}
1416 fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1418 fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1419 fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
1421
1422 fn set_aria_role(&mut self, _role: &str) {}
1424 fn set_aria_label(&mut self, _label: &str) {}
1425
1426 fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
1428
1429 fn set_key(&mut self, _key: &str) {}
1431
1432 fn get_telemetry(&self) -> TelemetryData {
1435 TelemetryData::default()
1436 }
1437
1438 fn push_shadow(&mut self, _radius: f32, _color: [f32; 4], _offset: [f32; 2]) {}
1441 fn pop_shadow(&mut self) {}
1443
1444 fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
1447 fn pop_vnode(&mut self) {}
1449 fn register_handler(
1451 &mut self,
1452 _event_type: &str,
1453 _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
1454 ) {
1455 }
1456
1457 fn set_z_index(&mut self, _z: f32) {}
1461 fn get_z_index(&self) -> f32 {
1463 0.0
1464 }
1465
1466 fn load_svg(&mut self, _name: &str, _svg_data: &[u8]) {}
1469 fn draw_svg(&mut self, _name: &str, _rect: Rect) {}
1471
1472 fn push_transform(&mut self, _translation: [f32; 2], _scale: [f32; 2], _rotation: f32) {}
1477 fn pop_transform(&mut self) {}
1479 fn query_layout(&self, _node_id: scene_graph::NodeId) -> Option<Rect> {
1481 None
1482 }
1483 fn set_debug_layout(&mut self, _enabled: bool) {}
1485 fn get_debug_layout(&self) -> bool {
1487 false
1488 }
1489}
1490#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
1492pub enum RenderTier {
1493 Tier1GPU = 0,
1495 Tier2GPU = 1,
1497 Tier3Fallback = 2,
1499}
1500use bytemuck::{Pod, Zeroable};
1504#[repr(C)]
1506#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1507pub struct ColorTheme {
1508 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
1510 pub glass_base: [f32; 4],
1511 pub glass_edge: [f32; 4],
1512 pub rune_glow: [f32; 4],
1513 pub ember_core: [f32; 4],
1514 pub background_deep: [f32; 4],
1515 pub glass_blur_strength: f32,
1516 pub shatter_edge_width: f32,
1517 pub neon_bloom_radius: f32,
1518 pub rune_opacity: f32, pub _pad: [f32; 3], pub _pad2: f32,
1522}
1523impl ColorTheme {
1524 pub fn cyberpunk_viking() -> Self {
1525 Self {
1526 primary_neon: [0.0, 1.0, 0.95, 1.2],
1527 shatter_neon: [1.0, 0.0, 0.75, 1.5],
1528 glass_base: [0.04, 0.04, 0.06, 0.82],
1529 glass_edge: [0.0, 0.45, 0.55, 0.6],
1530 rune_glow: [0.75, 0.98, 1.0, 0.9],
1531 ember_core: [0.95, 0.12, 0.12, 1.0],
1532 background_deep: [0.01, 0.01, 0.03, 1.0],
1533 glass_blur_strength: 0.6,
1534 shatter_edge_width: 1.8,
1535 neon_bloom_radius: 0.022,
1536 rune_opacity: 0.55,
1537 _pad: [0.0; 3],
1538 _pad2: 0.0,
1539 }
1540 }
1541 pub fn vibrant_glass() -> Self {
1542 Self {
1543 primary_neon: [0.0, 1.0, 0.95, 1.2],
1544 shatter_neon: [1.0, 0.0, 0.75, 1.5],
1545 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],
1548 ember_core: [1.0, 0.4, 0.1, 1.0],
1549 background_deep: [0.05, 0.05, 0.1, 1.0],
1550 glass_blur_strength: 0.9,
1551 shatter_edge_width: 1.8,
1552 neon_bloom_radius: 0.022,
1553 rune_opacity: 0.55,
1554 _pad: [0.0; 3],
1555 _pad2: 0.0,
1556 }
1557 }
1558}
1559impl Default for ColorTheme {
1560 fn default() -> Self {
1561 Self::vibrant_glass()
1562 }
1563}
1564#[repr(C)]
1566#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1567pub struct SceneUniforms {
1568 pub view: glam::Mat4,
1569 pub proj: glam::Mat4,
1570 pub time: f32,
1571 pub delta_time: f32,
1572 pub resolution: [f32; 2],
1573 pub mouse: [f32; 2],
1574 pub mouse_velocity: [f32; 2],
1575 pub shatter_origin: [f32; 2],
1576 pub shatter_time: f32,
1577 pub shatter_force: f32,
1578 pub berzerker_rage: f32,
1579 pub scroll_offset: f32,
1580 pub scale_factor: f32,
1581 pub _pad: [f32; 1],
1583}
1584impl SceneUniforms {
1585 pub fn new(width: f32, height: f32) -> Self {
1586 Self {
1587 view: glam::Mat4::IDENTITY,
1588 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
1589 time: 0.0,
1590 delta_time: 0.016,
1591 resolution: [width, height],
1592 mouse: [0.5, 0.5],
1593 mouse_velocity: [0.0, 0.0],
1594 shatter_origin: [0.5, 0.5],
1595 shatter_time: -100.0,
1596 shatter_force: 0.0,
1597 berzerker_rage: 0.0,
1598 scroll_offset: 0.0,
1599 scale_factor: 1.0,
1600 _pad: [0.0; 1],
1601 }
1602 }
1603}
1604#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1606pub struct Mesh {
1607 pub vertices: Vec<[f32; 3]>,
1608 pub normals: Vec<[f32; 3]>,
1609 pub indices: Vec<u32>,
1610}
1611impl Mesh {
1612 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
1613 let mut cursor = std::io::Cursor::new(data);
1614 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
1615 Ok((Vec::new(), Default::default()))
1616 })?;
1617 let mut meshes = Vec::new();
1618 for m in models {
1619 let mesh = m.mesh;
1620 let vertices: Vec<[f32; 3]> = mesh
1621 .positions
1622 .chunks(3)
1623 .map(|c| [c[0], c[1], c[2]])
1624 .collect();
1625 let normals = if mesh.normals.is_empty() {
1626 vec![[0.0, 0.0, 1.0]; vertices.len()]
1627 } else {
1628 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
1629 };
1630 meshes.push(Mesh {
1631 vertices,
1632 normals,
1633 indices: mesh.indices,
1634 });
1635 }
1636 Ok(meshes)
1637 }
1638 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
1639 let mut cursor = std::io::Cursor::new(data);
1640 let stl = stl_io::read_stl(&mut cursor)?;
1641 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
1642 let mut indices = Vec::new();
1643 for face in stl.faces {
1644 indices.push(face.vertices[0] as u32);
1645 indices.push(face.vertices[1] as u32);
1646 indices.push(face.vertices[2] as u32);
1647 }
1648 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
1649 Ok(Mesh {
1650 vertices,
1651 normals,
1652 indices,
1653 })
1654 }
1655}
1656pub trait FrameRenderer<E = ()>: Renderer {
1659 fn begin_frame(&mut self) -> E;
1660 fn end_frame(&mut self, encoder: E);
1661}
1662use std::sync::Arc;
1663#[derive(Clone)]
1665pub struct State<T: Clone + Send + Sync + 'static> {
1666 swap: Arc<arc_swap::ArcSwap<T>>,
1667 metadata_swap: Arc<arc_swap::ArcSwap<Option<agents::MutationMetadata>>>,
1668 #[cfg(not(target_arch = "wasm32"))]
1669 tvar: Arc<stm::TVar<T>>,
1670 #[cfg(not(target_arch = "wasm32"))]
1671 metadata_tvar: Arc<stm::TVar<Option<agents::MutationMetadata>>>,
1672 subscribers: Arc<std::sync::Mutex<Vec<Box<dyn Fn(&T) + Send + Sync>>>>,
1673 version: Arc<std::sync::atomic::AtomicU64>,
1674 resolution: agents::ConflictResolution,
1675}
1676impl<T: Clone + Send + Sync + 'static> State<T> {
1677 pub fn new(value: T) -> Self {
1679 #[cfg(not(target_arch = "wasm32"))]
1680 let tvar = Arc::new(stm::TVar::new(value.clone()));
1681 #[cfg(not(target_arch = "wasm32"))]
1682 let metadata_tvar = Arc::new(stm::TVar::new(None));
1683 Self {
1684 swap: Arc::new(arc_swap::ArcSwap::from_pointee(value)),
1685 metadata_swap: Arc::new(arc_swap::ArcSwap::new(Arc::new(None))),
1686 #[cfg(not(target_arch = "wasm32"))]
1687 tvar,
1688 #[cfg(not(target_arch = "wasm32"))]
1689 metadata_tvar,
1690 subscribers: Arc::new(std::sync::Mutex::new(Vec::new())),
1691 version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
1692 resolution: agents::ConflictResolution::default(),
1693 }
1694 }
1695 pub fn with_resolution(mut self, resolution: agents::ConflictResolution) -> Self {
1697 self.resolution = resolution;
1698 self
1699 }
1700 pub fn get(&self) -> T {
1702 (**self.swap.load()).clone()
1703 }
1704 pub fn set(&self, value: T) {
1706 #[cfg(not(target_arch = "wasm32"))]
1707 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
1708 let new_meta = agents::get_current_mutation_metadata();
1709 let existing_meta = self.metadata_tvar.read(tx)?;
1710 let mut skip = false;
1711 if self.resolution == agents::ConflictResolution::PriorityWins
1712 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
1713 && new_m.priority < old_m.priority {
1714 skip = true;
1715 }
1716 if !skip {
1717 self.tvar.write(tx, value.clone())?;
1718 self.metadata_tvar.write(tx, new_meta)?;
1719 Ok((false, value.clone(), new_meta))
1720 } else {
1721 Ok((true, self.tvar.read(tx)?, existing_meta))
1722 }
1723 });
1724 #[cfg(target_arch = "wasm32")]
1725 let (was_skipped, final_val, final_meta) = (false, value, agents::get_current_mutation_metadata());
1726 if was_skipped {
1727 if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
1728 agents::notify_conflict(agents::ConflictEvent {
1729 agent_id: new_m.agent_id,
1730 priority: new_m.priority,
1731 existing_agent_id: old_m.agent_id,
1732 existing_priority: old_m.priority,
1733 timestamp_ms: new_m.timestamp_ms,
1734 });
1735 }
1736 return;
1737 }
1738 self.swap.store(Arc::new(final_val.clone()));
1739 self.metadata_swap.store(Arc::new(final_meta));
1740 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
1741 let subs = Arc::clone(&self.subscribers);
1742 if crate::is_batching() {
1743 crate::enqueue_batch_task(Box::new(move || {
1744 let s = subs.lock().unwrap();
1745 for cb in s.iter() {
1746 cb(&final_val);
1747 }
1748 }));
1749 } else {
1750 let s = subs.lock().unwrap();
1751 for cb in s.iter() {
1752 cb(&final_val);
1753 }
1754 }
1755 }
1756 pub fn mutate<F: Fn(&T) -> T>(&self, f: F) {
1757 #[cfg(not(target_arch = "wasm32"))]
1758 {
1759 let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
1760 let new_meta = agents::get_current_mutation_metadata();
1761 let existing_meta = self.metadata_tvar.read(tx)?;
1762 let mut skip = false;
1763 if self.resolution == agents::ConflictResolution::PriorityWins
1764 && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
1765 && new_m.priority < old_m.priority {
1766 skip = true;
1767 }
1768 if !skip {
1769 let current = self.tvar.read(tx)?;
1770 let next = f(¤t);
1771 self.tvar.write(tx, next.clone())?;
1772 self.metadata_tvar.write(tx, new_meta)?;
1773 Ok((false, next, new_meta))
1774 } else {
1775 Ok((true, self.tvar.read(tx)?, existing_meta))
1776 }
1777 });
1778 if was_skipped {
1779 if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
1780 agents::notify_conflict(agents::ConflictEvent {
1781 agent_id: new_m.agent_id,
1782 priority: new_m.priority,
1783 existing_agent_id: old_m.agent_id,
1784 existing_priority: old_m.priority,
1785 timestamp_ms: new_m.timestamp_ms,
1786 });
1787 }
1788 return;
1789 }
1790 self.swap.store(Arc::new(final_val.clone()));
1791 self.metadata_swap.store(Arc::new(final_meta));
1792 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
1793 let subs = Arc::clone(&self.subscribers);
1794 if crate::is_batching() {
1795 crate::enqueue_batch_task(Box::new(move || {
1796 let s = subs.lock().unwrap();
1797 for cb in s.iter() {
1798 cb(&final_val);
1799 }
1800 }));
1801 } else {
1802 let s = subs.lock().unwrap();
1803 for cb in s.iter() {
1804 cb(&final_val);
1805 }
1806 }
1807 }
1808 #[cfg(target_arch = "wasm32")]
1809 {
1810 self.set(f(&self.get()));
1811 }
1812 }
1813 pub fn version(&self) -> u64 {
1815 self.version.load(std::sync::atomic::Ordering::Acquire)
1816 }
1817 pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
1819 self.subscribers.lock().unwrap().push(Box::new(callback));
1820 }
1821}
1822use crate::runtime::NodeStateSnapshot;
1823use std::sync::atomic::{AtomicBool, Ordering};
1824use std::sync::OnceLock;
1825pub static SYSTEM_STATE: OnceLock<Arc<arc_swap::ArcSwap<KnowledgeState>>> = OnceLock::new();
1827#[cfg(not(target_arch = "wasm32"))]
1828static KNOWLEDGE_TVAR: OnceLock<stm::TVar<KnowledgeState>> = OnceLock::new();
1829static IS_BATCHING: AtomicBool = AtomicBool::new(false);
1830pub static IS_RENDERING: AtomicBool = AtomicBool::new(false);
1831pub static LAYOUT_DIRTY: AtomicBool = AtomicBool::new(false);
1832static BATCH_QUEUE: OnceLock<std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync>>>> = OnceLock::new();
1833pub fn is_batching() -> bool {
1835 IS_BATCHING.load(Ordering::Acquire)
1836}
1837pub fn is_rendering() -> bool {
1839 IS_RENDERING.load(Ordering::Acquire)
1840}
1841pub fn begin_render_phase() {
1843 IS_RENDERING.store(true, Ordering::Release);
1844}
1845pub fn end_render_phase() {
1847 IS_RENDERING.store(false, Ordering::Release);
1848}
1849pub fn enqueue_batch_task(task: Box<dyn FnOnce() + Send + Sync>) {
1851 let mut queue = BATCH_QUEUE
1852 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
1853 .lock()
1854 .unwrap();
1855 queue.push(task);
1856}
1857pub fn batch<F: FnOnce()>(f: F) {
1861 if IS_BATCHING.swap(true, Ordering::AcqRel) {
1862 f();
1864 return;
1865 }
1866 f();
1867 IS_BATCHING.store(false, Ordering::Release);
1868 let mut queue = BATCH_QUEUE
1869 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
1870 .lock()
1871 .unwrap();
1872 let tasks: Vec<_> = queue.drain(..).collect();
1873 drop(queue);
1874 for task in tasks {
1875 task();
1876 }
1877}
1878pub fn get_system_state() -> Arc<arc_swap::ArcSwap<KnowledgeState>> {
1880 SYSTEM_STATE
1881 .get_or_init(|| Arc::new(arc_swap::ArcSwap::from_pointee(KnowledgeState::default())))
1882 .clone()
1883}
1884pub fn load_system_state() -> arc_swap::Guard<Arc<KnowledgeState>> {
1885 get_system_state().load()
1886}
1887pub fn update_system_state<F>(f: F)
1888where
1889 F: Fn(&KnowledgeState) -> KnowledgeState,
1890{
1891 if is_rendering() {
1892 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1893 }
1894 LAYOUT_DIRTY.store(true, Ordering::SeqCst);
1895 let swap = get_system_state();
1896 let current = swap.load();
1897 let new_state = Arc::new(f(¤t));
1898 swap.store(Arc::clone(&new_state));
1899 #[cfg(not(target_arch = "wasm32"))]
1900 {
1901 let tvar = KNOWLEDGE_TVAR
1902 .get_or_init(|| stm::TVar::new((*new_state).clone()));
1903 stm::atomically(|tx| tvar.write(tx, (*new_state).clone()));
1904 }
1905}
1906pub fn transact_system_state<F>(f: F)
1907where
1908 F: Fn(&KnowledgeState) -> KnowledgeState,
1909{
1910 #[cfg(not(target_arch = "wasm32"))]
1911 {
1912 if is_rendering() {
1913 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1914 }
1915 let tvar = KNOWLEDGE_TVAR
1916 .get_or_init(|| {
1917 stm::TVar::new((**get_system_state().load()).clone())
1918 })
1919 .clone();
1920 let new_state = stm::atomically(move |tx| {
1921 let current = tvar.read(tx)?;
1922 let next = f(¤t);
1923 tvar.write(tx, next.clone())?;
1924 Ok(next)
1925 });
1926 get_system_state().store(Arc::new(new_state));
1927 }
1928 #[cfg(target_arch = "wasm32")]
1929 {
1930 if is_rendering() {
1931 log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1932 }
1933 update_system_state(f);
1934 }
1935}
1936impl KnowledgeState {
1937 pub fn new() -> Self {
1939 Self::default()
1940 }
1941 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
1943 self.component_states
1944 .insert(id, Arc::new(std::sync::RwLock::new(state)));
1945 }
1946pub fn get_component_state<T: 'static + Send + Sync>(
1948 &self,
1949 id: u64,
1950 ) -> Option<Arc<std::sync::RwLock<T>>> {
1951 let lock = self.component_states.get(&id)?;
1952 let _inner: &std::sync::RwLock<dyn std::any::Any + Send + Sync> = lock;
1954 None }
1958 pub fn remember(&mut self, fragment: KnowledgeFragment) {
1960 self.fragments.insert(fragment.id.clone(), fragment);
1961 }
1962 pub fn process_query(&mut self, query: &str) {
1964 let query_lower = query.to_lowercase();
1965 let mut results: Vec<(f32, String)> = self
1966 .fragments
1967 .iter()
1968 .map(|(id, frag)| {
1969 let mut score = 0.0;
1970 if frag.summary.to_lowercase().contains(&query_lower) {
1971 score += 1.0;
1972 }
1973 if frag.source.to_lowercase().contains(&query_lower) {
1974 score += 0.5;
1975 }
1976 (score, id.clone())
1977 })
1978 .filter(|(score, _)| *score > 0.0)
1979 .collect();
1980 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
1982 self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
1983 }
1984 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
1986 let mut snapshots = Vec::new();
1987 for frag in self.fragments.values() {
1989 if let Ok(val) = serde_json::to_value(frag) {
1990 snapshots.push(NodeStateSnapshot { id: 0, state: val });
1991 }
1992 }
1993 snapshots
1994 }
1995}
1996#[derive(Clone)]
1998pub struct Binding<T: Clone + Send + Sync + 'static> {
1999 swap: Arc<arc_swap::ArcSwap<T>>,
2000 #[cfg(not(target_arch = "wasm32"))]
2001 tvar: Arc<stm::TVar<T>>,
2002 version: Arc<std::sync::atomic::AtomicU64>,
2003}
2004impl<T: Clone + Send + Sync + 'static> Binding<T> {
2005 pub fn from_state(state: &State<T>) -> Self {
2007 Self {
2008 swap: Arc::clone(&state.swap),
2009 #[cfg(not(target_arch = "wasm32"))]
2010 tvar: Arc::clone(&state.tvar),
2011 version: Arc::clone(&state.version),
2012 }
2013 }
2014 pub fn get(&self) -> T {
2016 (**self.swap.load()).clone()
2017 }
2018 pub fn set(&self, value: T) {
2020 self.swap.store(Arc::new(value.clone()));
2021 #[cfg(not(target_arch = "wasm32"))]
2022 {
2023 let tvar = Arc::clone(&self.tvar);
2024 let v = value.clone();
2025 stm::atomically(move |tx| tvar.write(tx, v.clone()));
2026 }
2027 self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2028 }
2029 pub fn version(&self) -> u64 {
2031 self.version.load(std::sync::atomic::Ordering::Acquire)
2032 }
2033}
2034#[cfg(not(target_arch = "wasm32"))]
2035pub fn transact_pair<A, B, F>(state_a: &State<A>, state_b: &State<B>, f: F)
2036where
2037 A: Clone + Send + Sync + 'static,
2038 B: Clone + Send + Sync + 'static,
2039 F: Fn(&A, &B) -> (A, B),
2040{
2041 let tvar_a = Arc::clone(&state_a.tvar);
2042 let tvar_b = Arc::clone(&state_b.tvar);
2043 let (new_a, new_b) = stm::atomically(move |tx| {
2044 let a = tvar_a.read(tx)?;
2045 let b = tvar_b.read(tx)?;
2046 let (na, nb) = f(&a, &b);
2047 tvar_a.write(tx, na.clone())?;
2048 tvar_b.write(tx, nb.clone())?;
2049 Ok((na, nb))
2050 });
2051 state_a.swap.store(Arc::new(new_a.clone()));
2052 state_b.swap.store(Arc::new(new_b.clone()));
2053 state_a.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2054 state_b.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2055 let subs_a = Arc::clone(&state_a.subscribers);
2056 let subs_b = Arc::clone(&state_b.subscribers);
2057 if crate::is_batching() {
2058 crate::enqueue_batch_task(Box::new(move || {
2059 {
2060 let s = subs_a.lock().unwrap();
2061 for cb in s.iter() { cb(&new_a); }
2062 }
2063 {
2064 let s = subs_b.lock().unwrap();
2065 for cb in s.iter() { cb(&new_b); }
2066 }
2067 }));
2068 } else {
2069 {
2070 let s = subs_a.lock().unwrap();
2071 for cb in s.iter() { cb(&new_a); }
2072 }
2073 {
2074 let s = subs_b.lock().unwrap();
2075 for cb in s.iter() { cb(&new_b); }
2076 }
2077 }
2078}
2079use std::any::TypeId;
2080use std::sync::Mutex;
2081pub(crate) static ENVIRONMENT: OnceLock<
2083 Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
2084> = OnceLock::new();
2085pub trait EnvKey: 'static + Send + Sync {
2089 type Value: Clone + Send + Sync + 'static;
2091 fn default_value() -> Self::Value;
2093}
2094pub struct YggdrasilKey;
2096impl EnvKey for YggdrasilKey {
2097 type Value = YggdrasilTokens;
2098 fn default_value() -> Self::Value {
2099 default_tokens()
2100 }
2101}
2102#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2105pub enum Appearance {
2106 Light,
2107 Dark,
2108}
2109#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2111pub enum Orientation {
2112 Horizontal,
2113 Vertical,
2114}
2115#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2117pub enum Alignment {
2118 #[default]
2119 Center,
2120 Leading,
2121 Trailing,
2122 Top,
2123 Bottom,
2124}
2125#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2127pub enum Distribution {
2128 #[default]
2129 Fill,
2130 Center,
2131 Leading,
2132 Trailing,
2133 SpaceBetween,
2134 SpaceAround,
2135 SpaceEvenly,
2136}
2137#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2139pub struct Color {
2140 pub r: f32,
2141 pub g: f32,
2142 pub b: f32,
2143 pub a: f32,
2144}
2145impl Color {
2146 pub const BLACK: Color = Color {
2147 r: 0.0,
2148 g: 0.0,
2149 b: 0.0,
2150 a: 1.0,
2151 };
2152 pub const WHITE: Color = Color {
2153 r: 1.0,
2154 g: 1.0,
2155 b: 1.0,
2156 a: 1.0,
2157 };
2158 pub const TRANSPARENT: Color = Color {
2159 r: 0.0,
2160 g: 0.0,
2161 b: 0.0,
2162 a: 0.0,
2163 };
2164 pub const RED: Color = Color {
2165 r: 1.0,
2166 g: 0.0,
2167 b: 0.0,
2168 a: 1.0,
2169 };
2170 pub const GREEN: Color = Color {
2171 r: 0.0,
2172 g: 1.0,
2173 b: 0.0,
2174 a: 1.0,
2175 };
2176 pub const BLUE: Color = Color {
2177 r: 0.0,
2178 g: 0.0,
2179 b: 1.0,
2180 a: 1.0,
2181 };
2182 pub fn relative_luminance(&self) -> f32 {
2184 fn res(c: f32) -> f32 {
2185 if c <= 0.03928 {
2186 c / 12.92
2187 } else {
2188 ((c + 0.055) / 1.055).powf(2.4)
2189 }
2190 }
2191 0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
2192 }
2193 pub fn contrast_ratio(&self, other: &Color) -> f32 {
2195 let l1 = self.relative_luminance();
2196 let l2 = other.relative_luminance();
2197 if l1 > l2 {
2198 (l1 + 0.05) / (l2 + 0.05)
2199 } else {
2200 (l2 + 0.05) / (l1 + 0.05)
2201 }
2202 }
2203 pub const CYAN: Color = Color {
2204 r: 0.0,
2205 g: 1.0,
2206 b: 1.0,
2207 a: 1.0,
2208 };
2209 pub const YELLOW: Color = Color {
2210 r: 1.0,
2211 g: 1.0,
2212 b: 0.0,
2213 a: 1.0,
2214 };
2215 pub const MAGENTA: Color = Color {
2216 r: 1.0,
2217 g: 0.0,
2218 b: 1.0,
2219 a: 1.0,
2220 };
2221 pub const GRAY: Color = Color {
2222 r: 0.5,
2223 g: 0.5,
2224 b: 0.5,
2225 a: 1.0,
2226 };
2227 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
2229 Self { r, g, b, a }
2230 }
2231 pub fn as_array(&self) -> [f32; 4] {
2233 [self.r, self.g, self.b, self.a]
2234 }
2235}
2236impl View for Color {
2237 type Body = Never;
2238 fn body(self) -> Self::Body {
2239 unreachable!()
2240 }
2241 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
2242 renderer.fill_rect(rect, self.as_array());
2243 }
2244}
2245pub struct AppearanceKey;
2247impl EnvKey for AppearanceKey {
2248 type Value = Appearance;
2249 fn default_value() -> Self::Value {
2250 Appearance::Dark }
2252}
2253pub struct StyleResolver;
2255impl StyleResolver {
2256 pub fn color(key: &str) -> String {
2258 let tokens = Environment::<YggdrasilKey>::new().get();
2259 let appearance = Environment::<AppearanceKey>::new().get();
2260 let is_dark = appearance == Appearance::Dark;
2261 tokens
2262 .get_color(key, is_dark)
2263 .unwrap_or_else(|| "#FF00FF".to_string()) }
2265 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
2267 let tokens = Environment::<YggdrasilKey>::new().get();
2268 let appearance = Environment::<AppearanceKey>::new().get();
2269 let is_dark = appearance == Appearance::Dark;
2270 tokens.get(category, key, is_dark)
2271 }
2272}
2273pub fn default_tokens() -> YggdrasilTokens {
2275 let mut tokens = YggdrasilTokens::new();
2276 tokens.color.insert(
2278 "background".to_string(),
2279 TokenValue::Single {
2280 value: "#000000".to_string(), },
2282 );
2283 tokens.color.insert(
2284 "primary".to_string(),
2285 TokenValue::Single {
2286 value: "#00FFFF".to_string(), },
2288 );
2289 tokens.color.insert(
2290 "secondary".to_string(),
2291 TokenValue::Single {
2292 value: "#FF00FF".to_string(), },
2294 );
2295 tokens.color.insert(
2296 "surface".to_string(),
2297 TokenValue::Adaptive {
2298 light: "#FFFFFF".to_string(),
2299 dark: "#121212".to_string(),
2300 },
2301 );
2302 tokens.color.insert(
2303 "text".to_string(),
2304 TokenValue::Adaptive {
2305 light: "#000000".to_string(),
2306 dark: "#FFFFFF".to_string(),
2307 },
2308 );
2309 tokens.bifrost.insert(
2311 "blur".to_string(),
2312 TokenValue::Single {
2313 value: "25.0".to_string(),
2314 },
2315 );
2316 tokens.bifrost.insert(
2317 "saturation".to_string(),
2318 TokenValue::Single {
2319 value: "1.2".to_string(),
2320 },
2321 );
2322 tokens.bifrost.insert(
2323 "opacity".to_string(),
2324 TokenValue::Single {
2325 value: "0.65".to_string(),
2326 },
2327 );
2328 tokens.gungnir.insert(
2330 "intensity".to_string(),
2331 TokenValue::Single {
2332 value: "1.0".to_string(),
2333 },
2334 );
2335 tokens.gungnir.insert(
2336 "radius".to_string(),
2337 TokenValue::Single {
2338 value: "15.0".to_string(),
2339 },
2340 );
2341 tokens.mjolnir.insert(
2343 "clip_angle".to_string(),
2344 TokenValue::Single {
2345 value: "12.0".to_string(),
2346 },
2347 );
2348 tokens.mjolnir.insert(
2349 "border_width".to_string(),
2350 TokenValue::Single {
2351 value: "2.0".to_string(),
2352 },
2353 );
2354 tokens.anim.insert(
2356 "stiffness".to_string(),
2357 TokenValue::Single {
2358 value: "170.0".to_string(),
2359 },
2360 );
2361 tokens.anim.insert(
2362 "damping".to_string(),
2363 TokenValue::Single {
2364 value: "26.0".to_string(),
2365 },
2366 );
2367 tokens.anim.insert(
2368 "mass".to_string(),
2369 TokenValue::Single {
2370 value: "1.0".to_string(),
2371 },
2372 );
2373 tokens.accessibility.insert(
2375 "reduce_motion".to_string(),
2376 TokenValue::Single {
2377 value: "false".to_string(),
2378 },
2379 );
2380 tokens
2381}
2382pub struct Environment<K: EnvKey> {
2384 _marker: std::marker::PhantomData<K>,
2385}
2386impl<K: EnvKey> Default for Environment<K> {
2387 fn default() -> Self {
2388 Self::new()
2389 }
2390}
2391impl<K: EnvKey> Environment<K> {
2392 pub fn new() -> Self {
2394 Self {
2395 _marker: std::marker::PhantomData,
2396 }
2397 }
2398 pub fn get(&self) -> K::Value {
2400 if let Some(env_store) = ENVIRONMENT.get() {
2401 let env_lock = env_store.lock().unwrap();
2402 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
2403 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
2404 return typed_val.clone();
2405 } else {
2406 log::warn!("Environment: Downcast failed for key type {:?}", std::any::type_name::<K>());
2407 }
2408 } else {
2409 log::debug!("Environment: Key not found: {:?}. Returning default.", std::any::type_name::<K>());
2410 }
2411 } else {
2412 log::debug!("Environment: Store not initialized. Key: {:?}. Returning default.", std::any::type_name::<K>());
2413 }
2414 K::default_value()
2415 }
2416}
2417pub mod env {
2419 pub fn insert<K: super::EnvKey>(value: K::Value) {
2421 let store = super::ENVIRONMENT.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
2422 let mut env_map = store.lock().unwrap();
2423 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
2424 }
2425 pub fn remove<K: super::EnvKey>() {
2427 if let Some(store) = super::ENVIRONMENT.get() {
2428 let mut env_map = store.lock().unwrap();
2429 env_map.remove(&std::any::TypeId::of::<K>());
2430 }
2431 }
2432}
2433#[derive(Debug, Clone, Copy, PartialEq)]
2436pub struct Size {
2437 pub width: f32,
2438 pub height: f32,
2439}
2440
2441impl Size {
2442 pub const ZERO: Self = Self { width: 0.0, height: 0.0 };
2443
2444 pub fn new(width: f32, height: f32) -> Self {
2445 Self { width, height }
2446 }
2447}
2448
2449#[derive(Debug, Clone, Copy, PartialEq)]
2451pub struct EdgeInsets {
2452 pub top: f32,
2453 pub leading: f32,
2454 pub bottom: f32,
2455 pub trailing: f32,
2456}
2457
2458impl EdgeInsets {
2459 pub fn all(value: f32) -> Self {
2461 Self {
2462 top: value,
2463 leading: value,
2464 bottom: value,
2465 trailing: value,
2466 }
2467 }
2468
2469 pub fn vertical(value: f32) -> Self {
2471 Self {
2472 top: value,
2473 leading: 0.0,
2474 bottom: value,
2475 trailing: 0.0,
2476 }
2477 }
2478
2479 pub fn horizontal(value: f32) -> Self {
2481 Self {
2482 top: 0.0,
2483 leading: value,
2484 bottom: 0.0,
2485 trailing: value,
2486 }
2487 }
2488}
2489
2490#[derive(Debug, Clone, Copy, PartialEq)]
2492pub struct FrameModifier {
2493 pub width: Option<f32>,
2494 pub height: Option<f32>,
2495}
2496
2497impl Default for FrameModifier {
2498 fn default() -> Self {
2499 Self::new()
2500 }
2501}
2502
2503impl FrameModifier {
2504 pub fn new() -> Self {
2505 Self {
2506 width: None,
2507 height: None,
2508 }
2509 }
2510
2511 pub fn width(mut self, width: f32) -> Self {
2512 self.width = Some(width);
2513 self
2514 }
2515
2516 pub fn height(mut self, height: f32) -> Self {
2517 self.height = Some(height);
2518 self
2519 }
2520
2521 pub fn size(mut self, width: f32, height: f32) -> Self {
2522 self.width = Some(width);
2523 self.height = Some(height);
2524 self
2525 }
2526}
2527
2528impl ViewModifier for FrameModifier {
2529 fn modify<V: View>(self, content: V) -> impl View {
2530 ModifiedView::new(content, self)
2531 }
2532}
2533
2534#[derive(Debug, Clone, Copy, PartialEq)]
2536pub struct FlexModifier {
2537 pub weight: f32,
2538}
2539
2540impl ViewModifier for FlexModifier {
2541 fn modify<V: View>(self, content: V) -> impl View {
2542 ModifiedView::new(content, self)
2543 }
2544
2545 fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
2546 self.weight
2547 }
2548}
2549
2550#[derive(Debug, Clone, Copy, PartialEq)]
2552pub struct OffsetModifier {
2553 pub x: f32,
2554 pub y: f32,
2555}
2556
2557impl OffsetModifier {
2558 pub fn new(x: f32, y: f32) -> Self {
2559 Self { x, y }
2560 }
2561}
2562
2563impl ViewModifier for OffsetModifier {
2564 fn modify<V: View>(self, content: V) -> impl View {
2565 ModifiedView::new(content, self)
2566 }
2567}
2568
2569#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2571pub struct ZIndexModifier {
2572 pub z_index: i32,
2573}
2574
2575impl ZIndexModifier {
2576 pub fn new(z_index: i32) -> Self {
2577 Self { z_index }
2578 }
2579}
2580
2581impl ViewModifier for ZIndexModifier {
2582 fn modify<V: View>(self, content: V) -> impl View {
2583 ModifiedView::new(content, self)
2584 }
2585}
2586
2587#[derive(Debug, Clone, Copy, PartialEq, Default)]
2589pub struct LayoutConstraints {
2590 pub min_width: Option<f32>,
2591 pub max_width: Option<f32>,
2592 pub min_height: Option<f32>,
2593 pub max_height: Option<f32>,
2594}
2595
2596#[derive(Debug, Clone, Copy, PartialEq)]
2598pub struct LayoutModifier {
2599 pub constraints: LayoutConstraints,
2600}
2601
2602impl LayoutModifier {
2603 pub fn new(constraints: LayoutConstraints) -> Self {
2604 Self { constraints }
2605 }
2606}
2607
2608impl ViewModifier for LayoutModifier {
2609 fn modify<V: View>(self, content: V) -> impl View {
2610 ModifiedView::new(content, self)
2611 }
2612}
2613
2614#[derive(Debug, Clone, Copy, PartialEq)]
2616pub struct SafeAreaModifier {
2617 pub ignores: bool,
2618}
2619
2620impl ViewModifier for SafeAreaModifier {
2621 fn modify<V: View>(self, content: V) -> impl View {
2622 ModifiedView::new(content, self)
2623 }
2624}
2625
2626#[derive(Debug, Clone, Copy, PartialEq)]
2628pub struct ElevationModifier {
2629 pub level: f32,
2630}
2631
2632impl ViewModifier for ElevationModifier {
2633 fn modify<V: View>(self, content: V) -> impl View {
2634 ModifiedView::new(content, self)
2635 }
2636
2637 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
2638 if self.level > 0.0 {
2639 let radius = self.level * 2.0;
2640 let offset_y = self.level * 0.5;
2641 let shadow_color = [0.0, 0.0, 0.0, 0.3];
2642 renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
2643 view.render(renderer, rect);
2644 renderer.pop_shadow();
2645 } else {
2646 view.render(renderer, rect);
2647 }
2648 }
2649}
2650
2651pub mod layout {
2653 use super::*;
2654
2655 pub struct LayoutCache {
2657 pub safe_area: SafeArea,
2658 size_cache: HashMap<(u64, u32, u32), Size>, }
2660
2661 impl Default for LayoutCache {
2662 fn default() -> Self {
2663 Self::new()
2664 }
2665 }
2666
2667 impl LayoutCache {
2668 pub fn new() -> Self {
2669 Self {
2670 safe_area: SafeArea::default(),
2671 size_cache: HashMap::new(),
2672 }
2673 }
2674
2675 pub fn clear(&mut self) {
2676 self.safe_area = SafeArea::default();
2677 self.size_cache.clear();
2678 }
2679
2680 pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
2681 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2682 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2683 self.size_cache.get(&(view_hash, pw, ph)).copied()
2684 }
2685
2686 pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: Size) {
2687 let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2688 let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2689 self.size_cache.insert((view_hash, pw, ph), size);
2690 }
2691
2692 pub fn invalidate_view(&mut self, view_hash: u64) {
2694 self.size_cache.retain(|&(hash, _, _), _| hash != view_hash);
2695 }
2696 }
2697
2698 #[derive(Debug, Clone, Copy, PartialEq)]
2700 pub struct SizeProposal {
2701 pub width: Option<f32>,
2702 pub height: Option<f32>,
2703 }
2704
2705 impl SizeProposal {
2706 pub fn unspecified() -> Self {
2707 Self {
2708 width: None,
2709 height: None,
2710 }
2711 }
2712
2713 pub fn width(width: f32) -> Self {
2714 Self {
2715 width: Some(width),
2716 height: None,
2717 }
2718 }
2719
2720 pub fn height(height: f32) -> Self {
2721 Self {
2722 width: None,
2723 height: Some(height),
2724 }
2725 }
2726
2727 pub fn tight(width: f32, height: f32) -> Self {
2728 Self {
2729 width: Some(width),
2730 height: Some(height),
2731 }
2732 }
2733
2734 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
2735 Self { width, height }
2736 }
2737 }
2738
2739 pub trait LayoutView: Send {
2741 fn size_that_fits(
2743 &self,
2744 proposal: SizeProposal,
2745 subviews: &[&dyn LayoutView],
2746 cache: &mut LayoutCache,
2747 ) -> Size;
2748
2749 fn place_subviews(
2751 &self,
2752 bounds: Rect,
2753 subviews: &mut [&mut dyn LayoutView],
2754 cache: &mut LayoutCache,
2755 );
2756
2757 fn flex_weight(&self) -> f32 {
2759 0.0
2760 }
2761 }
2762 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2764 pub struct EdgeInsets {
2765 pub top: f32,
2766 pub leading: f32,
2767 pub bottom: f32,
2768 pub trailing: f32,
2769 }
2770
2771 impl EdgeInsets {
2772 pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
2773 Self { top, leading, bottom, trailing }
2774 }
2775
2776 pub fn all(value: f32) -> Self {
2777 Self {
2778 top: value,
2779 leading: value,
2780 bottom: value,
2781 trailing: value,
2782 }
2783 }
2784 }
2785
2786 #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2788 pub struct SafeArea {
2789 pub insets: EdgeInsets,
2790 }
2791
2792 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2794 pub struct Rect {
2795 pub x: f32,
2796 pub y: f32,
2797 pub width: f32,
2798 pub height: f32,
2799 }
2800
2801 impl Rect {
2802 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
2803 Self {
2804 x,
2805 y,
2806 width,
2807 height,
2808 }
2809 }
2810
2811 pub fn zero() -> Self {
2812 Self {
2813 x: 0.0,
2814 y: 0.0,
2815 width: 0.0,
2816 height: 0.0,
2817 }
2818 }
2819
2820 pub fn size(&self) -> Size {
2821 Size {
2822 width: self.width,
2823 height: self.height,
2824 }
2825 }
2826
2827 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
2829 if n == 0 {
2830 return vec![];
2831 }
2832 let item_width = self.width / n as f32;
2833 (0..n)
2834 .map(|i| Rect {
2835 x: self.x + i as f32 * item_width,
2836 y: self.y,
2837 width: item_width,
2838 height: self.height,
2839 })
2840 .collect()
2841 }
2842
2843 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
2845 if n == 0 {
2846 return vec![];
2847 }
2848 let item_height = self.height / n as f32;
2849 (0..n)
2850 .map(|i| Rect {
2851 x: self.x,
2852 y: self.y + i as f32 * item_height,
2853 width: self.width,
2854 height: item_height,
2855 })
2856 .collect()
2857 }
2858 }
2859}
2860
2861pub use layout::{LayoutCache, LayoutView, Rect, SizeProposal};
2863pub mod runtime;
2866pub mod scene_graph;
2867pub mod agents;
2868pub mod material;
2869
2870
2871pub use scene_graph::{NodeId, bifrost_registry};
2872
2873pub trait AssetManager: Send + Sync {
2877 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
2879
2880 fn preload_image(&self, url: &str);
2882}
2883
2884#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2886pub enum Event {
2887 PointerDown { x: f32, y: f32 },
2888 PointerUp { x: f32, y: f32 },
2889 PointerMove { x: f32, y: f32 },
2890 PointerClick { x: f32, y: f32 },
2891 PointerEnter,
2892 PointerLeave,
2893 KeyDown { key: String },
2894 KeyUp { key: String },
2895 Ime(String),
2897}
2898
2899impl Event {
2900 pub fn name(&self) -> &'static str {
2902 match self {
2903 Self::PointerDown { .. } => "pointerdown",
2904 Self::PointerUp { .. } => "pointerup",
2905 Self::PointerMove { .. } => "pointermove",
2906 Self::PointerClick { .. } => "pointerclick",
2907 Self::PointerEnter => "pointerenter",
2908 Self::PointerLeave => "pointerleave",
2909 Self::KeyDown { .. } => "keydown",
2910 Self::KeyUp { .. } => "keyup",
2911 Self::Ime(_) => "ime",
2912 }
2913 }
2914}
2915
2916#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2918pub enum EventResponse {
2919 Handled,
2920 Ignored,
2921}
2922
2923pub struct DefaultAssetManager {
2925 cache: Arc<arc_swap::ArcSwap<HashMap<String, AssetState<Arc<Vec<u8>>>>>>,
2926}
2927
2928impl Default for DefaultAssetManager {
2929 fn default() -> Self {
2930 Self::new()
2931 }
2932}
2933
2934impl DefaultAssetManager {
2935 pub fn new() -> Self {
2936 Self {
2937 cache: Arc::new(arc_swap::ArcSwap::from_pointee(HashMap::new())),
2938 }
2939 }
2940}
2941
2942impl AssetManager for DefaultAssetManager {
2943 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
2944 if let Some(state) = self.cache.load().get(url) {
2945 return state.clone();
2946 }
2947
2948 self.cache.rcu(|map| {
2949 let mut m = (**map).clone();
2950 m.entry(url.to_string()).or_insert(AssetState::Loading);
2951 m
2952 });
2953 AssetState::Loading
2954 }
2955
2956 fn preload_image(&self, _url: &str) {}
2957}
2958
2959use std::future::Future;
2960
2961pub struct Suspense<T: Clone + Send + Sync + 'static> {
2964 inner: State<AssetState<T>>,
2965}
2966
2967impl<T: Clone + Send + Sync + 'static> Default for Suspense<T> {
2968 fn default() -> Self {
2969 Self::new()
2970 }
2971}
2972
2973impl<T: Clone + Send + Sync + 'static> Suspense<T> {
2974 pub fn new() -> Self {
2975 Self {
2976 inner: State::new(AssetState::Loading),
2977 }
2978 }
2979
2980 pub fn new_async<F>(_future: F) -> Self
2981 where
2982 F: Future<Output = Result<T, String>> + Send + 'static,
2983 {
2984 let suspense = Self::new();
2985 let _suspense_clone = suspense.clone();
2986
2987 #[cfg(not(target_arch = "wasm32"))]
2988 {
2989 std::thread::spawn(move || {
2990 let _rt = std::sync::Arc::new(std::sync::Mutex::new(_future));
2994 });
2996 }
2997 #[cfg(target_arch = "wasm32")]
2998 {
2999 }
3002
3003 suspense
3004 }
3005
3006 pub fn ready(value: T) -> Self {
3007 Self {
3008 inner: State::new(AssetState::Ready(value)),
3009 }
3010 }
3011
3012 pub fn error(message: impl Into<String>) -> Self {
3013 Self {
3014 inner: State::new(AssetState::Error(message.into())),
3015 }
3016 }
3017
3018 pub fn get(&self) -> AssetState<T> {
3019 self.inner.get()
3020 }
3021
3022 pub fn get_ref(&self) -> AssetState<T> {
3023 self.inner.get()
3024 }
3025
3026 pub fn is_loading(&self) -> bool {
3027 matches!(self.get(), AssetState::Loading)
3028 }
3029
3030 pub fn is_ready(&self) -> bool {
3031 matches!(self.get(), AssetState::Ready(_))
3032 }
3033
3034 pub fn is_error(&self) -> bool {
3035 matches!(self.get(), AssetState::Error(_))
3036 }
3037
3038 pub fn ready_value(&self) -> Option<T> {
3039 match self.get() {
3040 AssetState::Ready(value) => Some(value),
3041 _ => None,
3042 }
3043 }
3044
3045 pub fn error_message(&self) -> Option<String> {
3046 match self.get() {
3047 AssetState::Error(message) => Some(message),
3048 _ => None,
3049 }
3050 }
3051
3052 pub fn subscribe<F: Fn(&AssetState<T>) + Send + Sync + 'static>(&self, callback: F) {
3053 self.inner.subscribe(callback)
3054 }
3055
3056 pub fn inner_state(&self) -> &State<AssetState<T>> {
3057 &self.inner
3058 }
3059}
3060
3061impl<T: Clone + Send + Sync + 'static> Clone for Suspense<T> {
3062 fn clone(&self) -> Self {
3063 Self {
3064 inner: self.inner.clone(),
3065 }
3066 }
3067}
3068
3069impl<T: Clone + Send + Sync + 'static> From<T> for Suspense<T> {
3070 fn from(value: T) -> Self {
3071 Self::ready(value)
3072 }
3073}
3074
3075impl<T: Clone + Send + Sync + 'static> From<Result<T, String>> for Suspense<T> {
3076 fn from(result: Result<T, String>) -> Self {
3077 match result {
3078 Ok(value) => Self::ready(value),
3079 Err(error) => Self::error(error),
3080 }
3081 }
3082}
3083
3084#[cfg(test)]
3085mod phase1_test;