1use serde::{Deserialize, Serialize};
35use std::collections::HashMap;
36use std::str::FromStr;
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40#[serde(untagged)]
41pub enum TokenValue {
42 Single {
44 value: String,
45 },
46 Adaptive {
48 light: String,
49 dark: String,
50 },
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct YggdrasilTokens {
56 pub color: HashMap<String, TokenValue>,
57 pub font: HashMap<String, TokenValue>,
58 pub spacing: HashMap<String, TokenValue>,
59 pub radius: HashMap<String, TokenValue>,
60 pub shadow: HashMap<String, TokenValue>,
61 pub border: HashMap<String, TokenValue>,
62 pub anim: HashMap<String, TokenValue>,
63 pub bifrost: HashMap<String, TokenValue>,
64 pub gungnir: HashMap<String, TokenValue>,
65 pub mjolnir: HashMap<String, TokenValue>,
66 pub accessibility: HashMap<String, TokenValue>,
67}
68
69impl YggdrasilTokens {
70 pub fn new() -> Self {
71 Self {
72 color: HashMap::new(),
73 font: HashMap::new(),
74 spacing: HashMap::new(),
75 radius: HashMap::new(),
76 shadow: HashMap::new(),
77 border: HashMap::new(),
78 anim: HashMap::new(),
79 bifrost: HashMap::new(),
80 gungnir: HashMap::new(),
81 mjolnir: HashMap::new(),
82 accessibility: HashMap::new(),
83 }
84 }
85
86 pub fn get_color(&self, key: &str, is_dark: bool) -> Option<String> {
88 self.color.get(key).and_then(|token| {
89 match token {
90 TokenValue::Single { value } => Some(value.clone()),
91 TokenValue::Adaptive { light, dark } => {
92 if is_dark { Some(dark.clone()) } else { Some(light.clone()) }
93 }
94 }
95 })
96 }
97
98 pub fn get<T: FromStr>(&self, category: &str, key: &str, is_dark: bool) -> Option<T> {
100 let map = match category {
101 "color" => &self.color,
102 "font" => &self.font,
103 "spacing" => &self.spacing,
104 "radius" => &self.radius,
105 "shadow" => &self.shadow,
106 "border" => &self.border,
107 "anim" => &self.anim,
108 "bifrost" => &self.bifrost,
109 "gungnir" => &self.gungnir,
110 "mjolnir" => &self.mjolnir,
111 "accessibility" => &self.accessibility,
112 _ => return None,
113 };
114
115 map.get(key).and_then(|token| {
116 match token {
117 TokenValue::Single { value } => value.parse().ok(),
118 TokenValue::Adaptive { light, dark } => {
119 let value = if is_dark { dark } else { light };
120 value.parse().ok()
121 }
122 }
123 })
124 }
125}
126
127pub trait View: Sized + Send {
128 type Body: View;
131
132 fn body(self) -> Self::Body;
133
134 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
137
138 fn layout(&self) -> Option<&dyn layout::LayoutView> {
140 None
141 }
142
143 fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
145 ModifiedView::new(self, m)
146 }
147
148 fn bifrost(self, blur: f32, saturation: f32, opacity: f32) -> ModifiedView<Self, BifrostModifier> {
150 self.modifier(BifrostModifier { blur, saturation, opacity })
151 }
152
153 fn gungnir(self, color: impl Into<String>, radius: f32, intensity: f32) -> ModifiedView<Self, GungnirModifier> {
155 self.modifier(GungnirModifier { color: color.into(), radius, intensity })
156 }
157
158 fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
160 self.modifier(MjolnirSliceModifier { angle, offset })
161 }
162
163 fn mjolnir_shatter(self, pieces: u32, force: f32) -> ModifiedView<Self, MjolnirShatterModifier> {
165 self.modifier(MjolnirShatterModifier { pieces, force })
166 }
167
168 fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
170 self.modifier(BifrostBridgeModifier { id: id.into() })
171 }
172
173 fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
175 self.modifier(BackgroundModifier { color })
176 }
177
178 fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
180 self.modifier(PaddingModifier { amount })
181 }
182
183 fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
185 self.modifier(OpacityModifier { opacity: opacity.clamp(0.0, 1.0) })
186 }
187
188 fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
190 self.modifier(ForegroundColorModifier { color })
191 }
192
193 fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
195 self.modifier(FrameModifier { width, height })
196 }
197
198 fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
200 self.modifier(ClipModifier)
201 }
202
203 fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
205 self.modifier(BorderModifier { color, width })
206 }
207
208 fn on_appear<F: Fn() + Send + Sync + 'static>(self, action: F) -> ModifiedView<Self, LifecycleModifier> {
210 self.modifier(LifecycleModifier {
211 on_appear: Some(Arc::new(action)),
212 on_disappear: None,
213 })
214 }
215
216 fn on_disappear<F: Fn() + Send + Sync + 'static>(self, action: F) -> ModifiedView<Self, LifecycleModifier> {
218 self.modifier(LifecycleModifier {
219 on_appear: None,
220 on_disappear: Some(Arc::new(action)),
221 })
222 }
223
224 fn erase(self) -> AnyView where Self: 'static {
226 AnyView::new(self)
227 }
228}
229
230pub trait ErasedView: Send {
232 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect);
233 fn name(&self) -> &'static str;
234}
235
236impl<V: View + 'static> ErasedView for V {
237 fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
238 self.render(renderer, rect);
239 }
240
241 fn name(&self) -> &'static str {
242 std::any::type_name::<V>()
243 }
244}
245
246pub struct AnyView {
248 inner: Box<dyn ErasedView>,
249}
250
251impl AnyView {
252 pub fn new<V: View + 'static>(view: V) -> Self {
253 Self { inner: Box::new(view) }
254 }
255}
256
257impl View for AnyView {
258 type Body = Never;
259 fn body(self) -> Self::Body { unreachable!() }
260
261 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
262 renderer.push_vnode(rect, self.inner.name());
263 self.inner.render_erased(renderer, rect);
264 renderer.pop_vnode();
265 }
266}
267
268#[derive(Debug, Clone, PartialEq)]
272pub struct BifrostBridgeModifier {
273 pub id: String,
274}
275
276impl ViewModifier for BifrostBridgeModifier {
277 fn modify<V: View>(self, content: V) -> impl View {
278 ModifiedView::new(content, self)
279 }
280
281 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
282 renderer.register_shared_element(&self.id, rect);
284 }
285}
286
287#[derive(Debug, Clone, Copy, PartialEq)]
290pub struct MjolnirSliceModifier {
291 pub angle: f32,
292 pub offset: f32,
293}
294
295impl ViewModifier for MjolnirSliceModifier {
296 fn modify<V: View>(self, content: V) -> impl View {
297 ModifiedView::new(content, self)
298 }
299
300 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
301 renderer.push_mjolnir_slice(self.angle, self.offset);
302 }
303
304 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
305 renderer.pop_mjolnir_slice();
306 }
307}
308
309#[derive(Debug, Clone, Copy, PartialEq)]
312pub struct MjolnirShatterModifier {
313 pub pieces: u32,
314 pub force: f32,
315}
316
317impl ViewModifier for MjolnirShatterModifier {
318 fn modify<V: View>(self, content: V) -> impl View {
319 ModifiedView::new(content, self)
320 }
321
322 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
323 let pieces = self.pieces.max(1);
325 for i in 0..pieces {
326 let progress = i as f32 / pieces as f32;
327 let next_progress = (i + 1) as f32 / pieces as f32;
328
329 let angle_start = progress * 360.0;
330 let angle_end = next_progress * 360.0;
331
332 renderer.push_mjolnir_slice(angle_start, 0.0);
334 renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
335
336 let mid_angle = (angle_start + angle_end) / 2.0;
338 let rad = mid_angle.to_radians();
339 let dx = rad.cos() * self.force;
340 let dy = rad.sin() * self.force;
341
342 let shard_rect = Rect {
343 x: rect.x + dx,
344 y: rect.y + dy,
345 ..rect
346 };
347
348 view.render(renderer, shard_rect);
349
350 renderer.pop_mjolnir_slice();
351 renderer.pop_mjolnir_slice();
352 }
353 }
354}
355
356#[derive(Debug, Clone, Copy, PartialEq)]
359pub struct BifrostModifier {
360 pub blur: f32,
361 pub saturation: f32,
362 pub opacity: f32,
363}
364
365impl ViewModifier for BifrostModifier {
366 fn modify<V: View>(self, content: V) -> impl View {
367 ModifiedView::new(content, self)
368 }
369
370 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
371 renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
372 }
373}
374
375#[derive(Debug, Clone, Copy, PartialEq)]
377pub struct BackgroundModifier {
378 pub color: [f32; 4],
379}
380
381impl ViewModifier for BackgroundModifier {
382 fn modify<V: View>(self, content: V) -> impl View {
383 ModifiedView::new(content, self)
384 }
385
386 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
387 renderer.fill_rect(rect, self.color);
388 }
389}
390
391#[derive(Debug, Clone, Copy, PartialEq)]
393pub struct PaddingModifier {
394 pub amount: f32,
395}
396
397impl ViewModifier for PaddingModifier {
398 fn modify<V: View>(self, content: V) -> impl View {
399 ModifiedView::new(content, self)
400 }
401
402 fn transform_rect(&self, rect: Rect) -> Rect {
403 Rect {
404 x: rect.x + self.amount,
405 y: rect.y + self.amount,
406 width: (rect.width - 2.0 * self.amount).max(0.0),
407 height: (rect.height - 2.0 * self.amount).max(0.0),
408 }
409 }
410}
411
412#[derive(Debug, Clone, PartialEq)]
415pub struct GungnirModifier {
416 pub color: String,
417 pub radius: f32,
418 pub intensity: f32,
419}
420
421impl ViewModifier for GungnirModifier {
422 fn modify<V: View>(self, content: V) -> impl View {
423 ModifiedView::new(content, self)
424 }
425
426 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
427 renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
429 }
430}
431
432#[derive(Debug, Clone, Copy, PartialEq)]
434pub struct GungnirPulseModifier {
435 pub color: [f32; 4],
436 pub radius: f32,
437 pub speed: f32,
438}
439
440impl ViewModifier for GungnirPulseModifier {
441 fn modify<V: View>(self, content: V) -> impl View {
442 ModifiedView::new(content, self)
443 }
444
445 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
446 let time = std::time::SystemTime::now()
447 .duration_since(std::time::UNIX_EPOCH)
448 .unwrap_or_default()
449 .as_secs_f32();
450
451 let intensity = (time * self.speed).sin() * 0.5 + 0.5;
454 let mut color = self.color;
455 color[3] *= intensity;
456
457 renderer.stroke_rect(rect, color, self.radius);
459 }
460}
461
462#[derive(Debug, Clone, PartialEq)]
464pub struct SleipnirModifier<T> {
465 pub target: T,
466 pub stiffness: f32,
467 pub damping: f32,
468}
469
470impl<T: Send + Sync + 'static + Clone> ViewModifier for SleipnirModifier<T> {
471 fn modify<V: View>(self, content: V) -> impl View {
472 ModifiedView::new(content, self)
473 }
474}
475
476#[derive(Clone)]
478pub struct LifecycleModifier {
479 pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
480 pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
481}
482
483impl ViewModifier for LifecycleModifier {
484 fn modify<V: View>(self, content: V) -> impl View {
485 ModifiedView::new(content, self)
486 }
487}
488
489#[derive(Debug, Clone, Copy, PartialEq)]
492pub struct OpacityModifier {
493 pub opacity: f32,
494}
495
496impl ViewModifier for OpacityModifier {
497 fn modify<V: View>(self, content: V) -> impl View {
498 ModifiedView::new(content, self)
499 }
500
501 fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
502 renderer.push_opacity(self.opacity);
503 }
504
505 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
506 renderer.pop_opacity();
507 }
508}
509
510#[derive(Debug, Clone, Copy, PartialEq)]
513pub struct ForegroundColorModifier {
514 pub color: [f32; 4],
515}
516
517impl ViewModifier for ForegroundColorModifier {
518 fn modify<V: View>(self, content: V) -> impl View {
519 ModifiedView::new(content, self)
520 }
521}
522
523#[derive(Debug, Clone, Copy, PartialEq, Eq)]
526pub struct ClipModifier;
527
528impl ViewModifier for ClipModifier {
529 fn modify<V: View>(self, content: V) -> impl View {
530 ModifiedView::new(content, self)
531 }
532
533 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
534 renderer.push_clip_rect(rect);
535 }
536
537 fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
538 renderer.pop_clip_rect();
539 }
540}
541
542#[derive(Debug, Clone, Copy, PartialEq)]
544pub struct BorderModifier {
545 pub color: [f32; 4],
546 pub width: f32,
547}
548
549impl ViewModifier for BorderModifier {
550 fn modify<V: View>(self, content: V) -> impl View {
551 ModifiedView::new(content, self)
552 }
553
554 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
555 renderer.stroke_rect(rect, self.color, self.width);
556 }
557}
558
559#[doc(hidden)]
561pub enum Never {}
562
563impl View for Never {
564 type Body = Never;
565 fn body(self) -> Never {
566 unreachable!()
567 }
568}
569
570pub struct ModifiedView<V, M> {
574 view: V,
575 modifier: M,
576}
577
578 impl<V: View, M: ViewModifier> ModifiedView<V, M> {
579 #[doc(hidden)]
580 pub fn new(view: V, modifier: M) -> Self {
581 Self { view, modifier }
582 }
583 }
584
585 impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
586 type Body = ModifiedView<V::Body, M>;
587
588 fn body(self) -> Self::Body {
589 ModifiedView {
590 view: self.view.body(),
591 modifier: self.modifier.clone(),
592 }
593 }
594
595 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
596 self.modifier.render_view(&self.view, renderer, rect);
597 }
598 }
599
600
601 pub trait ViewModifier: Send + Clone {
602 fn modify<V: View>(self, content: V) -> impl View;
603
604 fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
606
607 fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
609
610 fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
613 self.render(renderer, rect);
614 let child_rect = self.transform_rect(rect);
615 view.render(renderer, child_rect);
616 self.post_render(renderer, rect);
617 }
618
619 fn transform_rect(&self, rect: Rect) -> Rect { rect }
620 }
621
622 pub trait Renderer: Send {
630 fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
632 fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
633 fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
635
636 fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
638 fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
639 fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
641 fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
643
644 fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
646 fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
648
649 fn draw_texture(&mut self, texture_id: u32, rect: Rect);
652 fn draw_image(&mut self, image_name: &str, rect: Rect);
654 fn load_image(&mut self, name: &str, data: &[u8]);
656
657 fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
660 fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
662
663 fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
666
667 fn draw_linear_gradient(&mut self, _rect: Rect, _start_color: [f32; 4], _end_color: [f32; 4], _angle: f32) {}
670 fn draw_radial_gradient(&mut self, _rect: Rect, _inner_color: [f32; 4], _outer_color: [f32; 4]) {}
672 fn draw_drop_shadow(&mut self, _rect: Rect, _radius: f32, _color: [f32; 4], _blur: f32, _spread: f32) {}
674 fn stroke_dashed_rounded_rect(&mut self, _rect: Rect, _radius: f32, _color: [f32; 4], _width: f32, _dash: f32, _gap: f32) {}
676 fn draw_9slice(&mut self, _image_name: &str, _rect: Rect, _left: f32, _top: f32, _right: f32, _bottom: f32) {}
678
679 fn push_clip_rect(&mut self, rect: Rect);
683 fn pop_clip_rect(&mut self);
685
686 fn push_opacity(&mut self, opacity: f32);
690 fn pop_opacity(&mut self);
692
693 fn set_theme(&mut self, _theme: ColorTheme) {}
695 fn set_rage(&mut self, _rage: f32) {}
696 fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
697
698 fn bifrost(&mut self, rect: Rect, blur: f32, saturation: f32, opacity: f32);
701 fn push_mjolnir_slice(&mut self, angle: f32, offset: f32);
703 fn pop_mjolnir_slice(&mut self);
705 fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
707 fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
708 fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
710
711 fn set_aria_role(&mut self, _role: &str) {}
713 fn set_aria_label(&mut self, _label: &str) {}
714
715 fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
717
718 fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
721 fn pop_vnode(&mut self) {}
723 fn register_handler(&mut self, _event_type: &str, _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>) {}
725 }
726
727 use bytemuck::{Pod, Zeroable};
732
733 #[repr(C)]
735 #[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
736 pub struct ColorTheme {
737 pub primary_neon: [f32; 4], pub shatter_neon: [f32; 4],
739 pub glass_base: [f32; 4],
740 pub glass_edge: [f32; 4],
741 pub rune_glow: [f32; 4],
742 pub ember_core: [f32; 4],
743 pub background_deep: [f32; 4],
744 pub glass_blur_strength: f32,
745 pub shatter_edge_width: f32,
746 pub neon_bloom_radius: f32,
747 pub rune_opacity: f32, pub _pad: [f32; 3], pub _pad2: f32,
751 }
752
753 impl ColorTheme {
754 pub fn cyberpunk_viking() -> Self {
755 Self {
756 primary_neon: [0.0, 1.0, 0.95, 1.2],
757 shatter_neon: [1.0, 0.0, 0.75, 1.5],
758 glass_base: [0.04, 0.04, 0.06, 0.82],
759 glass_edge: [0.0, 0.45, 0.55, 0.6],
760 rune_glow: [0.75, 0.98, 1.0, 0.9],
761 ember_core: [0.95, 0.12, 0.12, 1.0],
762 background_deep: [0.01, 0.01, 0.03, 1.0],
763 glass_blur_strength: 0.6,
764 shatter_edge_width: 1.8,
765 neon_bloom_radius: 0.022,
766 rune_opacity: 0.55,
767 _pad: [0.0; 3],
768 _pad2: 0.0,
769 }
770 }
771
772 pub fn vibrant_glass() -> Self {
773 Self {
774 primary_neon: [0.0, 1.0, 0.95, 1.2],
775 shatter_neon: [1.0, 0.0, 0.75, 1.5],
776 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],
779 ember_core: [1.0, 0.4, 0.1, 1.0],
780 background_deep: [0.05, 0.05, 0.1, 1.0],
781 glass_blur_strength: 0.9,
782 shatter_edge_width: 1.8,
783 neon_bloom_radius: 0.022,
784 rune_opacity: 0.55,
785 _pad: [0.0; 3],
786 _pad2: 0.0,
787 }
788 }
789 }
790
791 impl Default for ColorTheme {
792 fn default() -> Self {
793 Self::vibrant_glass()
794 }
795 }
796
797 #[repr(C)]
799 #[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
800 pub struct SceneUniforms {
801 pub view: glam::Mat4,
802 pub proj: glam::Mat4,
803 pub time: f32,
804 pub delta_time: f32,
805 pub resolution: [f32; 2],
806 pub mouse: [f32; 2],
807 pub mouse_velocity: [f32; 2],
808 pub shatter_origin: [f32; 2],
809 pub shatter_time: f32,
810 pub shatter_force: f32,
811 pub berzerker_rage: f32,
812 pub scroll_offset: f32,
813 pub _pad: [f32; 2],
815 }
816
817 impl SceneUniforms {
818 pub fn new(width: f32, height: f32) -> Self {
819 Self {
820 view: glam::Mat4::IDENTITY,
821 proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
822 time: 0.0,
823 delta_time: 0.016,
824 resolution: [width, height],
825 mouse: [0.5, 0.5],
826 mouse_velocity: [0.0, 0.0],
827 shatter_origin: [0.5, 0.5],
828 shatter_time: -100.0,
829 shatter_force: 0.0,
830 berzerker_rage: 0.0,
831 scroll_offset: 0.0,
832 _pad: [0.0; 2],
833 }
834 }
835 }
836
837 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
839 pub struct Mesh {
840 pub vertices: Vec<[f32; 3]>,
841 pub normals: Vec<[f32; 3]>,
842 pub indices: Vec<u32>,
843 }
844
845 impl Mesh {
846 pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
847 let mut cursor = std::io::Cursor::new(data);
848 let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
849 Ok((Vec::new(), Default::default()))
850 })?;
851
852 let mut meshes = Vec::new();
853 for m in models {
854 let mesh = m.mesh;
855 let vertices: Vec<[f32; 3]> = mesh.positions.chunks(3).map(|c| [c[0], c[1], c[2]]).collect();
856 let normals = if mesh.normals.is_empty() {
857 vec![[0.0, 0.0, 1.0]; vertices.len()]
858 } else {
859 mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
860 };
861 meshes.push(Mesh { vertices, normals, indices: mesh.indices });
862 }
863 Ok(meshes)
864 }
865
866 pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
867 let mut cursor = std::io::Cursor::new(data);
868 let stl = stl_io::read_stl(&mut cursor)?;
869
870 let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
871 let mut indices = Vec::new();
872 for face in stl.faces {
873 indices.push(face.vertices[0] as u32);
874 indices.push(face.vertices[1] as u32);
875 indices.push(face.vertices[2] as u32);
876 }
877
878 let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
879
880 Ok(Mesh { vertices, normals, indices })
881 }
882 }
883
884 pub trait FrameRenderer<E = ()>: Renderer {
887 fn begin_frame(&mut self) -> E;
888 fn end_frame(&mut self, encoder: E);
889 }
890
891
892
893use std::sync::Arc;
894
895#[derive(Clone)]
897pub struct State<T: Clone + Send + Sync + 'static> {
898 value: Arc<std::sync::RwLock<T>>,
899 subscribers: Arc<std::sync::RwLock<Vec<Box<dyn FnMut(&T) + Send + Sync>>>>,
900}
901
902impl<T: Clone + Send + Sync + 'static> State<T> {
903 pub fn new(value: T) -> Self {
905 Self {
906 value: Arc::new(std::sync::RwLock::new(value)),
907 subscribers: Arc::new(std::sync::RwLock::new(Vec::new())),
908 }
909 }
910
911 pub fn get(&self) -> T {
913 self.value.read().unwrap().clone()
914 }
915
916 pub fn set(&self, value: T) {
918 *self.value.write().unwrap() = value;
919 let mut subscribers = self.subscribers.write().unwrap();
921 for subscriber in subscribers.iter_mut() {
922 subscriber(&self.get());
923 }
924 }
925
926 pub fn subscribe<F: FnMut(&T) + Send + Sync + 'static>(&self, callback: F) {
928 self.subscribers.write().unwrap().push(Box::new(callback));
929 }
930}
931
932#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
936pub struct ComponentErrorState {
937 pub has_error: bool,
938 pub error_message: Option<String>,
939 pub error_location: Option<String>,
940}
941
942impl ComponentErrorState {
943 pub fn clear() -> Self {
945 Self::default()
946 }
947
948 pub fn error(message: impl Into<String>, location: impl Into<String>) -> Self {
950 Self {
951 has_error: true,
952 error_message: Some(message.into()),
953 error_location: Some(location.into()),
954 }
955 }
956}
957
958#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
960pub struct KnowledgeFragment {
961 pub id: String,
963 pub summary: String,
965 pub source: String,
967 pub created_at: u64,
969 pub accessed_count: u32,
971 pub content: Option<String>,
973}
974
975#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
978pub struct KnowledgeState {
979 #[serde(skip)]
981 pub component_states: std::collections::HashMap<u64, Arc<dyn std::any::Any + Send + Sync>>,
982
983 pub fragments: HashMap<String, KnowledgeFragment>,
985
986 pub last_query_results: Vec<String>,
988}
989
990use std::sync::OnceLock;
991use crate::runtime::NodeStateSnapshot;
992
993pub static SYSTEM_STATE: OnceLock<Arc<std::sync::RwLock<KnowledgeState>>> = OnceLock::new();
995
996pub fn get_system_state() -> Arc<std::sync::RwLock<KnowledgeState>> {
998 SYSTEM_STATE.get_or_init(|| Arc::new(std::sync::RwLock::new(KnowledgeState::default()))).clone()
999}
1000
1001impl KnowledgeState {
1002 pub fn new() -> Self {
1004 Self::default()
1005 }
1006
1007 pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
1009 self.component_states.insert(id, Arc::new(std::sync::RwLock::new(state)));
1010 }
1011
1012 pub fn get_component_state<T: 'static + Send + Sync>(&self, id: u64) -> Option<Arc<std::sync::RwLock<T>>> {
1014 let lock = self.component_states.get(&id)?;
1015 lock.clone().downcast::<std::sync::RwLock<T>>().ok()
1016 }
1017
1018 pub fn remember(&mut self, fragment: KnowledgeFragment) {
1020 self.fragments.insert(fragment.id.clone(), fragment);
1021 }
1022
1023 pub fn process_query(&mut self, query: &str) {
1025 let query_lower = query.to_lowercase();
1026 let mut results: Vec<(f32, String)> = self.fragments
1027 .iter()
1028 .map(|(id, frag)| {
1029 let mut score = 0.0;
1030 if frag.summary.to_lowercase().contains(&query_lower) { score += 1.0; }
1031 if frag.source.to_lowercase().contains(&query_lower) { score += 0.5; }
1032 (score, id.clone())
1033 })
1034 .filter(|(score, _)| *score > 0.0)
1035 .collect();
1036
1037 results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
1039
1040 self.last_query_results = results.into_iter()
1041 .map(|(_, id)| id)
1042 .take(5)
1043 .collect();
1044 }
1045
1046 pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
1048 let mut snapshots = Vec::new();
1049
1050 for (_id, frag) in &self.fragments {
1052 if let Ok(val) = serde_json::to_value(frag) {
1053 snapshots.push(NodeStateSnapshot {
1054 id: 0,
1055 state: val,
1056 });
1057 }
1058 }
1059
1060 snapshots
1061 }
1062}
1063
1064#[derive(Clone)]
1066pub struct Binding<T: Clone + Send + Sync + 'static> {
1067 state: Arc<std::sync::RwLock<T>>,
1068}
1069
1070impl<T: Clone + Send + Sync + 'static> Binding<T> {
1071 pub fn from_state(state: &State<T>) -> Self {
1073 Self {
1074 state: state.value.clone(),
1075 }
1076 }
1077
1078 pub fn get(&self) -> T {
1080 self.state.read().unwrap().clone()
1081 }
1082
1083 pub fn set(&self, value: T) {
1085 *self.state.write().unwrap() = value;
1086 }
1087}
1088
1089use std::any::TypeId;
1090use std::sync::Mutex;
1091
1092pub(crate) static ENVIRONMENT: OnceLock<Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>> = OnceLock::new();
1094
1095pub trait EnvKey: 'static + Send + Sync {
1099 type Value: Clone + Send + Sync + 'static;
1101
1102 fn default_value() -> Self::Value;
1104}
1105
1106pub struct YggdrasilKey;
1108
1109impl EnvKey for YggdrasilKey {
1110 type Value = YggdrasilTokens;
1111 fn default_value() -> Self::Value {
1112 default_tokens()
1113 }
1114}
1115
1116pub struct AssetKey;
1118
1119impl EnvKey for AssetKey {
1120 type Value = Arc<dyn AssetManager>;
1121 fn default_value() -> Self::Value {
1122 Arc::new(DefaultAssetManager::new())
1123 }
1124}
1125
1126#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1128pub enum Appearance {
1129 Light,
1130 Dark,
1131}
1132
1133#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1135pub enum Orientation {
1136 Horizontal,
1137 Vertical,
1138}
1139
1140#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
1142pub struct Color {
1143 pub r: f32,
1144 pub g: f32,
1145 pub b: f32,
1146 pub a: f32,
1147}
1148
1149impl Color {
1150 pub const BLACK: Color = Color { r: 0.0, g: 0.0, b: 0.0, a: 1.0 };
1151 pub const WHITE: Color = Color { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
1152 pub const TRANSPARENT: Color = Color { r: 0.0, g: 0.0, b: 0.0, a: 0.0 };
1153 pub const RED: Color = Color { r: 1.0, g: 0.0, b: 0.0, a: 1.0 };
1154 pub const GREEN: Color = Color { r: 0.0, g: 1.0, b: 0.0, a: 1.0 };
1155 pub const BLUE: Color = Color { r: 0.0, g: 0.0, b: 1.0, a: 1.0 };
1156 pub const CYAN: Color = Color { r: 0.0, g: 1.0, b: 1.0, a: 1.0 };
1157 pub const YELLOW: Color = Color { r: 1.0, g: 1.0, b: 0.0, a: 1.0 };
1158 pub const MAGENTA: Color = Color { r: 1.0, g: 0.0, b: 1.0, a: 1.0 };
1159 pub const GRAY: Color = Color { r: 0.5, g: 0.5, b: 0.5, a: 1.0 };
1160
1161 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
1163 Self { r, g, b, a }
1164 }
1165
1166 pub fn as_array(&self) -> [f32; 4] {
1168 [self.r, self.g, self.b, self.a]
1169 }
1170}
1171
1172impl View for Color {
1173 type Body = Never;
1174 fn body(self) -> Self::Body { unreachable!() }
1175
1176 fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1177 renderer.fill_rect(rect, self.as_array());
1178 }
1179}
1180
1181pub struct AppearanceKey;
1183
1184impl EnvKey for AppearanceKey {
1185 type Value = Appearance;
1186 fn default_value() -> Self::Value {
1187 Appearance::Dark }
1189}
1190
1191pub struct StyleResolver;
1193
1194impl StyleResolver {
1195 pub fn color(key: &str) -> String {
1197 let tokens = Environment::<YggdrasilKey>::new().get();
1198 let appearance = Environment::<AppearanceKey>::new().get();
1199 let is_dark = appearance == Appearance::Dark;
1200
1201 tokens.get_color(key, is_dark).unwrap_or_else(|| "#FF00FF".to_string()) }
1203
1204 pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
1206 let tokens = Environment::<YggdrasilKey>::new().get();
1207 let appearance = Environment::<AppearanceKey>::new().get();
1208 let is_dark = appearance == Appearance::Dark;
1209
1210 tokens.get(category, key, is_dark)
1211 }
1212}
1213
1214pub fn default_tokens() -> YggdrasilTokens {
1216 let mut tokens = YggdrasilTokens::new();
1217
1218 tokens.color.insert("background".to_string(), TokenValue::Single {
1220 value: "#000000".to_string(), });
1222
1223 tokens.color.insert("primary".to_string(), TokenValue::Single {
1224 value: "#00FFFF".to_string(), });
1226
1227 tokens.color.insert("secondary".to_string(), TokenValue::Single {
1228 value: "#FF00FF".to_string(), });
1230
1231 tokens.color.insert("surface".to_string(), TokenValue::Adaptive {
1232 light: "#FFFFFF".to_string(),
1233 dark: "#121212".to_string(),
1234 });
1235
1236 tokens.color.insert("text".to_string(), TokenValue::Adaptive {
1237 light: "#000000".to_string(),
1238 dark: "#FFFFFF".to_string(),
1239 });
1240
1241 tokens.bifrost.insert("blur".to_string(), TokenValue::Single {
1243 value: "25.0".to_string(),
1244 });
1245 tokens.bifrost.insert("saturation".to_string(), TokenValue::Single {
1246 value: "1.2".to_string(),
1247 });
1248 tokens.bifrost.insert("opacity".to_string(), TokenValue::Single {
1249 value: "0.65".to_string(),
1250 });
1251
1252 tokens.gungnir.insert("intensity".to_string(), TokenValue::Single {
1254 value: "1.0".to_string(),
1255 });
1256 tokens.gungnir.insert("radius".to_string(), TokenValue::Single {
1257 value: "15.0".to_string(),
1258 });
1259
1260 tokens.mjolnir.insert("clip_angle".to_string(), TokenValue::Single {
1262 value: "12.0".to_string(),
1263 });
1264 tokens.mjolnir.insert("border_width".to_string(), TokenValue::Single {
1265 value: "2.0".to_string(),
1266 });
1267
1268 tokens.anim.insert("stiffness".to_string(), TokenValue::Single {
1270 value: "170.0".to_string(),
1271 });
1272 tokens.anim.insert("damping".to_string(), TokenValue::Single {
1273 value: "26.0".to_string(),
1274 });
1275 tokens.anim.insert("mass".to_string(), TokenValue::Single {
1276 value: "1.0".to_string(),
1277 });
1278
1279 tokens.accessibility.insert("reduce_motion".to_string(), TokenValue::Single {
1281 value: "false".to_string(),
1282 });
1283
1284 tokens
1285}
1286
1287
1288
1289
1290pub struct Environment<K: EnvKey> {
1292 _marker: std::marker::PhantomData<K>,
1293}
1294
1295impl<K: EnvKey> Environment<K> {
1296 pub fn new() -> Self {
1298 Self {
1299 _marker: std::marker::PhantomData,
1300 }
1301 }
1302
1303 pub fn get(&self) -> K::Value {
1305 if let Some(env_store) = ENVIRONMENT.get() {
1306 let env_lock = env_store.lock().unwrap();
1307 if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
1308 if let Some(typed_val) = val.downcast_ref::<K::Value>() {
1309 return typed_val.clone();
1310 }
1311 }
1312 }
1313 K::default_value()
1314 }
1315}
1316
1317pub mod env {
1319
1320 pub fn insert<K: super::EnvKey>(value: K::Value) {
1322 if let Some(store) = super::ENVIRONMENT.get() {
1323 let mut env_map = store.lock().unwrap();
1324 env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
1325 }
1326 }
1327
1328 pub fn remove<K: super::EnvKey>() {
1330 if let Some(store) = super::ENVIRONMENT.get() {
1331 let mut env_map = store.lock().unwrap();
1332 env_map.remove(&std::any::TypeId::of::<K>());
1333 }
1334 }
1335}
1336
1337
1338
1339#[derive(Debug, Clone, Copy, PartialEq)]
1343pub struct Size {
1344 pub width: f32,
1345 pub height: f32,
1346}
1347
1348#[derive(Debug, Clone, Copy, PartialEq)]
1350pub struct EdgeInsets {
1351 pub top: f32,
1352 pub leading: f32,
1353 pub bottom: f32,
1354 pub trailing: f32,
1355}
1356
1357impl EdgeInsets {
1358 pub fn all(value: f32) -> Self {
1360 Self {
1361 top: value,
1362 leading: value,
1363 bottom: value,
1364 trailing: value,
1365 }
1366 }
1367
1368 pub fn vertical(value: f32) -> Self {
1370 Self {
1371 top: value,
1372 leading: 0.0,
1373 bottom: value,
1374 trailing: 0.0,
1375 }
1376 }
1377
1378 pub fn horizontal(value: f32) -> Self {
1380 Self {
1381 top: 0.0,
1382 leading: value,
1383 bottom: 0.0,
1384 trailing: value,
1385 }
1386 }
1387}
1388
1389#[derive(Debug, Clone, Copy, PartialEq)]
1391pub struct FrameModifier {
1392 pub width: Option<f32>,
1393 pub height: Option<f32>,
1394}
1395
1396impl FrameModifier {
1397 pub fn new() -> Self {
1398 Self {
1399 width: None,
1400 height: None,
1401 }
1402 }
1403
1404 pub fn width(mut self, width: f32) -> Self {
1405 self.width = Some(width);
1406 self
1407 }
1408
1409 pub fn height(mut self, height: f32) -> Self {
1410 self.height = Some(height);
1411 self
1412 }
1413
1414 pub fn size(mut self, width: f32, height: f32) -> Self {
1415 self.width = Some(width);
1416 self.height = Some(height);
1417 self
1418 }
1419}
1420
1421impl ViewModifier for FrameModifier {
1422 fn modify<V: View>(self, content: V) -> impl View {
1423 ModifiedView::new(content, self)
1424 }
1425}
1426
1427
1428#[derive(Debug, Clone, Copy, PartialEq)]
1430pub struct OffsetModifier {
1431 pub x: f32,
1432 pub y: f32,
1433}
1434
1435impl OffsetModifier {
1436 pub fn new(x: f32, y: f32) -> Self {
1437 Self { x, y }
1438 }
1439}
1440
1441impl ViewModifier for OffsetModifier {
1442 fn modify<V: View>(self, content: V) -> impl View {
1443 ModifiedView::new(content, self)
1444 }
1445}
1446
1447#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1449pub struct ZIndexModifier {
1450 pub z_index: i32,
1451}
1452
1453impl ZIndexModifier {
1454 pub fn new(z_index: i32) -> Self {
1455 Self { z_index }
1456 }
1457}
1458
1459impl ViewModifier for ZIndexModifier {
1460 fn modify<V: View>(self, content: V) -> impl View {
1461 ModifiedView::new(content, self)
1462 }
1463}
1464
1465#[derive(Debug, Clone, Copy, PartialEq)]
1467pub struct LayoutConstraints {
1468 pub min_width: Option<f32>,
1469 pub max_width: Option<f32>,
1470 pub min_height: Option<f32>,
1471 pub max_height: Option<f32>,
1472}
1473
1474impl Default for LayoutConstraints {
1475 fn default() -> Self {
1476 Self {
1477 min_width: None,
1478 max_width: None,
1479 min_height: None,
1480 max_height: None,
1481 }
1482 }
1483}
1484
1485#[derive(Debug, Clone, Copy, PartialEq)]
1487pub struct LayoutModifier {
1488 pub constraints: LayoutConstraints,
1489}
1490
1491impl LayoutModifier {
1492 pub fn new(constraints: LayoutConstraints) -> Self {
1493 Self { constraints }
1494 }
1495}
1496
1497impl ViewModifier for LayoutModifier {
1498 fn modify<V: View>(self, content: V) -> impl View {
1499 ModifiedView::new(content, self)
1500 }
1501}
1502
1503#[derive(Debug, Clone, Copy, PartialEq)]
1505pub struct FlexModifier {
1506 pub flex: f32,
1507}
1508
1509impl FlexModifier {
1510 pub fn new(flex: f32) -> Self {
1511 Self { flex }
1512 }
1513}
1514
1515impl ViewModifier for FlexModifier {
1516 fn modify<V: View>(self, content: V) -> impl View {
1517 ModifiedView::new(content, self)
1518 }
1519}
1520
1521pub mod layout {
1523 use super::*;
1524
1525 pub struct LayoutCache;
1527
1528 impl LayoutCache {
1529 pub fn new() -> Self {
1530 Self
1531 }
1532
1533 pub fn clear(&mut self) {
1534 }
1536 }
1537
1538 #[derive(Debug, Clone, Copy, PartialEq)]
1540 pub struct SizeProposal {
1541 pub width: Option<f32>,
1542 pub height: Option<f32>,
1543 }
1544
1545 impl SizeProposal {
1546 pub fn unspecified() -> Self {
1547 Self {
1548 width: None,
1549 height: None,
1550 }
1551 }
1552
1553 pub fn width(width: f32) -> Self {
1554 Self {
1555 width: Some(width),
1556 height: None,
1557 }
1558 }
1559
1560 pub fn height(height: f32) -> Self {
1561 Self {
1562 width: None,
1563 height: Some(height),
1564 }
1565 }
1566
1567 pub fn tight(width: f32, height: f32) -> Self {
1568 Self {
1569 width: Some(width),
1570 height: Some(height),
1571 }
1572 }
1573 }
1574
1575 pub trait LayoutView: Send {
1577 fn size_that_fits(&self, proposal: SizeProposal, subviews: &[&dyn LayoutView], cache: &mut LayoutCache) -> Size;
1579
1580 fn place_subviews(&self, bounds: Rect, subviews: &mut [&mut dyn LayoutView], cache: &mut LayoutCache);
1582 }
1583
1584 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
1586 pub struct Rect {
1587 pub x: f32,
1588 pub y: f32,
1589 pub width: f32,
1590 pub height: f32,
1591 }
1592
1593 impl Rect {
1594 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
1595 Self { x, y, width, height }
1596 }
1597
1598 pub fn zero() -> Self {
1599 Self { x: 0.0, y: 0.0, width: 0.0, height: 0.0 }
1600 }
1601
1602 pub fn size(&self) -> Size {
1603 Size { width: self.width, height: self.height }
1604 }
1605
1606 pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
1608 if n == 0 { return vec![]; }
1609 let item_width = self.width / n as f32;
1610 (0..n).map(|i| Rect {
1611 x: self.x + i as f32 * item_width,
1612 y: self.y,
1613 width: item_width,
1614 height: self.height,
1615 }).collect()
1616 }
1617
1618 pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
1620 if n == 0 { return vec![]; }
1621 let item_height = self.height / n as f32;
1622 (0..n).map(|i| Rect {
1623 x: self.x,
1624 y: self.y + i as f32 * item_height,
1625 width: self.width,
1626 height: item_height,
1627 }).collect()
1628 }
1629 }
1630}
1631
1632pub use layout::{LayoutView, SizeProposal, Rect, LayoutCache};
1634pub mod runtime;
1637pub mod scene_graph;
1638
1639pub use scene_graph::{NodeId, bifrost_registry};
1640
1641
1642#[derive(Debug, Clone, PartialEq)]
1644pub enum AssetState<T> {
1645 Loading,
1646 Ready(T),
1647 Error(String),
1648}
1649
1650pub trait AssetManager: Send + Sync {
1652 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
1654
1655 fn preload_image(&self, url: &str);
1657}
1658
1659
1660#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1662pub enum Event {
1663 PointerDown { x: f32, y: f32 },
1664 PointerUp { x: f32, y: f32 },
1665 PointerMove { x: f32, y: f32 },
1666 KeyDown { key: String },
1667 KeyUp { key: String },
1668}
1669
1670#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1672pub enum EventResponse {
1673 Handled,
1674 Ignored,
1675}
1676
1677pub struct DefaultAssetManager {
1679 cache: Arc<std::sync::RwLock<HashMap<String, AssetState<Arc<Vec<u8>>>>>>,
1680}
1681
1682impl DefaultAssetManager {
1683 pub fn new() -> Self {
1684 Self {
1685 cache: Arc::new(std::sync::RwLock::new(HashMap::new())),
1686 }
1687 }
1688}
1689
1690impl AssetManager for DefaultAssetManager {
1691 fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
1692 let mut cache = self.cache.write().unwrap();
1693 if let Some(state) = cache.get(url) {
1694 return state.clone();
1695 }
1696
1697 cache.insert(url.to_string(), AssetState::Loading);
1700 AssetState::Loading
1701 }
1702
1703 fn preload_image(&self, _url: &str) {
1704 }
1706}
1707
1708#[cfg(test)]
1709mod phase1_test;