Skip to main content

cvkg_core/
lib.rs

1//! # CVKG Agentic Development Guidelines (v1.2)
2//!
3//! All AI agents contributing to this crate MUST follow ALL seven rules:
4//!
5//! ── Karpathy Guidelines (1–4) ────────────────────────────────────────────
6//! 1. THINK FIRST     — State assumptions. Surface ambiguity. Push back on complexity.
7//! 2. STAY SIMPLE     — Minimum code. No speculative features. No unasked-for abstractions.
8//! 3. BE SURGICAL     — Touch only what's required. Own your orphans. Don't improve neighbors.
9//! 4. VERIFY GOALS    — Turn tasks into checkable criteria. Loop until they pass. Never commit broken.
10//!
11//! ── CVKG Extended Protocols (5–7) ────────────────────────────────────────
12//! 5. TRIPLE-PASS     — Read the target, its surrounding context, and its full call graph
13//                      at least THREE TIMES before making any edit or revision.
14//! 6. COMMENT ALL     — Every major pub fn, unsafe block, and non-trivial algorithm in
15//                      every .rs/.ts/.h/.wgsl file MUST have a descriptive doc comment.
16//                      Comments describe WHY and WHAT CONTRACT, not HOW mechanically.
17//! 7. MONITOR LOOPS   — Check every tool call / command for progress every 30 seconds.
18//                      After 3 consecutive identical failures, stop, write BLOCKED.md,
19//                      and move to unblocked work. Never silently accept a broken state.
20//!
21//! Sources:
22//   Karpathy: https://github.com/multica-ai/andrej-karpathy-skills
23//   CVKG Extended: Section 2 of the CVKG Design Specification
24
25//! The View trait is the fundamental building block of CVKG. Every UI element — from a plain text label
26//! to a complex navigation controller — is a View. The trait is intentionally minimal; complexity emerges
27//! through modifier composition.
28//!
29//! # Conformance rules:
30//! 1. `body()` must be pure and side-effect free
31//! 2. Primitive views use `Never` as `Body` and register a `PaintCommand` directly with the scene graph
32//! 3. `View` types must implement `Send` but not necessarily `Sync`, enabling safe multi-threaded layout passes
33
34use serde::{Deserialize, Serialize};
35use std::collections::HashMap;
36use std::str::FromStr;
37
38/// Design token value that can adapt to light/dark mode
39#[derive(Debug, Clone, Serialize, Deserialize)]
40#[serde(untagged)]
41pub enum TokenValue {
42    /// Single value (same for light and dark)
43    Single {
44        value: String,
45    },
46    /// Different values for light and dark mode
47    Adaptive {
48        light: String,
49        dark: String,
50    },
51}
52
53/// YggdrasilTokens is the authoritative container for all design tokens in the CVKG ecosystem.
54#[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    /// Get a color token value for the current mode
87    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    /// Get a token value of any type and parse it into the target type
99    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    /// The concrete type produced after applying modifiers.
129    /// For primitive views this is Self.
130    type Body: View;
131
132    fn body(self) -> Self::Body;
133
134    /// Render this view into the provided renderer at the specified bounds.
135    /// Primitive views override this to perform drawing operations.
136    fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
137
138    /// Optionally provide a layout implementation for this view.
139    fn layout(&self) -> Option<&dyn layout::LayoutView> {
140        None
141    }
142
143    /// Provided modifier entry point
144    fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
145        ModifiedView::new(self, m)
146    }
147
148    /// Apply a Bifrost (Frosted Glass) effect to the view
149    fn bifrost(self, blur: f32, saturation: f32, opacity: f32) -> ModifiedView<Self, BifrostModifier> {
150        self.modifier(BifrostModifier { blur, saturation, opacity })
151    }
152
153    /// Apply a Gungnir (Neon Glow) effect to the view
154    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    /// Apply a Mjolnir Slice (Geometric cut) to the view
159    fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
160        self.modifier(MjolnirSliceModifier { angle, offset })
161    }
162
163    /// Apply a Mjolnir Shatter (Fragmented transition) to the view
164    fn mjolnir_shatter(self, pieces: u32, force: f32) -> ModifiedView<Self, MjolnirShatterModifier> {
165        self.modifier(MjolnirShatterModifier { pieces, force })
166    }
167
168    /// Mark this view as a Bifrost Bridge (Shared Element) for cross-view persistence
169    fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
170        self.modifier(BifrostBridgeModifier { id: id.into() })
171    }
172
173    /// Add a background color to this view
174    fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
175        self.modifier(BackgroundModifier { color })
176    }
177
178    /// Add padding to this view
179    fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
180        self.modifier(PaddingModifier { amount })
181    }
182
183    /// Set the opacity (alpha) of this view in the range [0.0, 1.0].
184    fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
185        self.modifier(OpacityModifier { opacity: opacity.clamp(0.0, 1.0) })
186    }
187
188    /// Override the foreground (text / icon) color of this view.
189    fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
190        self.modifier(ForegroundColorModifier { color })
191    }
192
193    /// Constrain this view to an explicit width and/or height.
194    fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
195        self.modifier(FrameModifier { width, height })
196    }
197
198    /// Clip all child drawing to this view's bounds.
199    fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
200        self.modifier(ClipModifier)
201    }
202
203    /// Draw a colored border around this view.
204    fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
205        self.modifier(BorderModifier { color, width })
206    }
207
208    /// Trigger an action when the view appears
209    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    /// Trigger an action when the view disappears
217    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    /// Type-erase this view into AnyView
225    fn erase(self) -> AnyView where Self: 'static {
226        AnyView::new(self)
227    }
228}
229
230/// An object-safe version of the View trait for type erasure.
231pub 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
246/// A type-erased View wrapper.
247pub 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/// BifrostBridgeModifier enables shared-element transitions.
269/// When two views share the same Bifrost Bridge ID, the Sleipnir solver will
270/// interpolate their geometry and effects (blur, glow) during the transition.
271#[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        // Register this element with the renderer for shared-element transition logic
283        renderer.register_shared_element(&self.id, rect);
284    }
285}
286
287/// MjolnirSliceModifier implements the "Geometric Slice" aesthetic.
288/// It uses a signed distance field (SDF) to clip the view along a sharp angled line.
289#[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/// MjolnirShatterModifier implements the "Shattering" effect.
310/// It breaks the view into discrete geometric fragments that can be animated.
311#[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        // RADIAL SHATTER: Fragment the view into wedges
324        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            // Wedge slice: intersection of two half-planes
333            renderer.push_mjolnir_slice(angle_start, 0.0);
334            renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
335            
336            // Apply radial force offset
337            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/// BifrostModifier implements the Cyberpunk "Frosted Glass" aesthetic.
357/// It triggers backdrop blurring and light scattering in the render pipeline.
358#[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/// A modifier that adds a background color to a view.
376#[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/// A modifier that adds padding to a view.
392#[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/// GungnirModifier implements the "Neon Glow" aesthetic.
413/// It uses additive blending and multi-pass blurring to simulate glowing light.
414#[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        // Neon Glow using Mode 1 in the Surtr pipeline
428        renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
429    }
430}
431
432/// GungnirPulseModifier implements a "breathing" neon effect.
433#[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        // Mode 19: Dashed Border
452        // Mode 20: 9-Slice / Patch Scaling
453        let intensity = (time * self.speed).sin() * 0.5 + 0.5;
454        let mut color = self.color;
455        color[3] *= intensity;
456        
457        // Mode 1 neon glow with dynamic intensity
458        renderer.stroke_rect(rect, color, self.radius);
459    }
460}
461
462/// SleipnirModifier handles physics-based animations via the Sleipnir RK4 solver.
463#[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/// LifecycleModifier handles on_appear and on_disappear hooks.
477#[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/// OpacityModifier fades this view and all its descendants to the given alpha.
490/// The renderer is expected to honour `push_opacity`/`pop_opacity` on the Renderer trait.
491#[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/// ForegroundColorModifier overrides the foreground (text / icon) color inherited
511/// by all descendants until another ForegroundColorModifier is encountered.
512#[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/// ClipModifier restricts all child drawing to the view's layout rectangle.
524/// The renderer must support `push_clip_rect`/`pop_clip_rect`.
525#[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/// BorderModifier draws a solid-color border around the view bounds.
543#[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// Primitive (leaf) views implement Never as body
560#[doc(hidden)]
561pub enum Never {}
562
563impl View for Never {
564    type Body = Never;
565    fn body(self) -> Never {
566        unreachable!()
567    }
568}
569
570/// A view that has been transformed by a modifier.
571///
572/// Section 4.3: "Each modifier implements ViewModifier and produces a ModifiedView<Inner, Self>."
573pub 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        /// Core rendering hook called before child views.
605        fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
606        
607        /// Cleanup hook called after child views.
608        fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
609        
610        /// Allows a modifier to completely override or wrap the rendering of its child.
611        /// Default implementation performs a standard push -> transform -> render child -> pop sequence.
612        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    /// The Renderer trait defines the atomic drawing operations for all CVKG backends.
623    /// This trait is object-safe and used by the View::render system.
624    ///
625    /// # Implementation Requirements
626    /// 1. Coordinate system is origin-top-left (0,0) with Y increasing downwards.
627    /// 2. Colors are [R, G, B, A] in the [0.0, 1.0] range.
628    /// 3. All operations must be batchable by the underlying backend.
629    pub trait Renderer: Send {
630        // ── Filled shapes ────────────────────────────────────────────────────
631        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        /// Fill an ellipse/circle that fits inside `rect`.
634        fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
635
636        // ── Stroked shapes ───────────────────────────────────────────────────
637        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        /// Stroke an ellipse/circle that fits inside `rect`.
640        fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
641        /// Draw a straight line from (x1,y1) to (x2,y2).
642        fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
643
644        // ── Text ─────────────────────────────────────────────────────────────
645        fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
646        /// Measure the width and height of the specified text.
647        fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
648
649        // ── Images & textures ────────────────────────────────────────────────
650        /// Draw a texture (GPU-side) at the specified rect.
651        fn draw_texture(&mut self, texture_id: u32, rect: Rect);
652        /// Draw an image asset by name or path.
653        fn draw_image(&mut self, image_name: &str, rect: Rect);
654        /// Load an image asset from memory.
655        fn load_image(&mut self, name: &str, data: &[u8]);
656
657        // ── Data Visualization ───────────────────────────────────────────────
658        /// Upload raw float data as a GPU texture for heatmap rendering.
659        fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
660        /// Draw a heatmap using a previously uploaded data texture.
661        fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
662
663        // ── 3D Objects ───────────────────────────────────────────────────────
664        /// Draw a 3D mesh.
665        fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
666
667        // ── Advanced Visual Effects ──────────────────────────────────────────
668        /// Draw a linear gradient between two colors at the specified angle.
669        fn draw_linear_gradient(&mut self, _rect: Rect, _start_color: [f32; 4], _end_color: [f32; 4], _angle: f32) {}
670        /// Draw a radial gradient between two colors.
671        fn draw_radial_gradient(&mut self, _rect: Rect, _inner_color: [f32; 4], _outer_color: [f32; 4]) {}
672        /// Draw a high-fidelity drop shadow for a rounded rectangle.
673        fn draw_drop_shadow(&mut self, _rect: Rect, _radius: f32, _color: [f32; 4], _blur: f32, _spread: f32) {}
674        /// Draw a dashed border for a rounded rectangle.
675        fn stroke_dashed_rounded_rect(&mut self, _rect: Rect, _radius: f32, _color: [f32; 4], _width: f32, _dash: f32, _gap: f32) {}
676        /// Draw a 9-slice / patch scaled image.
677        fn draw_9slice(&mut self, _image_name: &str, _rect: Rect, _left: f32, _top: f32, _right: f32, _bottom: f32) {}
678
679        // ── Clipping ─────────────────────────────────────────────────────────
680        /// Push a clip rectangle.  All subsequent drawing is clipped to `rect`.
681        /// Implementations that do not support clipping may ignore this call.
682        fn push_clip_rect(&mut self, rect: Rect);
683        /// Pop the most recently pushed clip rectangle.
684        fn pop_clip_rect(&mut self);
685
686        // ── Global opacity ───────────────────────────────────────────────────
687        /// Set a global opacity multiplier applied to all subsequent draw calls
688        /// until `pop_opacity` is called.  `opacity` is in [0.0, 1.0].
689        fn push_opacity(&mut self, opacity: f32);
690        /// Restore the previous opacity level.
691        fn pop_opacity(&mut self);
692        
693        // ── Berserker Pipeline State ─────────────────────────────────────────
694        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        // ── Cyberpunk Effects ────────────────────────────────────────────────
699        /// Apply a Bifrost (Frosted Glass) effect to the specified rect.
700        fn bifrost(&mut self, rect: Rect, blur: f32, saturation: f32, opacity: f32);
701        /// Push a Mjolnir Slice (geometric clipping).
702        fn push_mjolnir_slice(&mut self, angle: f32, offset: f32);
703        /// Pop the Mjolnir Slice.
704        fn pop_mjolnir_slice(&mut self);
705        /// Apply a Mjolnir Shatter effect (fragmentation) to the specified rect.
706        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        /// Draw a Mjolnir Bolt (lightning strike) between two points.
709        fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
710
711        // ── Accessibility (ShieldWall) ───────────────────────────────────────
712        fn set_aria_role(&mut self, _role: &str) {}
713        fn set_aria_label(&mut self, _label: &str) {}
714
715        /// Register a shared element for Bifrost Bridge transitions.
716        fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
717
718        // ── VDOM Hierarchy ───────────────────────────────────────────────────
719        /// Push a Virtual DOM node onto the stack for hierarchy tracking.
720        fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
721        /// Pop the current Virtual DOM node from the stack.
722        fn pop_vnode(&mut self) {}
723        /// Register an event handler for the current VDOM node.
724        fn register_handler(&mut self, _event_type: &str, _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>) {}
725    }
726
727    // =============================================================================
728    // BERSERKER UNIFORMS
729    // =============================================================================
730
731    use bytemuck::{Pod, Zeroable};
732
733    /// Fully themeable color palette for the Berserker pipeline.
734    #[repr(C)]
735    #[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
736    pub struct ColorTheme {
737        pub primary_neon:        [f32; 4],   // (R, G, B, intensity)
738        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,   // 0.0–1.0, default 0.55
748        // Padding to ensure 16-byte alignment for GPU uniforms
749        pub _pad:                [f32; 3],   // align to 16 bytes
750        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], // Luminous cool tint
777                glass_edge:          [0.7,  0.85, 1.0, 0.45],  // Subtle blue-white rim
778                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    /// Per-frame scene state for the Berserker pipeline.
798    #[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        // Padding to ensure 16-byte alignment for GPU uniforms
814        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    /// A 3D mesh containing vertex and index data.
838    #[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    /// FrameRenderer extends Renderer with frame lifecycle management.
885    /// It is typically implemented by the host windowing/rendering environment.
886    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/// State wrapper that owns a value and notifies subscribers when changed
896#[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    /// Create a new State with initial value
904    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    /// Get the current value
912    pub fn get(&self) -> T {
913        self.value.read().unwrap().clone()
914    }
915    
916    /// Set a new value, notifying all subscribers
917    pub fn set(&self, value: T) {
918        *self.value.write().unwrap() = value;
919        // Notify subscribers
920        let mut subscribers = self.subscribers.write().unwrap();
921        for subscriber in subscribers.iter_mut() {
922            subscriber(&self.get());
923        }
924    }
925    
926    /// Subscribe to state changes
927    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/// Error state for fault isolation at the component level.
933///
934/// Section 1.1: "Components must self-handle errors... isolating failures."
935#[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    /// Create a new clear error state.
944    pub fn clear() -> Self {
945        Self::default()
946    }
947
948    /// Create an error state with a message and location.
949    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/// A discrete fragment of knowledge stored in the agent's memory.
959#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
960pub struct KnowledgeFragment {
961    /// Unique identifier for this fragment
962    pub id: String,
963    /// Short summary for prompt injection and quick search
964    pub summary: String,
965    /// Reference source (e.g. filename, URL, or conversation ID)
966    pub source: String,
967    /// Frame number or timestamp of creation
968    pub created_at: u64,
969    /// Number of times this fragment has been retrieved
970    pub accessed_count: u32,
971    /// Full content (optional, can be loaded on-demand)
972    pub content: Option<String>,
973}
974
975/// The KnowledgeState registry is the central repository for all agent-observable application data.
976/// It stores both component-level states and high-level agentic memory fragments.
977#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
978pub struct KnowledgeState {
979    /// Component states indexed by NodeId. Skipped in serialization as it contains opaque types.
980    #[serde(skip)]
981    pub component_states: std::collections::HashMap<u64, Arc<dyn std::any::Any + Send + Sync>>,
982    
983    /// Map of IDs to knowledge fragments (Agentic Memory)
984    pub fragments: HashMap<String, KnowledgeFragment>,
985    
986    /// IDs of fragments returned by the last search query
987    pub last_query_results: Vec<String>,
988}
989
990use std::sync::OnceLock;
991use crate::runtime::NodeStateSnapshot;
992
993/// Global application state registry.
994pub static SYSTEM_STATE: OnceLock<Arc<std::sync::RwLock<KnowledgeState>>> = OnceLock::new();
995
996/// Get a reference to the global system state.
997pub 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    /// Create a new empty KnowledgeState.
1003    pub fn new() -> Self {
1004        Self::default()
1005    }
1006
1007    /// Set a component's internal state.
1008    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    /// Get a reference to a component's internal state.
1013    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    /// Add a new fragment to memory.
1019    pub fn remember(&mut self, fragment: KnowledgeFragment) {
1020        self.fragments.insert(fragment.id.clone(), fragment);
1021    }
1022
1023    /// Process a search query against the local knowledge base.
1024    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        // Sort by relevance score
1038        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    /// Captures a snapshot of the current state for debugging and hot-reloading.
1047    pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
1048        let mut snapshots = Vec::new();
1049        
1050        // Snapshots of agentic fragments
1051        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/// Read/write reference to state owned by another view
1065#[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    /// Create a binding from a State
1072    pub fn from_state(state: &State<T>) -> Self {
1073        Self {
1074            state: state.value.clone(),
1075        }
1076    }
1077    
1078    /// Get the current value
1079    pub fn get(&self) -> T {
1080        self.state.read().unwrap().clone()
1081    }
1082    
1083    /// Set a new value
1084    pub fn set(&self, value: T) {
1085        *self.state.write().unwrap() = value;
1086    }
1087}
1088
1089use std::any::TypeId;
1090use std::sync::Mutex;
1091
1092/// Global environment storage using TypeId as keys.
1093pub(crate) static ENVIRONMENT: OnceLock<Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>> = OnceLock::new();
1094
1095/// Environment key type for accessing ambient values
1096///
1097/// Implement this trait to define a new environment key.
1098pub trait EnvKey: 'static + Send + Sync {
1099    /// The type of value stored in the environment
1100    type Value: Clone + Send + Sync + 'static;
1101    
1102    /// Get a default value for this key
1103    fn default_value() -> Self::Value;
1104}
1105
1106/// Key for accessing the Yggdrasil design token tree
1107pub struct YggdrasilKey;
1108
1109impl EnvKey for YggdrasilKey {
1110    type Value = YggdrasilTokens;
1111    fn default_value() -> Self::Value {
1112        default_tokens()
1113    }
1114}
1115
1116/// Key for accessing the AssetManager
1117pub 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/// System appearance (Light/Dark mode)
1127#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1128pub enum Appearance {
1129    Light,
1130    Dark,
1131}
1132
1133/// Orientation for layouts
1134#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1135pub enum Orientation {
1136    Horizontal,
1137    Vertical,
1138}
1139
1140/// A color represented by RGBA components in the [0.0, 1.0] range.
1141#[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    /// Create a new color from RGBA components.
1162    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
1163        Self { r, g, b, a }
1164    }
1165
1166    /// Convert the color to a [r, g, b, a] array.
1167    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
1181/// Key for accessing the current system appearance
1182pub struct AppearanceKey;
1183
1184impl EnvKey for AppearanceKey {
1185    type Value = Appearance;
1186    fn default_value() -> Self::Value {
1187        Appearance::Dark // Default to Dark (Ginnungagap) for Berserker aesthetic
1188    }
1189}
1190
1191/// StyleResolver provides high-level access to themed values from the environment.
1192pub struct StyleResolver;
1193
1194impl StyleResolver {
1195    /// Resolve a color from the current environment
1196    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()) // Default to MuspelMagenta on failure
1202    }
1203
1204    /// Resolve a generic token value
1205    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
1214/// The authoritative Cyberpunk Viking default tokens
1215pub fn default_tokens() -> YggdrasilTokens {
1216    let mut tokens = YggdrasilTokens::new();
1217    
1218    // Core Norse Colorways
1219    tokens.color.insert("background".to_string(), TokenValue::Single {
1220        value: "#000000".to_string(), // Ginnungagap (The Void)
1221    });
1222    
1223    tokens.color.insert("primary".to_string(), TokenValue::Single {
1224        value: "#00FFFF".to_string(), // NiflCyan (Aesir Primary)
1225    });
1226    
1227    tokens.color.insert("secondary".to_string(), TokenValue::Single {
1228        value: "#FF00FF".to_string(), // MuspelMagenta (Berserker Secondary)
1229    });
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    // Bifrost (Glassmorphism) - Frosted Style
1242    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    // Gungnir (Neon Glow)
1253    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    // Mjolnir (Sharp Geometry)
1261    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    // Sleipnir (Spring Animation)
1269    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    // Accessibility
1280    tokens.accessibility.insert("reduce_motion".to_string(), TokenValue::Single {
1281        value: "false".to_string(),
1282    });
1283    
1284    tokens
1285}
1286
1287
1288
1289
1290/// Environment wrapper for accessing ambient values
1291pub struct Environment<K: EnvKey> {
1292    _marker: std::marker::PhantomData<K>,
1293}
1294
1295impl<K: EnvKey> Environment<K> {
1296    /// Create a new Environment
1297    pub fn new() -> Self {
1298        Self {
1299            _marker: std::marker::PhantomData,
1300        }
1301    }
1302    
1303    /// Get the current value from the environment
1304    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
1317/// Ambient environment management
1318pub mod env {
1319    
1320    /// Insert a value into the environment
1321    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    /// Remove a value from the environment.
1329    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/// Geometry modifiers
1340
1341/// Size of the view in logical pixels
1342#[derive(Debug, Clone, Copy, PartialEq)]
1343pub struct Size {
1344    pub width: f32,
1345    pub height: f32,
1346}
1347
1348/// Insets for padding
1349#[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    /// Equal insets on all edges
1359    pub fn all(value: f32) -> Self {
1360        Self {
1361            top: value,
1362            leading: value,
1363            bottom: value,
1364            trailing: value,
1365        }
1366    }
1367    
1368    /// Vertical insets (top and bottom)
1369    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    /// Horizontal insets (leading and trailing)
1379    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/// Modifier to set the size of a view
1390#[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/// Modifier to offset a view
1429#[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/// Modifier to set the z-index of a view
1448#[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/// Layout constraints for views
1466#[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/// Modifier to set layout constraints
1486#[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/// Modifier to make a view flexible in layout
1504#[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
1521// Layout subsystem
1522pub mod layout {
1523    use super::*;
1524
1525    // Layout pass scratch space
1526    pub struct LayoutCache;
1527
1528    impl LayoutCache {
1529        pub fn new() -> Self {
1530            Self
1531        }
1532
1533        pub fn clear(&mut self) {
1534            // In a real implementation, this would clear cached layout data
1535        }
1536    }
1537    
1538    /// Proposed size from parent view
1539    #[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    /// A view that can participate in layout
1576    pub trait LayoutView: Send {
1577        /// Propose a size for this view given the available space
1578        fn size_that_fits(&self, proposal: SizeProposal, subviews: &[&dyn LayoutView], cache: &mut LayoutCache) -> Size;
1579        
1580        /// Place subviews within the given bounds
1581        fn place_subviews(&self, bounds: Rect, subviews: &mut [&mut dyn LayoutView], cache: &mut LayoutCache);
1582    }
1583    
1584    /// Rectangle in logical pixels
1585    #[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        /// Split the rect horizontally into N equal pieces
1607        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        /// Split the rect vertically into N equal pieces
1619        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
1632// Re-export layout items for convenience
1633pub use layout::{LayoutView, SizeProposal, Rect, LayoutCache};
1634// Size and FrameRenderer are pub items in this module; no re-export alias needed.
1635
1636pub mod runtime;
1637pub mod scene_graph;
1638
1639pub use scene_graph::{NodeId, bifrost_registry};
1640
1641
1642/// State of an asset being loaded
1643#[derive(Debug, Clone, PartialEq)]
1644pub enum AssetState<T> {
1645    Loading,
1646    Ready(T),
1647    Error(String),
1648}
1649
1650/// AssetManager defines the interface for loading and caching external resources.
1651pub trait AssetManager: Send + Sync {
1652    /// Request an image asset. Returns the current state (Loading, Ready, or Error).
1653    fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
1654    
1655    /// Pre-load an image into the cache.
1656    fn preload_image(&self, url: &str);
1657}
1658
1659
1660/// User input event types
1661#[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/// Response from an event handler
1671#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1672pub enum EventResponse {
1673    Handled,
1674    Ignored,
1675}
1676
1677/// A basic implementation of AssetManager that can be overridden by platform backends.
1678pub 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        // In the default manager, we just mark it as Loading and spawn a placeholder 
1698        // (Real backends will override this with actual I/O)
1699        cache.insert(url.to_string(), AssetState::Loading);
1700        AssetState::Loading
1701    }
1702
1703    fn preload_image(&self, _url: &str) {
1704        // No-op for default manager
1705    }
1706}
1707
1708#[cfg(test)]
1709mod phase1_test;