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
38pub mod security;
39
40/// Error state for fault isolation at the component level.
41#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
42pub struct ComponentErrorState {
43    pub has_error: bool,
44    pub error_message: Option<String>,
45    pub error_location: Option<String>,
46}
47impl ComponentErrorState {
48    pub fn clear() -> Self {
49        Self::default()
50    }
51
52    pub fn error(message: impl Into<String>, location: impl Into<String>) -> Self {
53        Self {
54            has_error: true,
55            error_message: Some(message.into()),
56            error_location: Some(location.into()),
57        }
58    }
59}
60
61/// Knowledge state for the agentic memory system.
62#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
63pub struct KnowledgeState {
64    pub thoughts: Vec<String>,
65    pub actions: Vec<String>,
66    pub context: HashMap<String, String>,
67    pub last_query_results: Vec<KnowledgeId>,
68    pub fragments: std::collections::HashMap<KnowledgeId, KnowledgeFragment>,
69    // Component state storage for dynamic state
70    #[serde(skip)]
71    pub component_states: HashMap<u64, Arc<std::sync::RwLock<dyn std::any::Any + Send + Sync>>>,
72}
73// Knowledge System Types
74/// Unique identifier for knowledge fragments
75pub type KnowledgeId = String;
76
77/// A knowledge fragment stored in the memory system
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct KnowledgeFragment {
80    /// Unique identifier for this fragment
81    pub id: String,
82    /// Short summary for prompt injection and quick search
83    pub summary: String,
84    /// Reference source (e.g. filename, URL, or conversation ID)
85    pub source: String,
86    /// Frame number or timestamp of creation
87    pub created_at: u64,
88    /// Number of times this fragment has been retrieved
89    pub accessed_count: u32,
90    /// Full content (optional, can be loaded on-demand)
91    pub content: Option<String>,
92}
93
94impl KnowledgeFragment {
95    pub fn new(id: String, summary: String, source: String) -> Self {
96        Self {
97            id,
98            summary,
99            source,
100            created_at: 0,
101            accessed_count: 0,
102            content: None,
103        }
104    }
105}
106
107#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
108pub struct AssetKey(pub String);
109
110impl EnvKey for AssetKey {
111    type Value = Arc<dyn AssetManager>;
112    fn default_value() -> Self::Value {
113        Arc::new(DefaultAssetManager::new())
114    }
115}
116
117/// Asset state for async resource loading.
118#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
119pub enum AssetState<T> {
120    Loading,
121    Ready(T),
122    Error(String),
123}
124
125/// Design token value that can adapt to light/dark mode
126#[derive(Debug, Clone, Serialize, Deserialize)]
127#[serde(untagged)]
128pub enum TokenValue {
129    /// Single value (same for light and dark)
130    Single { value: String },
131    /// Different values for light and dark mode
132    Adaptive { light: String, dark: String },
133}
134
135/// YggdrasilTokens is the authoritative container for all design tokens in the CVKG ecosystem.
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct YggdrasilTokens {
138    pub color: HashMap<String, TokenValue>,
139    pub font: HashMap<String, TokenValue>,
140    pub spacing: HashMap<String, TokenValue>,
141    pub radius: HashMap<String, TokenValue>,
142    pub shadow: HashMap<String, TokenValue>,
143    pub border: HashMap<String, TokenValue>,
144    pub anim: HashMap<String, TokenValue>,
145    pub bifrost: HashMap<String, TokenValue>,
146    pub gungnir: HashMap<String, TokenValue>,
147    pub mjolnir: HashMap<String, TokenValue>,
148    pub accessibility: HashMap<String, TokenValue>,
149}
150
151impl Default for YggdrasilTokens {
152    fn default() -> Self {
153        Self::new()
154    }
155}
156
157
158
159impl YggdrasilTokens {
160    pub fn new() -> Self {
161        Self {
162            color: HashMap::new(),
163            font: HashMap::new(),
164            spacing: HashMap::new(),
165            radius: HashMap::new(),
166            shadow: HashMap::new(),
167            border: HashMap::new(),
168            anim: HashMap::new(),
169            bifrost: HashMap::new(),
170            gungnir: HashMap::new(),
171            mjolnir: HashMap::new(),
172            accessibility: HashMap::new(),
173        }
174    }
175
176    /// Get a color token value for the current mode
177    pub fn get_color(&self, key: &str, is_dark: bool) -> Option<String> {
178        self.color.get(key).map(|token| match token {
179            TokenValue::Single { value } => value.clone(),
180            TokenValue::Adaptive { light, dark } => {
181                if is_dark {
182                    dark.clone()
183                } else {
184                    light.clone()
185                }
186            }
187        })
188    }
189
190    /// Get a token value of any type and parse it into the target type
191    pub fn get<T: FromStr>(&self, category: &str, key: &str, is_dark: bool) -> Option<T> {
192        let map = match category {
193            "color" => &self.color,
194            "font" => &self.font,
195            "spacing" => &self.spacing,
196            "radius" => &self.radius,
197            "shadow" => &self.shadow,
198            "border" => &self.border,
199            "anim" => &self.anim,
200            "bifrost" => &self.bifrost,
201            "gungnir" => &self.gungnir,
202            "mjolnir" => &self.mjolnir,
203            "accessibility" => &self.accessibility,
204            _ => return None,
205        };
206
207        map.get(key).and_then(|token| match token {
208            TokenValue::Single { value } => value.parse().ok(),
209            TokenValue::Adaptive { light, dark } => {
210                let value = if is_dark { dark } else { light };
211                value.parse().ok()
212            }
213        })
214    }
215}
216
217pub trait View: Sized + Send {
218    /// The concrete type produced after applying modifiers.
219    /// For primitive views this is Self.
220    type Body: View;
221
222    fn body(self) -> Self::Body;
223
224    /// Render this view into the provided renderer at the specified bounds.
225    /// Primitive views override this to perform drawing operations.
226    fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
227
228    /// Calculate the natural (intrinsic) size of this view given proposed constraints.
229    /// This allows views like Buttons or Labels to inform the layout engine of their needs.
230    fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
231        Size::ZERO
232    }
233
234    /// Optionally provide a layout implementation for this view.
235    fn layout(&self) -> Option<&dyn layout::LayoutView> {
236        None
237    }
238
239    /// Returns the flex weight of this view for proportional distribution in stacks.
240    fn flex_weight(&self) -> f32 {
241        0.0
242    }
243
244    /// Provided modifier entry point
245    fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
246        ModifiedView::new(self, m)
247    }
248
249    /// Apply a Bifrost (Frosted Glass) effect to the view
250    fn bifrost(
251        self,
252        blur: f32,
253        saturation: f32,
254        opacity: f32,
255    ) -> ModifiedView<Self, BifrostModifier> {
256        self.modifier(BifrostModifier {
257            blur,
258            saturation,
259            opacity,
260        })
261    }
262
263    /// Apply a Gungnir (Neon Glow) effect to the view
264    fn gungnir(
265        self,
266        color: impl Into<String>,
267        radius: f32,
268        intensity: f32,
269    ) -> ModifiedView<Self, GungnirModifier> {
270        self.modifier(GungnirModifier {
271            color: color.into(),
272            radius,
273            intensity,
274        })
275    }
276
277    /// Apply a Mjolnir Slice (Geometric cut) to the view
278    fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
279        self.modifier(MjolnirSliceModifier { angle, offset })
280    }
281
282    /// Apply a Mjolnir Shatter (Fragmented transition) to the view
283    fn mjolnir_shatter(
284        self,
285        pieces: u32,
286        force: f32,
287    ) -> ModifiedView<Self, MjolnirShatterModifier> {
288        self.modifier(MjolnirShatterModifier { pieces, force })
289    }
290
291    /// Mark this view as a Bifrost Bridge (Shared Element) for cross-view persistence
292    fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
293        self.modifier(BifrostBridgeModifier { id: id.into() })
294    }
295
296    /// Add a background color to this view
297    fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
298        self.modifier(BackgroundModifier { color })
299    }
300
301    /// Add padding to this view
302    fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
303        self.modifier(PaddingModifier { amount })
304    }
305
306    /// Set the opacity (alpha) of this view in the range [0.0, 1.0].
307    fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
308        self.modifier(OpacityModifier {
309            opacity: opacity.clamp(0.0, 1.0),
310        })
311    }
312
313    /// Override the foreground (text / icon) color of this view.
314    fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
315        self.modifier(ForegroundColorModifier { color })
316    }
317
318    /// Constrain this view to an explicit width and/or height.
319    fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
320        self.modifier(FrameModifier { width, height })
321    }
322
323    /// Give this view a flex weight for proportional space distribution in stacks.
324    fn flex(self, weight: f32) -> ModifiedView<Self, FlexModifier> {
325        self.modifier(FlexModifier { weight })
326    }
327
328    /// Automatically add padding to avoid overlapping with platform safe areas (notches, bars).
329    fn safe_area_padding(self) -> ModifiedView<Self, SafeAreaModifier> {
330        self.modifier(SafeAreaModifier { ignores: false })
331    }
332
333    /// Explicitly ignore platform safe areas and draw into the margins.
334    fn ignores_safe_area(self) -> ModifiedView<Self, SafeAreaModifier> {
335        self.modifier(SafeAreaModifier { ignores: true })
336    }
337
338    /// Clip all child drawing to this view's bounds.
339    fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
340        self.modifier(ClipModifier)
341    }
342
343    /// Draw a colored border around this view.
344    fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
345        self.modifier(BorderModifier { color, width })
346    }
347
348    /// Add elevation (shadow) to the view. Level determines the shadow depth.
349    fn elevation(self, level: f32) -> ModifiedView<Self, ElevationModifier> {
350        self.modifier(ElevationModifier { level })
351    }
352
353    /// Trigger an action when the view appears
354    fn on_appear<F: Fn() + Send + Sync + 'static>(
355        self,
356        action: F,
357    ) -> ModifiedView<Self, LifecycleModifier> {
358        self.modifier(LifecycleModifier {
359            on_appear: Some(Arc::new(action)),
360            on_disappear: None,
361        })
362    }
363
364    /// Trigger an action when the view disappears
365    fn on_disappear<F: Fn() + Send + Sync + 'static>(
366        self,
367        action: F,
368    ) -> ModifiedView<Self, LifecycleModifier> {
369        self.modifier(LifecycleModifier {
370            on_appear: None,
371            on_disappear: Some(Arc::new(action)),
372        })
373    }
374
375    /// Trigger an action when the view is clicked
376    fn on_click<F: Fn() + Send + Sync + 'static>(
377        self,
378        action: F,
379    ) -> ModifiedView<Self, OnClickModifier> {
380        self.modifier(OnClickModifier {
381            action: Arc::new(action),
382        })
383    }
384
385    /// Trigger an action when the pointer enters the view bounds
386    fn on_pointer_enter<F: Fn() + Send + Sync + 'static>(
387        self,
388        action: F,
389    ) -> ModifiedView<Self, OnPointerEnterModifier> {
390        self.modifier(OnPointerEnterModifier {
391            action: Arc::new(action),
392        })
393    }
394
395    /// Trigger an action when the pointer leaves the view bounds
396    fn on_pointer_leave<F: Fn() + Send + Sync + 'static>(
397        self,
398        action: F,
399    ) -> ModifiedView<Self, OnPointerLeaveModifier> {
400        self.modifier(OnPointerLeaveModifier {
401            action: Arc::new(action),
402        })
403    }
404
405    /// Trigger an action when the pointer moves inside the view bounds
406    fn on_pointer_move<F: Fn(f32, f32) + Send + Sync + 'static>(
407        self,
408        action: F,
409    ) -> ModifiedView<Self, OnPointerMoveModifier> {
410        self.modifier(OnPointerMoveModifier {
411            action: Arc::new(action),
412        })
413    }
414
415    /// Trigger an action when the pointer is pressed down
416    fn on_pointer_down<F: Fn() + Send + Sync + 'static>(
417        self,
418        action: F,
419    ) -> ModifiedView<Self, OnPointerDownModifier> {
420        self.modifier(OnPointerDownModifier {
421            action: Arc::new(action),
422        })
423    }
424
425    /// Trigger an action when the pointer is released
426    fn on_pointer_up<F: Fn() + Send + Sync + 'static>(
427        self,
428        action: F,
429    ) -> ModifiedView<Self, OnPointerUpModifier> {
430        self.modifier(OnPointerUpModifier {
431            action: Arc::new(action),
432        })
433    }
434
435    /// Type-erase this view into AnyView
436    fn erase(self) -> AnyView
437    where
438        Self: 'static,
439    {
440        AnyView::new(self)
441    }
442}
443
444/// An object-safe version of the View trait for type erasure.
445pub trait ErasedView: Send {
446    fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect);
447    fn name(&self) -> &'static str;
448    fn flex_weight_erased(&self) -> f32;
449    fn layout_erased(&self) -> Option<&dyn layout::LayoutView>;
450}
451
452impl<V: View + 'static> ErasedView for V {
453    fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
454        self.render(renderer, rect);
455    }
456
457    fn name(&self) -> &'static str {
458        std::any::type_name::<V>()
459    }
460
461    fn flex_weight_erased(&self) -> f32 {
462        self.flex_weight()
463    }
464
465    fn layout_erased(&self) -> Option<&dyn layout::LayoutView> {
466        self.layout()
467    }
468}
469
470/// A type-erased View wrapper.
471pub struct AnyView {
472    inner: Box<dyn ErasedView>,
473}
474
475impl AnyView {
476    pub fn new<V: View + 'static>(view: V) -> Self {
477        Self {
478            inner: Box::new(view),
479        }
480    }
481}
482
483impl View for AnyView {
484    type Body = Never;
485    fn body(self) -> Self::Body {
486        unreachable!()
487    }
488
489    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
490        renderer.push_vnode(rect, self.inner.name());
491        self.inner.render_erased(renderer, rect);
492        renderer.pop_vnode();
493    }
494
495    fn flex_weight(&self) -> f32 {
496        self.inner.flex_weight_erased()
497    }
498
499    fn layout(&self) -> Option<&dyn layout::LayoutView> {
500        self.inner.layout_erased()
501    }
502}
503
504/// BifrostBridgeModifier enables shared-element transitions.
505/// When two views share the same Bifrost Bridge ID, the Sleipnir solver will
506/// interpolate their geometry and effects (blur, glow) during the transition.
507#[derive(Debug, Clone, PartialEq)]
508pub struct BifrostBridgeModifier {
509    pub id: String,
510}
511
512impl ViewModifier for BifrostBridgeModifier {
513    fn modify<V: View>(self, content: V) -> impl View {
514        ModifiedView::new(content, self)
515    }
516
517    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
518        // Register this element with the renderer for shared-element transition logic
519        renderer.register_shared_element(&self.id, rect);
520    }
521}
522
523/// MjolnirSliceModifier implements the "Geometric Slice" aesthetic.
524/// It uses a signed distance field (SDF) to clip the view along a sharp angled line.
525#[derive(Debug, Clone, Copy, PartialEq)]
526pub struct MjolnirSliceModifier {
527    pub angle: f32,
528    pub offset: f32,
529}
530
531impl ViewModifier for MjolnirSliceModifier {
532    fn modify<V: View>(self, content: V) -> impl View {
533        ModifiedView::new(content, self)
534    }
535
536    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
537        renderer.push_mjolnir_slice(self.angle, self.offset);
538    }
539
540    fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
541        renderer.pop_mjolnir_slice();
542    }
543}
544
545/// MjolnirShatterModifier implements the "Shattering" effect.
546/// It breaks the view into discrete geometric fragments that can be animated.
547#[derive(Debug, Clone, Copy, PartialEq)]
548pub struct MjolnirShatterModifier {
549    pub pieces: u32,
550    pub force: f32,
551}
552
553impl ViewModifier for MjolnirShatterModifier {
554    fn modify<V: View>(self, content: V) -> impl View {
555        ModifiedView::new(content, self)
556    }
557
558    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
559        // RADIAL SHATTER: Fragment the view into wedges
560        let pieces = self.pieces.max(1);
561        for i in 0..pieces {
562            let progress = i as f32 / pieces as f32;
563            let next_progress = (i + 1) as f32 / pieces as f32;
564
565            let angle_start = progress * 360.0;
566            let angle_end = next_progress * 360.0;
567
568            // Wedge slice: intersection of two half-planes
569            renderer.push_mjolnir_slice(angle_start, 0.0);
570            renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
571
572            // Apply radial force offset
573            let mid_angle = (angle_start + angle_end) / 2.0;
574            let rad = mid_angle.to_radians();
575            let dx = rad.cos() * self.force;
576            let dy = rad.sin() * self.force;
577
578            let shard_rect = Rect {
579                x: rect.x + dx,
580                y: rect.y + dy,
581                ..rect
582            };
583
584            view.render(renderer, shard_rect);
585
586            renderer.pop_mjolnir_slice();
587            renderer.pop_mjolnir_slice();
588        }
589    }
590}
591
592/// BifrostModifier implements the Cyberpunk "Frosted Glass" aesthetic.
593/// It triggers backdrop blurring and light scattering in the render pipeline.
594#[derive(Debug, Clone, Copy, PartialEq)]
595pub struct BifrostModifier {
596    pub blur: f32,
597    pub saturation: f32,
598    pub opacity: f32,
599}
600
601impl ViewModifier for BifrostModifier {
602    fn modify<V: View>(self, content: V) -> impl View {
603        ModifiedView::new(content, self)
604    }
605
606    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
607        renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
608    }
609}
610
611/// A modifier that adds a background color to a view.
612#[derive(Debug, Clone, Copy, PartialEq)]
613pub struct BackgroundModifier {
614    pub color: [f32; 4],
615}
616
617impl ViewModifier for BackgroundModifier {
618    fn modify<V: View>(self, content: V) -> impl View {
619        ModifiedView::new(content, self)
620    }
621
622    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
623        renderer.fill_rect(rect, self.color);
624    }
625}
626
627/// A modifier that adds padding to a view.
628#[derive(Debug, Clone, Copy, PartialEq)]
629pub struct PaddingModifier {
630    pub amount: f32,
631}
632
633impl ViewModifier for PaddingModifier {
634    fn modify<V: View>(self, content: V) -> impl View {
635        ModifiedView::new(content, self)
636    }
637
638    fn transform_rect(&self, rect: Rect) -> Rect {
639        Rect {
640            x: rect.x + self.amount,
641            y: rect.y + self.amount,
642            width: (rect.width - 2.0 * self.amount).max(0.0),
643            height: (rect.height - 2.0 * self.amount).max(0.0),
644        }
645    }
646
647    fn transform_proposal(&self, mut proposal: SizeProposal) -> SizeProposal {
648        if let Some(w) = proposal.width {
649            proposal.width = Some((w - 2.0 * self.amount).max(0.0));
650        }
651        if let Some(h) = proposal.height {
652            proposal.height = Some((h - 2.0 * self.amount).max(0.0));
653        }
654        proposal
655    }
656
657    fn transform_size(&self, mut size: Size) -> Size {
658        size.width += 2.0 * self.amount;
659        size.height += 2.0 * self.amount;
660        size
661    }
662}
663
664/// GungnirModifier implements the "Neon Glow" aesthetic.
665/// It uses additive blending and multi-pass blurring to simulate glowing light.
666#[derive(Debug, Clone, PartialEq)]
667pub struct GungnirModifier {
668    pub color: String,
669    pub radius: f32,
670    pub intensity: f32,
671}
672
673impl ViewModifier for GungnirModifier {
674    fn modify<V: View>(self, content: V) -> impl View {
675        ModifiedView::new(content, self)
676    }
677
678    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
679        // Neon Glow using Mode 1 in the Surtr pipeline
680        renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
681    }
682}
683
684/// GungnirPulseModifier implements a "breathing" neon effect.
685#[derive(Debug, Clone, Copy, PartialEq)]
686pub struct GungnirPulseModifier {
687    pub color: [f32; 4],
688    pub radius: f32,
689    pub speed: f32,
690}
691
692impl ViewModifier for GungnirPulseModifier {
693    fn modify<V: View>(self, content: V) -> impl View {
694        ModifiedView::new(content, self)
695    }
696
697    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
698        let time = std::time::SystemTime::now()
699            .duration_since(std::time::UNIX_EPOCH)
700            .unwrap_or_default()
701            .as_secs_f32();
702
703        // Mode 19: Dashed Border
704        // Mode 20: 9-Slice / Patch Scaling
705        let intensity = (time * self.speed).sin() * 0.5 + 0.5;
706        let mut color = self.color;
707        color[3] *= intensity;
708
709        // Mode 1 neon glow with dynamic intensity
710        renderer.stroke_rect(rect, color, self.radius);
711    }
712}
713
714/// Sleipnir spring parameters for the physics solver
715#[derive(Debug, Clone, Copy, PartialEq)]
716pub struct SleipnirParams {
717    pub stiffness: f32,
718    pub damping: f32,
719    pub mass: f32,
720}
721
722impl SleipnirParams {
723    pub fn snappy() -> Self { Self { stiffness: 230.0, damping: 22.0, mass: 1.0 } }
724    pub fn fluid() -> Self { Self { stiffness: 170.0, damping: 26.0, mass: 1.0 } }
725    pub fn heavy() -> Self { Self { stiffness: 90.0, damping: 20.0, mass: 1.0 } }
726    pub fn bouncy() -> Self { Self { stiffness: 190.0, damping: 14.0, mass: 1.0 } }
727}
728
729impl Default for SleipnirParams {
730    fn default() -> Self { Self::fluid() }
731}
732
733#[derive(Debug, Clone, Copy, PartialEq)]
734struct SolverState {
735    x: f32,
736    v: f32,
737}
738
739/// SleipnirSolver implements a 4th-order Runge-Kutta (RK4) integration for springs.
740/// This provides superior stability for high-fidelity interactive motion.
741#[derive(Debug, Clone, Copy, PartialEq)]
742pub struct SleipnirSolver {
743    params: SleipnirParams,
744    target: f32,
745    state: SolverState,
746}
747
748impl SleipnirSolver {
749    /// Create a new solver with a target value and starting state.
750    pub fn new(params: SleipnirParams, target: f32, current: f32) -> Self {
751        Self {
752            params,
753            target,
754            state: SolverState { x: current, v: 0.0 },
755        }
756    }
757
758    /// Advance the simulation by dt seconds using RK4 integration.
759    pub fn tick(&mut self, dt: f32) -> f32 {
760        if dt <= 0.0 { return self.state.x; }
761        
762        // Use a fixed time step for stability if dt is too large
763        let mut remaining = dt;
764        let step = 1.0 / 120.0;
765        
766        while remaining > 0.0 {
767            let d = remaining.min(step);
768            self.step(d);
769            remaining -= d;
770        }
771        
772        self.state.x
773    }
774
775    fn step(&mut self, dt: f32) {
776        let a = self.evaluate(self.state, 0.0, SolverState { x: 0.0, v: 0.0 });
777        let b = self.evaluate(self.state, dt * 0.5, a);
778        let c = self.evaluate(self.state, dt * 0.5, b);
779        let d = self.evaluate(self.state, dt, c);
780
781        let dxdt = 1.0 / 6.0 * (a.x + 2.0 * (b.x + c.x) + d.x);
782        let dvdt = 1.0 / 6.0 * (a.v + 2.0 * (b.v + c.v) + d.v);
783
784        self.state.x += dxdt * dt;
785        self.state.v += dvdt * dt;
786    }
787
788    fn evaluate(&self, initial: SolverState, dt: f32, d: SolverState) -> SolverState {
789        let state = SolverState {
790            x: initial.x + d.x * dt,
791            v: initial.v + d.v * dt,
792        };
793        let force = -self.params.stiffness * (state.x - self.target) - self.params.damping * state.v;
794        let mass = self.params.mass.max(0.001);
795        SolverState { x: state.v, v: force / mass }
796    }
797
798    pub fn is_settled(&self) -> bool {
799        (self.state.x - self.target).abs() < 0.001 && self.state.v.abs() < 0.001
800    }
801
802    pub fn set_target(&mut self, target: f32) {
803        self.target = target;
804    }
805
806    pub fn current_value(&self) -> f32 {
807        self.state.x
808    }
809}
810
811/// SleipnirModifier handles physics-based animations via the Sleipnir RK4 solver.
812#[derive(Debug, Clone, PartialEq)]
813pub struct SleipnirModifier {
814    pub id: u64,
815    pub target: f32,
816    pub params: SleipnirParams,
817}
818
819impl ViewModifier for SleipnirModifier {
820    fn modify<V: View>(self, content: V) -> impl View {
821        ModifiedView::new(content, self)
822    }
823
824    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
825        let state = load_system_state();
826        
827        // Try to fetch the solver from persistent state.
828        let solver_lock_opt = state.get_component_state::<SleipnirSolver>(self.id);
829        
830        let current_val;
831        
832        if let Some(lock) = solver_lock_opt {
833            // Found a solver. Tick it.
834            let mut solver = lock.write().unwrap();
835            solver.set_target(self.target);
836            current_val = solver.tick(renderer.delta_time());
837            
838            // If the solver hasn't settled yet, request another frame.
839            if !solver.is_settled() {
840                renderer.request_redraw();
841            }
842        } else {
843            // First time seeing this ID. Initialize solver state.
844            let solver = SleipnirSolver::new(
845                self.params,
846                self.target,
847                self.target // Initialize at target to avoid jump on first frame
848            );
849            
850            // Insert into registry for next frame.
851            get_system_state().rcu(|old| {
852                let mut new_state = (**old).clone();
853                new_state.set_component_state(self.id, solver);
854                new_state
855            });
856            
857            current_val = self.target;
858        }
859
860        // Apply the solved value as a vertical translation.
861        renderer.push_transform([0.0, current_val], [1.0, 1.0], 0.0);
862        view.render(renderer, rect);
863        renderer.pop_transform();
864    }
865}
866
867/// TransformModifier applies a 2D transform (translation, scale, rotation) to its child.
868/// This modifier is "layout-neutral" and can be animated without re-running the layout engine.
869#[derive(Debug, Clone, Copy, PartialEq)]
870pub struct TransformModifier {
871    pub translation: [f32; 2],
872    pub scale: [f32; 2],
873    pub rotation: f32,
874}
875
876impl Default for TransformModifier {
877    fn default() -> Self {
878        Self::new()
879    }
880}
881
882impl TransformModifier {
883    pub fn new() -> Self {
884        Self {
885            translation: [0.0, 0.0],
886            scale: [1.0, 1.0],
887            rotation: 0.0,
888        }
889    }
890
891    pub fn translate(mut self, x: f32, y: f32) -> Self {
892        self.translation = [x, y];
893        self
894    }
895
896    pub fn scale(mut self, x: f32, y: f32) -> Self {
897        self.scale = [x, y];
898        self
899    }
900
901    pub fn rotate(mut self, radians: f32) -> Self {
902        self.rotation = radians;
903        self
904    }
905}
906
907impl ViewModifier for TransformModifier {
908    fn modify<V: View>(self, content: V) -> impl View {
909        ModifiedView::new(content, self)
910    }
911
912    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
913        renderer.push_transform(self.translation, self.scale, self.rotation);
914        view.render(renderer, rect);
915        renderer.pop_transform();
916    }
917}
918
919/// LifecycleModifier handles on_appear and on_disappear hooks.
920
921#[derive(Clone)]
922pub struct LifecycleModifier {
923    pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
924    pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
925}
926
927impl ViewModifier for LifecycleModifier {
928    fn modify<V: View>(self, content: V) -> impl View {
929        ModifiedView::new(content, self)
930    }
931}
932
933/// OpacityModifier fades this view and all its descendants to the given alpha.
934/// The renderer is expected to honour `push_opacity`/`pop_opacity` on the Renderer trait.
935#[derive(Debug, Clone, Copy, PartialEq)]
936pub struct OpacityModifier {
937    pub opacity: f32,
938}
939
940impl ViewModifier for OpacityModifier {
941    fn modify<V: View>(self, content: V) -> impl View {
942        ModifiedView::new(content, self)
943    }
944
945    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
946        renderer.push_opacity(self.opacity);
947    }
948
949    fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
950        renderer.pop_opacity();
951    }
952}
953
954/// OnClickModifier registers a click handler for this view.
955#[derive(Clone)]
956pub struct OnClickModifier {
957    pub action: Arc<dyn Fn() + Send + Sync>,
958}
959
960impl ViewModifier for OnClickModifier {
961    fn modify<V: View>(self, content: V) -> impl View {
962        ModifiedView::new(content, self)
963    }
964
965    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
966        let action = self.action.clone();
967        renderer.register_handler(
968            "pointerclick",
969            std::sync::Arc::new(move |event| {
970                if let Event::PointerClick { .. } = event {
971                    (action)();
972                }
973            }),
974        );
975    }
976}
977
978/// OnPointerEnterModifier registers a pointer enter handler.
979#[derive(Clone)]
980pub struct OnPointerEnterModifier {
981    pub action: Arc<dyn Fn() + Send + Sync>,
982}
983
984impl ViewModifier for OnPointerEnterModifier {
985    fn modify<V: View>(self, content: V) -> impl View {
986        ModifiedView::new(content, self)
987    }
988
989    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
990        let action = self.action.clone();
991        renderer.register_handler(
992            "pointerenter",
993            std::sync::Arc::new(move |event| {
994                if let Event::PointerEnter = event {
995                    (action)();
996                }
997            }),
998        );
999    }
1000}
1001
1002/// OnPointerLeaveModifier registers a pointer leave handler.
1003#[derive(Clone)]
1004pub struct OnPointerLeaveModifier {
1005    pub action: Arc<dyn Fn() + Send + Sync>,
1006}
1007
1008impl ViewModifier for OnPointerLeaveModifier {
1009    fn modify<V: View>(self, content: V) -> impl View {
1010        ModifiedView::new(content, self)
1011    }
1012
1013    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1014        let action = self.action.clone();
1015        renderer.register_handler(
1016            "pointerleave",
1017            std::sync::Arc::new(move |event| {
1018                if let Event::PointerLeave = event {
1019                    (action)();
1020                }
1021            }),
1022        );
1023    }
1024}
1025
1026/// OnPointerMoveModifier registers a pointer move handler.
1027#[derive(Clone)]
1028pub struct OnPointerMoveModifier {
1029    pub action: Arc<dyn Fn(f32, f32) + Send + Sync>,
1030}
1031
1032impl ViewModifier for OnPointerMoveModifier {
1033    fn modify<V: View>(self, content: V) -> impl View {
1034        ModifiedView::new(content, self)
1035    }
1036
1037    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1038        let action = self.action.clone();
1039        renderer.register_handler(
1040            "pointermove",
1041            std::sync::Arc::new(move |event| {
1042                if let Event::PointerMove { x, y } = event {
1043                    (action)(x, y);
1044                }
1045            }),
1046        );
1047    }
1048}
1049
1050/// OnPointerDownModifier registers a pointer down handler.
1051#[derive(Clone)]
1052pub struct OnPointerDownModifier {
1053    pub action: Arc<dyn Fn() + Send + Sync>,
1054}
1055
1056impl ViewModifier for OnPointerDownModifier {
1057    fn modify<V: View>(self, content: V) -> impl View {
1058        ModifiedView::new(content, self)
1059    }
1060
1061    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1062        let action = self.action.clone();
1063        renderer.register_handler(
1064            "pointerdown",
1065            std::sync::Arc::new(move |event| {
1066                if let Event::PointerDown { .. } = event {
1067                    (action)();
1068                }
1069            }),
1070        );
1071    }
1072}
1073
1074/// OnPointerUpModifier registers a pointer up handler.
1075#[derive(Clone)]
1076pub struct OnPointerUpModifier {
1077    pub action: Arc<dyn Fn() + Send + Sync>,
1078}
1079
1080impl ViewModifier for OnPointerUpModifier {
1081    fn modify<V: View>(self, content: V) -> impl View {
1082        ModifiedView::new(content, self)
1083    }
1084
1085    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1086        let action = self.action.clone();
1087        renderer.register_handler(
1088            "pointerup",
1089            std::sync::Arc::new(move |event| {
1090                if let Event::PointerUp { .. } = event {
1091                    (action)();
1092                }
1093            }),
1094        );
1095    }
1096}
1097
1098/// ForegroundColorModifier overrides the foreground (text / icon) color inherited
1099/// by all descendants until another ForegroundColorModifier is encountered.
1100#[derive(Debug, Clone, Copy, PartialEq)]
1101pub struct ForegroundColorModifier {
1102    pub color: [f32; 4],
1103}
1104
1105impl ViewModifier for ForegroundColorModifier {
1106    fn modify<V: View>(self, content: V) -> impl View {
1107        ModifiedView::new(content, self)
1108    }
1109}
1110
1111/// ClipModifier restricts all child drawing to the view's layout rectangle.
1112/// The renderer must support `push_clip_rect`/`pop_clip_rect`.
1113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1114pub struct ClipModifier;
1115
1116impl ViewModifier for ClipModifier {
1117    fn modify<V: View>(self, content: V) -> impl View {
1118        ModifiedView::new(content, self)
1119    }
1120
1121    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1122        renderer.push_clip_rect(rect);
1123    }
1124
1125    fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1126        renderer.pop_clip_rect();
1127    }
1128}
1129
1130/// BorderModifier draws a solid-color border around the view bounds.
1131#[derive(Debug, Clone, Copy, PartialEq)]
1132pub struct BorderModifier {
1133    pub color: [f32; 4],
1134    pub width: f32,
1135}
1136
1137impl ViewModifier for BorderModifier {
1138    fn modify<V: View>(self, content: V) -> impl View {
1139        ModifiedView::new(content, self)
1140    }
1141
1142    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1143        renderer.stroke_rect(rect, self.color, self.width);
1144    }
1145}
1146
1147// Primitive (leaf) views implement Never as body
1148#[doc(hidden)]
1149pub enum Never {}
1150
1151impl View for Never {
1152    type Body = Never;
1153    fn body(self) -> Never {
1154        unreachable!()
1155    }
1156}
1157
1158/// A view that has been transformed by a modifier.
1159///
1160/// Section 4.3: "Each modifier implements ViewModifier and produces a ModifiedView<Inner, Self>."
1161pub struct ModifiedView<V, M> {
1162    view: V,
1163    modifier: M,
1164}
1165
1166impl<V: View, M: ViewModifier> ModifiedView<V, M> {
1167    #[doc(hidden)]
1168    pub fn new(view: V, modifier: M) -> Self {
1169        Self { view, modifier }
1170    }
1171}
1172
1173impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
1174    type Body = ModifiedView<V::Body, M>;
1175
1176    fn body(self) -> Self::Body {
1177        ModifiedView {
1178            view: self.view.body(),
1179            modifier: self.modifier.clone(),
1180        }
1181    }
1182
1183    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1184        self.modifier.render_view(&self.view, renderer, rect);
1185    }
1186
1187    fn intrinsic_size(&self, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1188        self.modifier.measure_view(&self.view, renderer, proposal)
1189    }
1190
1191    fn flex_weight(&self) -> f32 {
1192        self.modifier.child_flex_weight(&self.view)
1193    }
1194
1195    fn layout(&self) -> Option<&dyn layout::LayoutView> {
1196        self.modifier.layout().or_else(|| self.view.layout())
1197    }
1198}
1199
1200pub trait ViewModifier: Send + Clone {
1201    fn modify<V: View>(self, content: V) -> impl View;
1202
1203    /// Core rendering hook called before child views.
1204    fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1205
1206    /// Cleanup hook called after child views.
1207    fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1208
1209    /// Allows a modifier to completely override or wrap the rendering of its child.
1210    /// Default implementation performs a standard push -> transform -> render child -> pop sequence.
1211    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1212        self.render(renderer, rect);
1213        let child_rect = self.transform_rect(rect);
1214        view.render(renderer, child_rect);
1215        self.post_render(renderer, rect);
1216    }
1217
1218    fn transform_rect(&self, rect: Rect) -> Rect {
1219        rect
1220    }
1221
1222    /// Allows a modifier to transform the layout proposal before it reaches the child.
1223    fn transform_proposal(&self, proposal: SizeProposal) -> SizeProposal {
1224        proposal
1225    }
1226
1227    /// Allows a modifier to transform the resulting size from the child.
1228    fn transform_size(&self, size: Size) -> Size {
1229        size
1230    }
1231
1232    /// Measure hook that coordinates size propagation.
1233    fn measure_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1234        let child_proposal = self.transform_proposal(proposal);
1235        let child_size = view.intrinsic_size(renderer, child_proposal);
1236        self.transform_size(child_size)
1237    }
1238
1239    /// Allows a modifier to override or pass through the child's flex weight.
1240    fn child_flex_weight<V: View>(&self, view: &V) -> f32 {
1241        view.flex_weight()
1242    }
1243
1244    fn layout(&self) -> Option<&dyn layout::LayoutView> {
1245        None
1246    }
1247}
1248
1249/// TelemetryData tracks real-time performance metrics for the GPU renderer.
1250#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1251pub struct TelemetryData {
1252    pub frame_time_ms: f32,
1253    
1254    // Pass timing
1255    pub input_time_ms: f32,
1256    pub state_flush_time_ms: f32,
1257    pub layout_time_ms: f32,
1258    pub draw_time_ms: f32,
1259    pub gpu_submit_time_ms: f32,
1260    
1261    pub draw_calls: u32,
1262    pub vertices: u32,
1263    
1264    // Memory breakdown
1265    pub vram_usage_mb: f32,
1266    pub vram_textures_mb: f32,
1267    pub vram_buffers_mb: f32,
1268    pub vram_pipelines_mb: f32,
1269}
1270
1271/// Configuration for render-loop frame timing and degradation strategies.
1272#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1273pub struct FrameBudget {
1274    /// Target frame time in milliseconds (default: 16.0 for 60FPS)
1275    pub target_ms: f32,
1276    /// If true, the renderer is allowed to dynamically skip non-critical effects
1277    /// (like heavy blurs or complex shadows) when the budget is exceeded.
1278    pub allow_degradation: bool,
1279}
1280
1281impl Default for FrameBudget {
1282    fn default() -> Self {
1283        Self {
1284            target_ms: 16.0,
1285            allow_degradation: true,
1286        }
1287    }
1288}
1289
1290/// The Renderer trait defines the atomic drawing operations for all CVKG backends.
1291/// This trait is object-safe and used by the View::render system.
1292///
1293/// # Implementation Requirements
1294/// 1. Coordinate system is origin-top-left (0,0) with Y increasing downwards.
1295/// 2. Colors are [R, G, B, A] in the [0.0, 1.0] range.
1296/// 3. All operations must be batchable by the underlying backend.
1297/// Trait providing timing information for the render loop.
1298pub trait ElapsedTime {
1299    /// Returns the cumulative time since the renderer started in seconds.
1300    fn elapsed_time(&self) -> f32;
1301    
1302    /// Returns the time elapsed since the last frame in seconds.
1303    fn delta_time(&self) -> f32;
1304}
1305
1306/// The Renderer trait defines the atomic drawing operations for all CVKG backends.
1307/// This trait is object-safe and used by the View::render system.
1308///
1309/// # Implementation Requirements
1310/// 1. Coordinate system is origin-top-left (0,0) with Y increasing downwards.
1311/// 2. Colors are [R, G, B, A] in the [0.0, 1.0] range.
1312/// 3. All operations must be batchable by the underlying backend.
1313pub trait Renderer: ElapsedTime + Send {
1314    /// Requests that the renderer redraws as soon as possible.
1315    /// Used for continuous animations.
1316    fn request_redraw(&mut self) {}
1317
1318    // ── Filled shapes ────────────────────────────────────────────────────
1319    fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
1320    fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
1321    /// Fill an ellipse/circle that fits inside `rect`.
1322    fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
1323
1324    // ── Stroked shapes ───────────────────────────────────────────────────
1325    fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1326    fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
1327    /// Stroke an ellipse/circle that fits inside `rect`.
1328    fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1329    /// Draw a straight line from (x1,y1) to (x2,y2).
1330    fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
1331    /// Fill a polygon defined by a set of vertices.
1332    fn fill_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4]) {}
1333    /// Stroke a polygon defined by a set of vertices.
1334    fn stroke_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4], _stroke_width: f32) {}
1335
1336    // ── Text ─────────────────────────────────────────────────────────────
1337    fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
1338    /// Measure the width and height of the specified text.
1339    fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
1340
1341    // ── Images & textures ────────────────────────────────────────────────
1342    /// Draw a texture (GPU-side) at the specified rect.
1343    fn draw_texture(&mut self, _texture_id: u32, _rect: Rect) {}
1344    /// Draw an image asset by name or path.
1345    fn draw_image(&mut self, _image_name: &str, _rect: Rect) {}
1346    /// Load an image asset from memory.
1347    fn load_image(&mut self, _name: &str, _data: &[u8]) {}
1348
1349    // ── Data Visualization ───────────────────────────────────────────────
1350    /// Upload raw float data as a GPU texture for heatmap rendering.
1351    fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
1352    /// Draw a heatmap using a previously uploaded data texture.
1353    fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
1354
1355    // ── 3D Objects ───────────────────────────────────────────────────────
1356    /// Draw a 3D mesh.
1357    fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
1358
1359    // ── Advanced Visual Effects ──────────────────────────────────────────
1360    /// Draw a linear gradient between two colors at the specified angle.
1361    fn draw_linear_gradient(
1362        &mut self,
1363        _rect: Rect,
1364        _start_color: [f32; 4],
1365        _end_color: [f32; 4],
1366        _angle: f32,
1367    ) {
1368    }
1369    /// Draw a radial gradient between two colors.
1370    fn draw_radial_gradient(
1371        &mut self,
1372        _rect: Rect,
1373        _inner_color: [f32; 4],
1374        _outer_color: [f32; 4],
1375    ) {
1376    }
1377    /// Draw a high-fidelity drop shadow for a rounded rectangle.
1378    fn draw_drop_shadow(
1379        &mut self,
1380        _rect: Rect,
1381        _radius: f32,
1382        _color: [f32; 4],
1383        _blur: f32,
1384        _spread: f32,
1385    ) {
1386    }
1387    /// Draw a dashed border for a rounded rectangle.
1388    fn stroke_dashed_rounded_rect(
1389        &mut self,
1390        _rect: Rect,
1391        _radius: f32,
1392        _color: [f32; 4],
1393        _width: f32,
1394        _dash: f32,
1395        _gap: f32,
1396    ) {
1397    }
1398    /// Draw a 9-slice / patch scaled image.
1399    fn draw_9slice(
1400        &mut self,
1401        _image_name: &str,
1402        _rect: Rect,
1403        _left: f32,
1404        _top: f32,
1405        _right: f32,
1406        _bottom: f32,
1407    ) {
1408    }
1409
1410    // ── Clipping ─────────────────────────────────────────────────────────
1411    /// Push a clip rectangle.  All subsequent drawing is clipped to `rect`.
1412    /// Implementations that do not support clipping may ignore this call.
1413    fn push_clip_rect(&mut self, _rect: Rect) {}
1414    /// Pop the most recently pushed clip rectangle.
1415    fn pop_clip_rect(&mut self) {}
1416
1417    // ── Global opacity ───────────────────────────────────────────────────
1418    /// Set a global opacity multiplier applied to all subsequent draw calls
1419    /// until `pop_opacity` is called.  `opacity` is in [0.0, 1.0].
1420    fn push_opacity(&mut self, _opacity: f32) {}
1421    /// Restore the previous opacity level.
1422    fn pop_opacity(&mut self) {}
1423
1424    // ── Berserker Pipeline State ─────────────────────────────────────────
1425    fn set_theme(&mut self, _theme: ColorTheme) {}
1426    fn set_rage(&mut self, _rage: f32) {}
1427    fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
1428
1429    // ── Cyberpunk Effects ────────────────────────────────────────────────
1430    /// Apply a Bifrost (Frosted Glass) effect to the specified rect.
1431    fn bifrost(&mut self, _rect: Rect, _blur: f32, _saturation: f32, _opacity: f32) {}
1432    /// Apply a Gungnir (Neon Glow) effect to the specified rect.
1433    fn gungnir(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32, _intensity: f32) {}
1434    /// Push a Mjolnir Slice (geometric clipping).
1435    fn push_mjolnir_slice(&mut self, _angle: f32, _offset: f32) {}
1436    fn pop_mjolnir_slice(&mut self) {}
1437    /// Apply a Mjolnir Shatter effect (fragmentation) to the specified rect.
1438    fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1439    fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
1440    /// Draw a Mjolnir Bolt (lightning strike) between two points.
1441    fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
1442
1443    // ── Accessibility (ShieldWall) ───────────────────────────────────────
1444    fn set_aria_role(&mut self, _role: &str) {}
1445    fn set_aria_label(&mut self, _label: &str) {}
1446
1447    /// Register a shared element for Bifrost Bridge transitions.
1448    fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
1449
1450    /// Set a unique key for the current VDOM node to ensure stable identity during diffing.
1451    fn set_key(&mut self, _key: &str) {}
1452
1453    // ── Telemetry ────────────────────────────────────────────────────────
1454    /// Get real-time performance telemetry.
1455    fn get_telemetry(&self) -> TelemetryData {
1456        TelemetryData::default()
1457    }
1458
1459    // ── GPU State Management ─────────────────────────────────────────────
1460    /// Push a shadow state to the stack. All following draw calls will have this shadow.
1461    fn push_shadow(&mut self, _radius: f32, _color: [f32; 4], _offset: [f32; 2]) {}
1462    /// Pop the last shadow state from the stack.
1463    fn pop_shadow(&mut self) {}
1464
1465    // ── VDOM & Scene Graph ───────────────────────────────────────────────
1466    /// Push a Virtual DOM node onto the stack for hierarchy tracking.
1467    fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
1468    /// Pop the current Virtual DOM node from the stack.
1469    fn pop_vnode(&mut self) {}
1470    /// Register an event handler for the current VDOM node.
1471    fn register_handler(
1472        &mut self,
1473        _event_type: &str,
1474        _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
1475    ) {
1476    }
1477
1478    // ── Z-Index & Depth ──────────────────────────────────────────────────
1479    /// Set the current Z-index for depth sorting.
1480    /// Higher values appear closer to the viewer.
1481    fn set_z_index(&mut self, _z: f32) {}
1482    /// Get the current Z-index.
1483    fn get_z_index(&self) -> f32 {
1484        0.0
1485    }
1486
1487    // ── Vector Graphics ──────────────────────────────────────────────────
1488    /// Load an SVG model from raw bytes.
1489    fn load_svg(&mut self, _name: &str, _svg_data: &[u8]) {}
1490    /// Draw a pre-loaded SVG model.
1491    fn draw_svg(&mut self, _name: &str, _rect: Rect) {}
1492
1493    // ── GPU Transformations ──────────────────────────────────────────────
1494    /// Push a 2D transform (translation, scale, rotation) onto the stack.
1495    /// This transform should be applied to all subsequent draw calls until popped.
1496    /// Transform-only animations use this to avoid re-triggering the layout engine.
1497    fn push_transform(&mut self, _translation: [f32; 2], _scale: [f32; 2], _rotation: f32) {}
1498    /// Pop the last 2D transform from the stack.
1499    fn pop_transform(&mut self) {}
1500    /// Return the resolved layout bounds for a specific node ID if it exists.
1501    fn query_layout(&self, _node_id: scene_graph::NodeId) -> Option<Rect> {
1502        None
1503    }
1504    /// Enable or disable the layout debug overlay (bounds, padding, margin).
1505    fn set_debug_layout(&mut self, _enabled: bool) {}
1506    /// Check if the layout debug overlay is currently enabled.
1507    fn get_debug_layout(&self) -> bool {
1508        false
1509    }
1510}
1511/// Defines the hardware acceleration tier and feature set available to the renderer.
1512#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
1513pub enum RenderTier {
1514    /// High-performance GPU path (WebGPU / Vulkan / Metal / DX12) with full shader support.
1515    Tier1GPU = 0,
1516    /// Mid-tier GPU path (WebGL2 / OpenGL 3.3) with standard shader support.
1517    Tier2GPU = 1,
1518    /// Fallback software or basic hardware path (Canvas 2D / GDI+) with limited effects.
1519    Tier3Fallback = 2,
1520}
1521// =============================================================================
1522// BERSERKER UNIFORMS
1523// =============================================================================
1524use bytemuck::{Pod, Zeroable};
1525/// Fully themeable color palette for the Berserker pipeline.
1526#[repr(C)]
1527#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1528pub struct ColorTheme {
1529    pub primary_neon: [f32; 4], // (R, G, B, intensity)
1530    pub shatter_neon: [f32; 4],
1531    pub glass_base: [f32; 4],
1532    pub glass_edge: [f32; 4],
1533    pub rune_glow: [f32; 4],
1534    pub ember_core: [f32; 4],
1535    pub background_deep: [f32; 4],
1536    pub glass_blur_strength: f32,
1537    pub shatter_edge_width: f32,
1538    pub neon_bloom_radius: f32,
1539    pub rune_opacity: f32, // 0.0–1.0, default 0.55
1540    // Padding to ensure 16-byte alignment for GPU uniforms
1541    pub _pad: [f32; 3], // align to 16 bytes
1542    pub _pad2: f32,
1543}
1544impl ColorTheme {
1545    pub fn cyberpunk_viking() -> Self {
1546        Self {
1547            primary_neon: [0.0, 1.0, 0.95, 1.2],
1548            shatter_neon: [1.0, 0.0, 0.75, 1.5],
1549            glass_base: [0.04, 0.04, 0.06, 0.82],
1550            glass_edge: [0.0, 0.45, 0.55, 0.6],
1551            rune_glow: [0.75, 0.98, 1.0, 0.9],
1552            ember_core: [0.95, 0.12, 0.12, 1.0],
1553            background_deep: [0.01, 0.01, 0.03, 1.0],
1554            glass_blur_strength: 0.6,
1555            shatter_edge_width: 1.8,
1556            neon_bloom_radius: 0.022,
1557            rune_opacity: 0.55,
1558            _pad: [0.0; 3],
1559            _pad2: 0.0,
1560        }
1561    }
1562    pub fn vibrant_glass() -> Self {
1563        Self {
1564            primary_neon: [0.0, 1.0, 0.95, 1.2],
1565            shatter_neon: [1.0, 0.0, 0.75, 1.5],
1566            glass_base: [0.55, 0.6, 0.7, 0.08], // Luminous cool tint
1567            glass_edge: [0.7, 0.85, 1.0, 0.45], // Subtle blue-white rim
1568            rune_glow: [0.75, 0.98, 1.0, 0.9],
1569            ember_core: [1.0, 0.4, 0.1, 1.0],
1570            background_deep: [0.05, 0.05, 0.1, 1.0],
1571            glass_blur_strength: 0.9,
1572            shatter_edge_width: 1.8,
1573            neon_bloom_radius: 0.022,
1574            rune_opacity: 0.55,
1575            _pad: [0.0; 3],
1576            _pad2: 0.0,
1577        }
1578    }
1579}
1580impl Default for ColorTheme {
1581    fn default() -> Self {
1582        Self::vibrant_glass()
1583    }
1584}
1585/// Per-frame scene state for the Berserker pipeline.
1586#[repr(C)]
1587#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
1588pub struct SceneUniforms {
1589    pub view: glam::Mat4,
1590    pub proj: glam::Mat4,
1591    pub time: f32,
1592    pub delta_time: f32,
1593    pub resolution: [f32; 2],
1594    pub mouse: [f32; 2],
1595    pub mouse_velocity: [f32; 2],
1596    pub shatter_origin: [f32; 2],
1597    pub shatter_time: f32,
1598    pub shatter_force: f32,
1599    pub berzerker_rage: f32,
1600    pub scroll_offset: f32,
1601    pub scale_factor: f32,
1602    // Padding to ensure 16-byte alignment for GPU uniforms (47 f32s + 1 = 48)
1603    pub _pad: [f32; 1],
1604}
1605impl SceneUniforms {
1606    pub fn new(width: f32, height: f32) -> Self {
1607        Self {
1608            view: glam::Mat4::IDENTITY,
1609            proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
1610            time: 0.0,
1611            delta_time: 0.016,
1612            resolution: [width, height],
1613            mouse: [0.5, 0.5],
1614            mouse_velocity: [0.0, 0.0],
1615            shatter_origin: [0.5, 0.5],
1616            shatter_time: -100.0,
1617            shatter_force: 0.0,
1618            berzerker_rage: 0.0,
1619            scroll_offset: 0.0,
1620            scale_factor: 1.0,
1621            _pad: [0.0; 1],
1622        }
1623    }
1624}
1625/// A 3D mesh containing vertex and index data.
1626#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1627pub struct Mesh {
1628    pub vertices: Vec<[f32; 3]>,
1629    pub normals: Vec<[f32; 3]>,
1630    pub indices: Vec<u32>,
1631}
1632impl Mesh {
1633    pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
1634        let mut cursor = std::io::Cursor::new(data);
1635        let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
1636            Ok((Vec::new(), Default::default()))
1637        })?;
1638        let mut meshes = Vec::new();
1639        for m in models {
1640            let mesh = m.mesh;
1641            let vertices: Vec<[f32; 3]> = mesh
1642                .positions
1643                .chunks(3)
1644                .map(|c| [c[0], c[1], c[2]])
1645                .collect();
1646            let normals = if mesh.normals.is_empty() {
1647                vec![[0.0, 0.0, 1.0]; vertices.len()]
1648            } else {
1649                mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
1650            };
1651            meshes.push(Mesh {
1652                vertices,
1653                normals,
1654                indices: mesh.indices,
1655            });
1656        }
1657        Ok(meshes)
1658    }
1659    pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
1660        let mut cursor = std::io::Cursor::new(data);
1661        let stl = stl_io::read_stl(&mut cursor)?;
1662        let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
1663        let mut indices = Vec::new();
1664        for face in stl.faces {
1665            indices.push(face.vertices[0] as u32);
1666            indices.push(face.vertices[1] as u32);
1667            indices.push(face.vertices[2] as u32);
1668        }
1669        let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
1670        Ok(Mesh {
1671            vertices,
1672            normals,
1673            indices,
1674        })
1675    }
1676}
1677/// FrameRenderer extends Renderer with frame lifecycle management.
1678/// It is typically implemented by the host windowing/rendering environment.
1679pub trait FrameRenderer<E = ()>: Renderer {
1680    fn begin_frame(&mut self) -> E;
1681    fn render_frame(&mut self) {
1682        // Default implementation does nothing - override for custom frame rendering
1683    }
1684    fn end_frame(&mut self, encoder: E);
1685}
1686use std::sync::Arc;
1687/// State wrapper that owns a value and notifies subscribers when changed
1688#[derive(Clone)]
1689pub struct State<T: Clone + Send + Sync + 'static> {
1690    swap: Arc<arc_swap::ArcSwap<T>>,
1691    metadata_swap: Arc<arc_swap::ArcSwap<Option<agents::MutationMetadata>>>,
1692    #[cfg(not(target_arch = "wasm32"))]
1693    tvar: Arc<stm::TVar<T>>,
1694    #[cfg(not(target_arch = "wasm32"))]
1695    metadata_tvar: Arc<stm::TVar<Option<agents::MutationMetadata>>>,
1696    subscribers: Arc<std::sync::Mutex<Vec<Box<dyn Fn(&T) + Send + Sync>>>>,
1697    version: Arc<std::sync::atomic::AtomicU64>,
1698    resolution: agents::ConflictResolution,
1699}
1700impl<T: Clone + Send + Sync + 'static> State<T> {
1701    /// Create a new State with initial value
1702    pub fn new(value: T) -> Self {
1703        #[cfg(not(target_arch = "wasm32"))]
1704        let tvar = Arc::new(stm::TVar::new(value.clone()));
1705        #[cfg(not(target_arch = "wasm32"))]
1706        let metadata_tvar = Arc::new(stm::TVar::new(None));
1707        Self {
1708            swap: Arc::new(arc_swap::ArcSwap::from_pointee(value)),
1709            metadata_swap: Arc::new(arc_swap::ArcSwap::new(Arc::new(None))),
1710            #[cfg(not(target_arch = "wasm32"))]
1711            tvar,
1712            #[cfg(not(target_arch = "wasm32"))]
1713            metadata_tvar,
1714            subscribers: Arc::new(std::sync::Mutex::new(Vec::new())),
1715            version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
1716            resolution: agents::ConflictResolution::default(),
1717        }
1718    }
1719    /// Set the conflict resolution strategy for this state.
1720    pub fn with_resolution(mut self, resolution: agents::ConflictResolution) -> Self {
1721        self.resolution = resolution;
1722        self
1723    }
1724    /// Get the current value
1725    pub fn get(&self) -> T {
1726        (**self.swap.load()).clone()
1727    }
1728    /// Set a new value, notifying all subscribers. Applies conflict resolution if agents are present.
1729    pub fn set(&self, value: T) {
1730        #[cfg(not(target_arch = "wasm32"))]
1731        let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
1732            let new_meta = agents::get_current_mutation_metadata();
1733            let existing_meta = self.metadata_tvar.read(tx)?;
1734            let mut skip = false;
1735            if self.resolution == agents::ConflictResolution::PriorityWins
1736                && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
1737                && new_m.priority < old_m.priority {
1738                    skip = true;
1739            }
1740            if !skip {
1741                self.tvar.write(tx, value.clone())?;
1742                self.metadata_tvar.write(tx, new_meta)?;
1743                Ok((false, value.clone(), new_meta))
1744            } else {
1745                Ok((true, self.tvar.read(tx)?, existing_meta))
1746            }
1747        });
1748        #[cfg(target_arch = "wasm32")]
1749        let (was_skipped, final_val, final_meta) = (false, value, agents::get_current_mutation_metadata());
1750        if was_skipped {
1751            if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
1752                agents::notify_conflict(agents::ConflictEvent {
1753                    agent_id: new_m.agent_id,
1754                    priority: new_m.priority,
1755                    existing_agent_id: old_m.agent_id,
1756                    existing_priority: old_m.priority,
1757                    timestamp_ms: new_m.timestamp_ms,
1758                });
1759            }
1760            return;
1761        }
1762        self.swap.store(Arc::new(final_val.clone()));
1763        self.metadata_swap.store(Arc::new(final_meta));
1764        self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
1765        let subs = Arc::clone(&self.subscribers);
1766        if crate::is_batching() {
1767            crate::enqueue_batch_task(Box::new(move || {
1768                let s = subs.lock().unwrap();
1769                for cb in s.iter() {
1770                    cb(&final_val);
1771                }
1772            }));
1773        } else {
1774            let s = subs.lock().unwrap();
1775            for cb in s.iter() {
1776                cb(&final_val);
1777            }
1778        }
1779    }
1780    pub fn mutate<F: Fn(&T) -> T>(&self, f: F) {
1781        #[cfg(not(target_arch = "wasm32"))]
1782        {
1783            let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
1784                let new_meta = agents::get_current_mutation_metadata();
1785                let existing_meta = self.metadata_tvar.read(tx)?;
1786                let mut skip = false;
1787                if self.resolution == agents::ConflictResolution::PriorityWins
1788                    && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
1789                    && new_m.priority < old_m.priority {
1790                        skip = true;
1791                }
1792                if !skip {
1793                    let current = self.tvar.read(tx)?;
1794                    let next = f(&current);
1795                    self.tvar.write(tx, next.clone())?;
1796                    self.metadata_tvar.write(tx, new_meta)?;
1797                    Ok((false, next, new_meta))
1798                } else {
1799                    Ok((true, self.tvar.read(tx)?, existing_meta))
1800                }
1801            });
1802            if was_skipped {
1803                if let (Some(new_m), Some(old_m)) = (agents::get_current_mutation_metadata(), final_meta) {
1804                    agents::notify_conflict(agents::ConflictEvent {
1805                        agent_id: new_m.agent_id,
1806                        priority: new_m.priority,
1807                        existing_agent_id: old_m.agent_id,
1808                        existing_priority: old_m.priority,
1809                        timestamp_ms: new_m.timestamp_ms,
1810                    });
1811                }
1812                return;
1813            }
1814            self.swap.store(Arc::new(final_val.clone()));
1815            self.metadata_swap.store(Arc::new(final_meta));
1816            self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
1817            let subs = Arc::clone(&self.subscribers);
1818            if crate::is_batching() {
1819                crate::enqueue_batch_task(Box::new(move || {
1820                    let s = subs.lock().unwrap();
1821                    for cb in s.iter() {
1822                        cb(&final_val);
1823                    }
1824                }));
1825            } else {
1826                let s = subs.lock().unwrap();
1827                for cb in s.iter() {
1828                    cb(&final_val);
1829                }
1830            }
1831        }
1832        #[cfg(target_arch = "wasm32")]
1833        {
1834            self.set(f(&self.get()));
1835        }
1836    }
1837    /// Get current version
1838    pub fn version(&self) -> u64 {
1839        self.version.load(std::sync::atomic::Ordering::Acquire)
1840    }
1841    /// Subscribe to state changes
1842    pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
1843        self.subscribers.lock().unwrap().push(Box::new(callback));
1844    }
1845}
1846use crate::runtime::NodeStateSnapshot;
1847use std::sync::atomic::{AtomicBool, Ordering};
1848use std::sync::OnceLock;
1849/// Global application state registry.
1850pub static SYSTEM_STATE: OnceLock<Arc<arc_swap::ArcSwap<KnowledgeState>>> = OnceLock::new();
1851#[cfg(not(target_arch = "wasm32"))]
1852static KNOWLEDGE_TVAR: OnceLock<stm::TVar<KnowledgeState>> = OnceLock::new();
1853static IS_BATCHING: AtomicBool = AtomicBool::new(false);
1854pub static IS_RENDERING: AtomicBool = AtomicBool::new(false);
1855pub static LAYOUT_DIRTY: AtomicBool = AtomicBool::new(false);
1856static BATCH_QUEUE: OnceLock<std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync>>>> = OnceLock::new();
1857/// Returns true if state updates are currently being batched.
1858pub fn is_batching() -> bool {
1859    IS_BATCHING.load(Ordering::Acquire)
1860}
1861/// Returns true if the system is currently in the render phase.
1862pub fn is_rendering() -> bool {
1863    IS_RENDERING.load(Ordering::Acquire)
1864}
1865/// Signals the start of the render phase. Mutations during this phase trigger warnings.
1866pub fn begin_render_phase() {
1867    IS_RENDERING.store(true, Ordering::Release);
1868}
1869/// Signals the end of the render phase.
1870pub fn end_render_phase() {
1871    IS_RENDERING.store(false, Ordering::Release);
1872}
1873/// Enqueues a notification task to be run when the current batch flushes.
1874pub fn enqueue_batch_task(task: Box<dyn FnOnce() + Send + Sync>) {
1875    let mut queue = BATCH_QUEUE
1876        .get_or_init(|| std::sync::Mutex::new(Vec::new()))
1877        .lock()
1878        .unwrap();
1879    queue.push(task);
1880}
1881/// Executes multiple state updates in a single batch, deferring all subscriber
1882/// notifications until the closure completes. This prevents layout thrashing
1883/// and redundant render cycles when modifying multiple independent states.
1884pub fn batch<F: FnOnce()>(f: F) {
1885    if IS_BATCHING.swap(true, Ordering::AcqRel) {
1886        // Already inside a batch, just execute
1887        f();
1888        return;
1889    }
1890    f();
1891    IS_BATCHING.store(false, Ordering::Release);
1892    let mut queue = BATCH_QUEUE
1893        .get_or_init(|| std::sync::Mutex::new(Vec::new()))
1894        .lock()
1895        .unwrap();
1896    let tasks: Vec<_> = queue.drain(..).collect();
1897    drop(queue);
1898    for task in tasks {
1899        task();
1900    }
1901}
1902/// Get a reference to the global system state.
1903pub fn get_system_state() -> Arc<arc_swap::ArcSwap<KnowledgeState>> {
1904    SYSTEM_STATE
1905        .get_or_init(|| Arc::new(arc_swap::ArcSwap::from_pointee(KnowledgeState::default())))
1906        .clone()
1907}
1908pub fn load_system_state() -> arc_swap::Guard<Arc<KnowledgeState>> {
1909    get_system_state().load()
1910}
1911pub fn update_system_state<F>(f: F)
1912where
1913    F: Fn(&KnowledgeState) -> KnowledgeState,
1914{
1915    if is_rendering() {
1916        log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1917    }
1918    LAYOUT_DIRTY.store(true, Ordering::SeqCst);
1919    let swap = get_system_state();
1920    let current = swap.load();
1921    let new_state = Arc::new(f(&current));
1922    swap.store(Arc::clone(&new_state));
1923    #[cfg(not(target_arch = "wasm32"))]
1924    {
1925        let tvar = KNOWLEDGE_TVAR
1926            .get_or_init(|| stm::TVar::new((*new_state).clone()));
1927        stm::atomically(|tx| tvar.write(tx, (*new_state).clone()));
1928    }
1929}
1930pub fn transact_system_state<F>(f: F)
1931where
1932    F: Fn(&KnowledgeState) -> KnowledgeState,
1933{
1934    #[cfg(not(target_arch = "wasm32"))]
1935    {
1936        if is_rendering() {
1937            log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1938        }
1939        let tvar = KNOWLEDGE_TVAR
1940            .get_or_init(|| {
1941                stm::TVar::new((**get_system_state().load()).clone())
1942            })
1943            .clone();
1944        let new_state = stm::atomically(move |tx| {
1945            let current = tvar.read(tx)?;
1946            let next = f(&current);
1947            tvar.write(tx, next.clone())?;
1948            Ok(next)
1949        });
1950        get_system_state().store(Arc::new(new_state));
1951    }
1952    #[cfg(target_arch = "wasm32")]
1953    {
1954        if is_rendering() {
1955            log::warn!("LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance.");
1956        }
1957        update_system_state(f);
1958    }
1959}
1960impl KnowledgeState {
1961    /// Create a new empty KnowledgeState.
1962    pub fn new() -> Self {
1963        Self::default()
1964    }
1965    /// Set a component's internal state.
1966    pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
1967        self.component_states
1968            .insert(id, Arc::new(std::sync::RwLock::new(state)));
1969    }
1970/// Get a reference to a component's internal state.
1971    pub fn get_component_state<T: 'static + Send + Sync>(
1972        &self,
1973        id: u64,
1974    ) -> Option<Arc<std::sync::RwLock<T>>> {
1975        let lock = self.component_states.get(&id)?;
1976        // Try to downcast the Arc<RwLock<dyn Any>> to Arc<RwLock<T>>
1977let _inner: &std::sync::RwLock<dyn std::any::Any + Send + Sync> = lock;
1978        // We cannot directly cast Arc<RwLock<dyn Any>> to Arc<RwLock<T>>
1979        // Instead, return the raw state - this is a limitation of the design
1980        None // Placeholder - proper implementation would need a different design
1981    }
1982    /// Add a new fragment to memory.
1983    pub fn remember(&mut self, fragment: KnowledgeFragment) {
1984        self.fragments.insert(fragment.id.clone(), fragment);
1985    }
1986    /// Process a search query against the local knowledge base.
1987    pub fn process_query(&mut self, query: &str) {
1988        let query_lower = query.to_lowercase();
1989        let mut results: Vec<(f32, String)> = self
1990            .fragments
1991            .iter()
1992            .map(|(id, frag)| {
1993                let mut score = 0.0;
1994                if frag.summary.to_lowercase().contains(&query_lower) {
1995                    score += 1.0;
1996                }
1997                if frag.source.to_lowercase().contains(&query_lower) {
1998                    score += 0.5;
1999                }
2000                (score, id.clone())
2001            })
2002            .filter(|(score, _)| *score > 0.0)
2003            .collect();
2004        // Sort by relevance score
2005        results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
2006        self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
2007    }
2008    /// Captures a snapshot of the current state for debugging and hot-reloading.
2009    pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
2010        let mut snapshots = Vec::new();
2011        // Snapshots of agentic fragments
2012        for frag in self.fragments.values() {
2013            if let Ok(val) = serde_json::to_value(frag) {
2014                snapshots.push(NodeStateSnapshot { id: 0, state: val });
2015            }
2016        }
2017        snapshots
2018    }
2019}
2020/// A read/write projection into a `State<T>` owned elsewhere.
2021#[derive(Clone)]
2022pub struct Binding<T: Clone + Send + Sync + 'static> {
2023    swap: Arc<arc_swap::ArcSwap<T>>,
2024    #[cfg(not(target_arch = "wasm32"))]
2025    tvar: Arc<stm::TVar<T>>,
2026    version: Arc<std::sync::atomic::AtomicU64>,
2027}
2028impl<T: Clone + Send + Sync + 'static> Binding<T> {
2029    /// Create a binding from a State
2030    pub fn from_state(state: &State<T>) -> Self {
2031        Self {
2032            swap: Arc::clone(&state.swap),
2033            #[cfg(not(target_arch = "wasm32"))]
2034            tvar: Arc::clone(&state.tvar),
2035            version: Arc::clone(&state.version),
2036        }
2037    }
2038    /// Get the current value
2039    pub fn get(&self) -> T {
2040        (**self.swap.load()).clone()
2041    }
2042    /// Set a new value
2043    pub fn set(&self, value: T) {
2044        self.swap.store(Arc::new(value.clone()));
2045        #[cfg(not(target_arch = "wasm32"))]
2046        {
2047            let tvar = Arc::clone(&self.tvar);
2048            let v = value.clone();
2049            stm::atomically(move |tx| tvar.write(tx, v.clone()));
2050        }
2051        self.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2052    }
2053    /// Get current version
2054    pub fn version(&self) -> u64 {
2055        self.version.load(std::sync::atomic::Ordering::Acquire)
2056    }
2057}
2058#[cfg(not(target_arch = "wasm32"))]
2059pub fn transact_pair<A, B, F>(state_a: &State<A>, state_b: &State<B>, f: F)
2060where
2061    A: Clone + Send + Sync + 'static,
2062    B: Clone + Send + Sync + 'static,
2063    F: Fn(&A, &B) -> (A, B),
2064{
2065    let tvar_a = Arc::clone(&state_a.tvar);
2066    let tvar_b = Arc::clone(&state_b.tvar);
2067    let (new_a, new_b) = stm::atomically(move |tx| {
2068        let a = tvar_a.read(tx)?;
2069        let b = tvar_b.read(tx)?;
2070        let (na, nb) = f(&a, &b);
2071        tvar_a.write(tx, na.clone())?;
2072        tvar_b.write(tx, nb.clone())?;
2073        Ok((na, nb))
2074    });
2075    state_a.swap.store(Arc::new(new_a.clone()));
2076    state_b.swap.store(Arc::new(new_b.clone()));
2077    state_a.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2078    state_b.version.fetch_add(1, std::sync::atomic::Ordering::Release);
2079    let subs_a = Arc::clone(&state_a.subscribers);
2080    let subs_b = Arc::clone(&state_b.subscribers);
2081    if crate::is_batching() {
2082        crate::enqueue_batch_task(Box::new(move || {
2083            {
2084                let s = subs_a.lock().unwrap();
2085                for cb in s.iter() { cb(&new_a); }
2086            }
2087            {
2088                let s = subs_b.lock().unwrap();
2089                for cb in s.iter() { cb(&new_b); }
2090            }
2091        }));
2092    } else {
2093        {
2094            let s = subs_a.lock().unwrap();
2095            for cb in s.iter() { cb(&new_a); }
2096        }
2097        {
2098            let s = subs_b.lock().unwrap();
2099            for cb in s.iter() { cb(&new_b); }
2100        }
2101    }
2102}
2103use std::any::TypeId;
2104use std::sync::Mutex;
2105/// Global environment storage using TypeId as keys.
2106pub(crate) static ENVIRONMENT: OnceLock<
2107    Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
2108> = OnceLock::new();
2109/// Environment key type for accessing ambient values
2110///
2111/// Implement this trait to define a new environment key.
2112pub trait EnvKey: 'static + Send + Sync {
2113    /// The type of value stored in the environment
2114    type Value: Clone + Send + Sync + 'static;
2115    /// Get a default value for this key
2116    fn default_value() -> Self::Value;
2117}
2118/// Key for accessing the Yggdrasil design token tree
2119pub struct YggdrasilKey;
2120impl EnvKey for YggdrasilKey {
2121    type Value = YggdrasilTokens;
2122    fn default_value() -> Self::Value {
2123        default_tokens()
2124    }
2125}
2126// Duplicate AssetKey removed - original definition at line 63
2127/// System appearance (Light/Dark mode)
2128#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2129pub enum Appearance {
2130    Light,
2131    Dark,
2132}
2133/// Orientation for layouts
2134#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2135pub enum Orientation {
2136    Horizontal,
2137    Vertical,
2138}
2139/// Cross-axis alignment for layout containers.
2140#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2141pub enum Alignment {
2142    #[default]
2143    Center,
2144    Leading,
2145    Trailing,
2146    Top,
2147    Bottom,
2148}
2149/// Main-axis distribution for linear layout containers.
2150#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2151pub enum Distribution {
2152    #[default]
2153    Fill,
2154    Center,
2155    Leading,
2156    Trailing,
2157    SpaceBetween,
2158    SpaceAround,
2159    SpaceEvenly,
2160}
2161/// A color represented by RGBA components in the [0.0, 1.0] range.
2162#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2163pub struct Color {
2164    pub r: f32,
2165    pub g: f32,
2166    pub b: f32,
2167    pub a: f32,
2168}
2169impl Color {
2170    pub const BLACK: Color = Color {
2171        r: 0.0,
2172        g: 0.0,
2173        b: 0.0,
2174        a: 1.0,
2175    };
2176    pub const WHITE: Color = Color {
2177        r: 1.0,
2178        g: 1.0,
2179        b: 1.0,
2180        a: 1.0,
2181    };
2182    pub const TRANSPARENT: Color = Color {
2183        r: 0.0,
2184        g: 0.0,
2185        b: 0.0,
2186        a: 0.0,
2187    };
2188    pub const RED: Color = Color {
2189        r: 1.0,
2190        g: 0.0,
2191        b: 0.0,
2192        a: 1.0,
2193    };
2194    pub const GREEN: Color = Color {
2195        r: 0.0,
2196        g: 1.0,
2197        b: 0.0,
2198        a: 1.0,
2199    };
2200    pub const BLUE: Color = Color {
2201        r: 0.0,
2202        g: 0.0,
2203        b: 1.0,
2204        a: 1.0,
2205    };
2206    /// Calculate the relative luminance of the color as defined by WCAG 2.x
2207    pub fn relative_luminance(&self) -> f32 {
2208        fn res(c: f32) -> f32 {
2209            if c <= 0.03928 {
2210                c / 12.92
2211            } else {
2212                ((c + 0.055) / 1.055).powf(2.4)
2213            }
2214        }
2215        0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
2216    }
2217    /// Calculate the contrast ratio between this color and another color
2218    pub fn contrast_ratio(&self, other: &Color) -> f32 {
2219        let l1 = self.relative_luminance();
2220        let l2 = other.relative_luminance();
2221        if l1 > l2 {
2222            (l1 + 0.05) / (l2 + 0.05)
2223        } else {
2224            (l2 + 0.05) / (l1 + 0.05)
2225        }
2226    }
2227    pub const CYAN: Color = Color {
2228        r: 0.0,
2229        g: 1.0,
2230        b: 1.0,
2231        a: 1.0,
2232    };
2233    pub const YELLOW: Color = Color {
2234        r: 1.0,
2235        g: 1.0,
2236        b: 0.0,
2237        a: 1.0,
2238    };
2239    pub const MAGENTA: Color = Color {
2240        r: 1.0,
2241        g: 0.0,
2242        b: 1.0,
2243        a: 1.0,
2244    };
2245    pub const GRAY: Color = Color {
2246        r: 0.5,
2247        g: 0.5,
2248        b: 0.5,
2249        a: 1.0,
2250    };
2251    /// Create a new color from RGBA components.
2252    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
2253        Self { r, g, b, a }
2254    }
2255    /// Convert the color to a [r, g, b, a] array.
2256    pub fn as_array(&self) -> [f32; 4] {
2257        [self.r, self.g, self.b, self.a]
2258    }
2259}
2260impl View for Color {
2261    type Body = Never;
2262    fn body(self) -> Self::Body {
2263        unreachable!()
2264    }
2265    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
2266        renderer.fill_rect(rect, self.as_array());
2267    }
2268}
2269/// Key for accessing the current system appearance
2270pub struct AppearanceKey;
2271impl EnvKey for AppearanceKey {
2272    type Value = Appearance;
2273    fn default_value() -> Self::Value {
2274        Appearance::Dark // Default to Dark (Ginnungagap) for Berserker aesthetic
2275    }
2276}
2277/// StyleResolver provides high-level access to themed values from the environment.
2278pub struct StyleResolver;
2279impl StyleResolver {
2280    /// Resolve a color from the current environment
2281    pub fn color(key: &str) -> String {
2282        let tokens = Environment::<YggdrasilKey>::new().get();
2283        let appearance = Environment::<AppearanceKey>::new().get();
2284        let is_dark = appearance == Appearance::Dark;
2285        tokens
2286            .get_color(key, is_dark)
2287            .unwrap_or_else(|| "#FF00FF".to_string()) // Default to MuspelMagenta on failure
2288    }
2289    /// Resolve a generic token value
2290    pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
2291        let tokens = Environment::<YggdrasilKey>::new().get();
2292        let appearance = Environment::<AppearanceKey>::new().get();
2293        let is_dark = appearance == Appearance::Dark;
2294        tokens.get(category, key, is_dark)
2295    }
2296}
2297/// The authoritative Cyberpunk Viking default tokens
2298pub fn default_tokens() -> YggdrasilTokens {
2299    let mut tokens = YggdrasilTokens::new();
2300    // Core Norse Colorways
2301    tokens.color.insert(
2302        "background".to_string(),
2303        TokenValue::Single {
2304            value: "#000000".to_string(), // Ginnungagap (The Void)
2305        },
2306    );
2307    tokens.color.insert(
2308        "primary".to_string(),
2309        TokenValue::Single {
2310            value: "#00FFFF".to_string(), // NiflCyan (Aesir Primary)
2311        },
2312    );
2313    tokens.color.insert(
2314        "secondary".to_string(),
2315        TokenValue::Single {
2316            value: "#FF00FF".to_string(), // MuspelMagenta (Berserker Secondary)
2317        },
2318    );
2319    tokens.color.insert(
2320        "surface".to_string(),
2321        TokenValue::Adaptive {
2322            light: "#FFFFFF".to_string(),
2323            dark: "#121212".to_string(),
2324        },
2325    );
2326    tokens.color.insert(
2327        "text".to_string(),
2328        TokenValue::Adaptive {
2329            light: "#000000".to_string(),
2330            dark: "#FFFFFF".to_string(),
2331        },
2332    );
2333    // Bifrost (Glassmorphism) - Frosted Style
2334    tokens.bifrost.insert(
2335        "blur".to_string(),
2336        TokenValue::Single {
2337            value: "25.0".to_string(),
2338        },
2339    );
2340    tokens.bifrost.insert(
2341        "saturation".to_string(),
2342        TokenValue::Single {
2343            value: "1.2".to_string(),
2344        },
2345    );
2346    tokens.bifrost.insert(
2347        "opacity".to_string(),
2348        TokenValue::Single {
2349            value: "0.65".to_string(),
2350        },
2351    );
2352    // Gungnir (Neon Glow)
2353    tokens.gungnir.insert(
2354        "intensity".to_string(),
2355        TokenValue::Single {
2356            value: "1.0".to_string(),
2357        },
2358    );
2359    tokens.gungnir.insert(
2360        "radius".to_string(),
2361        TokenValue::Single {
2362            value: "15.0".to_string(),
2363        },
2364    );
2365    // Mjolnir (Sharp Geometry)
2366    tokens.mjolnir.insert(
2367        "clip_angle".to_string(),
2368        TokenValue::Single {
2369            value: "12.0".to_string(),
2370        },
2371    );
2372    tokens.mjolnir.insert(
2373        "border_width".to_string(),
2374        TokenValue::Single {
2375            value: "2.0".to_string(),
2376        },
2377    );
2378    // Sleipnir (Spring Animation)
2379    tokens.anim.insert(
2380        "stiffness".to_string(),
2381        TokenValue::Single {
2382            value: "170.0".to_string(),
2383        },
2384    );
2385    tokens.anim.insert(
2386        "damping".to_string(),
2387        TokenValue::Single {
2388            value: "26.0".to_string(),
2389        },
2390    );
2391    tokens.anim.insert(
2392        "mass".to_string(),
2393        TokenValue::Single {
2394            value: "1.0".to_string(),
2395        },
2396    );
2397    // Accessibility
2398    tokens.accessibility.insert(
2399        "reduce_motion".to_string(),
2400        TokenValue::Single {
2401            value: "false".to_string(),
2402        },
2403    );
2404    tokens
2405}
2406/// Environment wrapper for accessing ambient values
2407pub struct Environment<K: EnvKey> {
2408    _marker: std::marker::PhantomData<K>,
2409}
2410impl<K: EnvKey> Default for Environment<K> {
2411    fn default() -> Self {
2412        Self::new()
2413    }
2414}
2415impl<K: EnvKey> Environment<K> {
2416    /// Create a new Environment
2417    pub fn new() -> Self {
2418        Self {
2419            _marker: std::marker::PhantomData,
2420        }
2421    }
2422    /// Get the current value from the environment
2423    pub fn get(&self) -> K::Value {
2424        if let Some(env_store) = ENVIRONMENT.get() {
2425            let env_lock = env_store.lock().unwrap();
2426            if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
2427                if let Some(typed_val) = val.downcast_ref::<K::Value>() {
2428                    return typed_val.clone();
2429                } else {
2430                    log::warn!("Environment: Downcast failed for key type {:?}", std::any::type_name::<K>());
2431                }
2432            } else {
2433                log::debug!("Environment: Key not found: {:?}. Returning default.", std::any::type_name::<K>());
2434            }
2435        } else {
2436            log::debug!("Environment: Store not initialized. Key: {:?}. Returning default.", std::any::type_name::<K>());
2437        }
2438        K::default_value()
2439    }
2440}
2441/// Ambient environment management
2442pub mod env {
2443    /// Insert a value into the environment
2444    pub fn insert<K: super::EnvKey>(value: K::Value) {
2445        let store = super::ENVIRONMENT.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
2446        let mut env_map = store.lock().unwrap();
2447        env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
2448    }
2449    /// Remove a value from the environment.
2450    pub fn remove<K: super::EnvKey>() {
2451        if let Some(store) = super::ENVIRONMENT.get() {
2452            let mut env_map = store.lock().unwrap();
2453            env_map.remove(&std::any::TypeId::of::<K>());
2454        }
2455    }
2456}
2457/// Geometry modifiers
2458/// Size of the view in logical pixels
2459#[derive(Debug, Clone, Copy, PartialEq)]
2460pub struct Size {
2461    pub width: f32,
2462    pub height: f32,
2463}
2464
2465impl Size {
2466    pub const ZERO: Self = Self { width: 0.0, height: 0.0 };
2467
2468    pub fn new(width: f32, height: f32) -> Self {
2469        Self { width, height }
2470    }
2471}
2472
2473/// Insets for padding
2474#[derive(Debug, Clone, Copy, PartialEq)]
2475pub struct EdgeInsets {
2476    pub top: f32,
2477    pub leading: f32,
2478    pub bottom: f32,
2479    pub trailing: f32,
2480}
2481
2482impl EdgeInsets {
2483    /// Equal insets on all edges
2484    pub fn all(value: f32) -> Self {
2485        Self {
2486            top: value,
2487            leading: value,
2488            bottom: value,
2489            trailing: value,
2490        }
2491    }
2492
2493    /// Vertical insets (top and bottom)
2494    pub fn vertical(value: f32) -> Self {
2495        Self {
2496            top: value,
2497            leading: 0.0,
2498            bottom: value,
2499            trailing: 0.0,
2500        }
2501    }
2502
2503    /// Horizontal insets (leading and trailing)
2504    pub fn horizontal(value: f32) -> Self {
2505        Self {
2506            top: 0.0,
2507            leading: value,
2508            bottom: 0.0,
2509            trailing: value,
2510        }
2511    }
2512}
2513
2514/// Modifier to set the size of a view
2515#[derive(Debug, Clone, Copy, PartialEq)]
2516pub struct FrameModifier {
2517    pub width: Option<f32>,
2518    pub height: Option<f32>,
2519}
2520
2521impl Default for FrameModifier {
2522    fn default() -> Self {
2523        Self::new()
2524    }
2525}
2526
2527impl FrameModifier {
2528    pub fn new() -> Self {
2529        Self {
2530            width: None,
2531            height: None,
2532        }
2533    }
2534
2535    pub fn width(mut self, width: f32) -> Self {
2536        self.width = Some(width);
2537        self
2538    }
2539
2540    pub fn height(mut self, height: f32) -> Self {
2541        self.height = Some(height);
2542        self
2543    }
2544
2545    pub fn size(mut self, width: f32, height: f32) -> Self {
2546        self.width = Some(width);
2547        self.height = Some(height);
2548        self
2549    }
2550}
2551
2552impl ViewModifier for FrameModifier {
2553    fn modify<V: View>(self, content: V) -> impl View {
2554        ModifiedView::new(content, self)
2555    }
2556}
2557
2558/// Modifier to set the flex weight of a view
2559#[derive(Debug, Clone, Copy, PartialEq)]
2560pub struct FlexModifier {
2561    pub weight: f32,
2562}
2563
2564impl ViewModifier for FlexModifier {
2565    fn modify<V: View>(self, content: V) -> impl View {
2566        ModifiedView::new(content, self)
2567    }
2568
2569    fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
2570        self.weight
2571    }
2572}
2573
2574/// Modifier to offset a view
2575#[derive(Debug, Clone, Copy, PartialEq)]
2576pub struct OffsetModifier {
2577    pub x: f32,
2578    pub y: f32,
2579}
2580
2581impl OffsetModifier {
2582    pub fn new(x: f32, y: f32) -> Self {
2583        Self { x, y }
2584    }
2585}
2586
2587impl ViewModifier for OffsetModifier {
2588    fn modify<V: View>(self, content: V) -> impl View {
2589        ModifiedView::new(content, self)
2590    }
2591}
2592
2593/// Modifier to set the z-index of a view
2594#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2595pub struct ZIndexModifier {
2596    pub z_index: i32,
2597}
2598
2599impl ZIndexModifier {
2600    pub fn new(z_index: i32) -> Self {
2601        Self { z_index }
2602    }
2603}
2604
2605impl ViewModifier for ZIndexModifier {
2606    fn modify<V: View>(self, content: V) -> impl View {
2607        ModifiedView::new(content, self)
2608    }
2609}
2610
2611/// Layout constraints for views
2612#[derive(Debug, Clone, Copy, PartialEq, Default)]
2613pub struct LayoutConstraints {
2614    pub min_width: Option<f32>,
2615    pub max_width: Option<f32>,
2616    pub min_height: Option<f32>,
2617    pub max_height: Option<f32>,
2618}
2619
2620/// Modifier to set layout constraints
2621#[derive(Debug, Clone, Copy, PartialEq)]
2622pub struct LayoutModifier {
2623    pub constraints: LayoutConstraints,
2624}
2625
2626impl LayoutModifier {
2627    pub fn new(constraints: LayoutConstraints) -> Self {
2628        Self { constraints }
2629    }
2630}
2631
2632impl ViewModifier for LayoutModifier {
2633    fn modify<V: View>(self, content: V) -> impl View {
2634        ModifiedView::new(content, self)
2635    }
2636}
2637
2638/// Modifier to handle platform safe areas
2639#[derive(Debug, Clone, Copy, PartialEq)]
2640pub struct SafeAreaModifier {
2641    pub ignores: bool,
2642}
2643
2644impl ViewModifier for SafeAreaModifier {
2645    fn modify<V: View>(self, content: V) -> impl View {
2646        ModifiedView::new(content, self)
2647    }
2648}
2649
2650/// Modifier to add elevation (shadow) to a view
2651#[derive(Debug, Clone, Copy, PartialEq)]
2652pub struct ElevationModifier {
2653    pub level: f32,
2654}
2655
2656impl ViewModifier for ElevationModifier {
2657    fn modify<V: View>(self, content: V) -> impl View {
2658        ModifiedView::new(content, self)
2659    }
2660
2661    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
2662        if self.level > 0.0 {
2663            let radius = self.level * 2.0;
2664            let offset_y = self.level * 0.5;
2665            let shadow_color = [0.0, 0.0, 0.0, 0.3];
2666            renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
2667            view.render(renderer, rect);
2668            renderer.pop_shadow();
2669        } else {
2670            view.render(renderer, rect);
2671        }
2672    }
2673}
2674
2675// Layout subsystem
2676pub mod layout {
2677    use super::*;
2678
2679    // Layout pass scratch space
2680    pub struct LayoutCache {
2681        pub safe_area: SafeArea,
2682        size_cache: HashMap<(u64, u32, u32), Size>, // (ViewHash, ProposalW, ProposalH)
2683    }
2684
2685    impl Default for LayoutCache {
2686        fn default() -> Self {
2687            Self::new()
2688        }
2689    }
2690
2691    impl LayoutCache {
2692        pub fn new() -> Self {
2693            Self {
2694                safe_area: SafeArea::default(),
2695                size_cache: HashMap::new(),
2696            }
2697        }
2698
2699        pub fn clear(&mut self) {
2700            self.safe_area = SafeArea::default();
2701            self.size_cache.clear();
2702        }
2703
2704        pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
2705            let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2706            let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2707            self.size_cache.get(&(view_hash, pw, ph)).copied()
2708        }
2709
2710        pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: Size) {
2711            let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
2712            let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
2713            self.size_cache.insert((view_hash, pw, ph), size);
2714        }
2715
2716        /// Remove all cached size entries for a specific view hash.
2717        pub fn invalidate_view(&mut self, view_hash: u64) {
2718            self.size_cache.retain(|&(hash, _, _), _| hash != view_hash);
2719        }
2720    }
2721
2722    /// Proposed size from parent view
2723    #[derive(Debug, Clone, Copy, PartialEq)]
2724    pub struct SizeProposal {
2725        pub width: Option<f32>,
2726        pub height: Option<f32>,
2727    }
2728
2729    impl SizeProposal {
2730        pub fn unspecified() -> Self {
2731            Self {
2732                width: None,
2733                height: None,
2734            }
2735        }
2736
2737        pub fn width(width: f32) -> Self {
2738            Self {
2739                width: Some(width),
2740                height: None,
2741            }
2742        }
2743
2744        pub fn height(height: f32) -> Self {
2745            Self {
2746                width: None,
2747                height: Some(height),
2748            }
2749        }
2750
2751        pub fn tight(width: f32, height: f32) -> Self {
2752            Self {
2753                width: Some(width),
2754                height: Some(height),
2755            }
2756        }
2757
2758        pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
2759            Self { width, height }
2760        }
2761    }
2762
2763    /// A view that can participate in layout
2764    pub trait LayoutView: Send {
2765        /// Propose a size for this view given the available space
2766        fn size_that_fits(
2767            &self,
2768            proposal: SizeProposal,
2769            subviews: &[&dyn LayoutView],
2770            cache: &mut LayoutCache,
2771        ) -> Size;
2772
2773        /// Place subviews within the given bounds
2774        fn place_subviews(
2775            &self,
2776            bounds: Rect,
2777            subviews: &mut [&mut dyn LayoutView],
2778            cache: &mut LayoutCache,
2779        );
2780
2781        /// Returns the flex weight of this view (default is 0.0, which means fixed/intrinsic)
2782        fn flex_weight(&self) -> f32 {
2783            0.0
2784        }
2785    }
2786    /// Edge insets for padding, margins, and safe areas
2787    #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2788    pub struct EdgeInsets {
2789        pub top: f32,
2790        pub leading: f32,
2791        pub bottom: f32,
2792        pub trailing: f32,
2793    }
2794
2795    impl EdgeInsets {
2796        pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
2797            Self { top, leading, bottom, trailing }
2798        }
2799
2800        pub fn all(value: f32) -> Self {
2801            Self {
2802                top: value,
2803                leading: value,
2804                bottom: value,
2805                trailing: value,
2806            }
2807        }
2808    }
2809
2810    /// SafeArea constraints provided by the platform
2811    #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
2812    pub struct SafeArea {
2813        pub insets: EdgeInsets,
2814    }
2815
2816    /// Rectangle in logical pixels
2817    #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2818    pub struct Rect {
2819        pub x: f32,
2820        pub y: f32,
2821        pub width: f32,
2822        pub height: f32,
2823    }
2824
2825    impl Rect {
2826        pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
2827            Self {
2828                x,
2829                y,
2830                width,
2831                height,
2832            }
2833        }
2834
2835        pub fn zero() -> Self {
2836            Self {
2837                x: 0.0,
2838                y: 0.0,
2839                width: 0.0,
2840                height: 0.0,
2841            }
2842        }
2843
2844        pub fn contains(&self, x: f32, y: f32) -> bool {
2845            x >= self.x && x <= self.x + self.width && y >= self.y && y <= self.y + self.height
2846        }
2847
2848        pub fn size(&self) -> Size {
2849            Size {
2850                width: self.width,
2851                height: self.height,
2852            }
2853        }
2854
2855        /// Split the rect horizontally into N equal pieces
2856        pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
2857            if n == 0 {
2858                return vec![];
2859            }
2860            let item_width = self.width / n as f32;
2861            (0..n)
2862                .map(|i| Rect {
2863                    x: self.x + i as f32 * item_width,
2864                    y: self.y,
2865                    width: item_width,
2866                    height: self.height,
2867                })
2868                .collect()
2869        }
2870
2871        /// Split the rect vertically into N equal pieces
2872        pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
2873            if n == 0 {
2874                return vec![];
2875            }
2876            let item_height = self.height / n as f32;
2877            (0..n)
2878                .map(|i| Rect {
2879                    x: self.x,
2880                    y: self.y + i as f32 * item_height,
2881                    width: self.width,
2882                    height: item_height,
2883                })
2884                .collect()
2885        }
2886    }
2887}
2888
2889// Re-export layout items for convenience
2890pub use layout::{LayoutCache, LayoutView, Rect, SizeProposal};
2891// Size and FrameRenderer are pub items in this module; no re-export alias needed.
2892
2893pub mod runtime;
2894pub mod scene_graph;
2895pub mod agents;
2896pub mod material;
2897
2898
2899pub use scene_graph::{NodeId, bifrost_registry};
2900
2901// Duplicate AssetState removed - original definition at line 67
2902
2903/// AssetManager defines the interface for loading and caching external resources.
2904pub trait AssetManager: Send + Sync {
2905    /// Request an image asset. Returns the current state (Loading, Ready, or Error).
2906    fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
2907
2908    /// Pre-load an image into the cache.
2909    fn preload_image(&self, url: &str);
2910}
2911
2912/// User input event types
2913#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2914pub enum Event {
2915    PointerDown { x: f32, y: f32 },
2916    PointerUp { x: f32, y: f32 },
2917    PointerMove { x: f32, y: f32 },
2918    PointerClick { x: f32, y: f32 },
2919    PointerEnter,
2920    PointerLeave,
2921    KeyDown { key: String },
2922    KeyUp { key: String },
2923    /// Input Method Editor event (e.g. CJK character composition)
2924    Ime(String),
2925}
2926
2927impl Event {
2928    /// Returns the canonical string name of the event for lookup in handler maps.
2929    pub fn name(&self) -> &'static str {
2930        match self {
2931            Self::PointerDown { .. } => "pointerdown",
2932            Self::PointerUp { .. } => "pointerup",
2933            Self::PointerMove { .. } => "pointermove",
2934            Self::PointerClick { .. } => "pointerclick",
2935            Self::PointerEnter => "pointerenter",
2936            Self::PointerLeave => "pointerleave",
2937            Self::KeyDown { .. } => "keydown",
2938            Self::KeyUp { .. } => "keyup",
2939            Self::Ime(_) => "ime",
2940        }
2941    }
2942}
2943
2944/// Response from an event handler
2945#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2946pub enum EventResponse {
2947    Handled,
2948    Ignored,
2949}
2950
2951/// A basic implementation of AssetManager that can be overridden by platform backends.
2952pub struct DefaultAssetManager {
2953    cache: Arc<arc_swap::ArcSwap<HashMap<String, AssetState<Arc<Vec<u8>>>>>>,
2954}
2955
2956impl Default for DefaultAssetManager {
2957    fn default() -> Self {
2958        Self::new()
2959    }
2960}
2961
2962impl DefaultAssetManager {
2963    pub fn new() -> Self {
2964        Self {
2965            cache: Arc::new(arc_swap::ArcSwap::from_pointee(HashMap::new())),
2966        }
2967    }
2968}
2969
2970impl AssetManager for DefaultAssetManager {
2971    fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
2972        if let Some(state) = self.cache.load().get(url) {
2973            return state.clone();
2974        }
2975
2976        self.cache.rcu(|map| {
2977            let mut m = (**map).clone();
2978            m.entry(url.to_string()).or_insert(AssetState::Loading);
2979            m
2980        });
2981        AssetState::Loading
2982    }
2983
2984    fn preload_image(&self, _url: &str) {}
2985}
2986
2987use std::future::Future;
2988
2989/// Suspense wrapper for asynchronous state management.
2990/// Integrates with State<T> to provide loading/error/ready states for async operations.
2991pub struct Suspense<T: Clone + Send + Sync + 'static> {
2992    inner: State<AssetState<T>>,
2993}
2994
2995impl<T: Clone + Send + Sync + 'static> Default for Suspense<T> {
2996    fn default() -> Self {
2997        Self::new()
2998    }
2999}
3000
3001impl<T: Clone + Send + Sync + 'static> Suspense<T> {
3002    pub fn new() -> Self {
3003        Self {
3004            inner: State::new(AssetState::Loading),
3005        }
3006    }
3007
3008    pub fn new_async<F>(_future: F) -> Self
3009    where
3010        F: Future<Output = Result<T, String>> + Send + 'static,
3011    {
3012        let suspense = Self::new();
3013        let _suspense_clone = suspense.clone();
3014        
3015        #[cfg(not(target_arch = "wasm32"))]
3016        {
3017            std::thread::spawn(move || {
3018                // Since native doesn't use Tokio by default, we block on the future in a separate thread.
3019                // In a real Tokio app, this would use tokio::spawn.
3020                // For cvkg-core, we execute synchronously in the spawned thread.
3021                let _rt = std::sync::Arc::new(std::sync::Mutex::new(_future));
3022                // We're stubbing execution to compile cleanly without heavy executor deps
3023            });
3024        }
3025        #[cfg(target_arch = "wasm32")]
3026        {
3027            // wasm_bindgen_futures::spawn_local(async move { ... });
3028            // Stubbed for compilation without wasm_bindgen_futures dependency in core
3029        }
3030        
3031        suspense
3032    }
3033
3034    pub fn ready(value: T) -> Self {
3035        Self {
3036            inner: State::new(AssetState::Ready(value)),
3037        }
3038    }
3039
3040    pub fn error(message: impl Into<String>) -> Self {
3041        Self {
3042            inner: State::new(AssetState::Error(message.into())),
3043        }
3044    }
3045
3046    pub fn get(&self) -> AssetState<T> {
3047        self.inner.get()
3048    }
3049
3050    pub fn get_ref(&self) -> AssetState<T> {
3051        self.inner.get()
3052    }
3053
3054    pub fn is_loading(&self) -> bool {
3055        matches!(self.get(), AssetState::Loading)
3056    }
3057
3058    pub fn is_ready(&self) -> bool {
3059        matches!(self.get(), AssetState::Ready(_))
3060    }
3061
3062    pub fn is_error(&self) -> bool {
3063        matches!(self.get(), AssetState::Error(_))
3064    }
3065
3066    pub fn ready_value(&self) -> Option<T> {
3067        match self.get() {
3068            AssetState::Ready(value) => Some(value),
3069            _ => None,
3070        }
3071    }
3072
3073    pub fn error_message(&self) -> Option<String> {
3074        match self.get() {
3075            AssetState::Error(message) => Some(message),
3076            _ => None,
3077        }
3078    }
3079
3080    pub fn subscribe<F: Fn(&AssetState<T>) + Send + Sync + 'static>(&self, callback: F) {
3081        self.inner.subscribe(callback)
3082    }
3083
3084    pub fn inner_state(&self) -> &State<AssetState<T>> {
3085        &self.inner
3086    }
3087}
3088
3089impl<T: Clone + Send + Sync + 'static> Clone for Suspense<T> {
3090    fn clone(&self) -> Self {
3091        Self {
3092            inner: self.inner.clone(),
3093        }
3094    }
3095}
3096
3097impl<T: Clone + Send + Sync + 'static> From<T> for Suspense<T> {
3098    fn from(value: T) -> Self {
3099        Self::ready(value)
3100    }
3101}
3102
3103impl<T: Clone + Send + Sync + 'static> From<Result<T, String>> for Suspense<T> {
3104    fn from(result: Result<T, String>) -> Self {
3105        match result {
3106            Ok(value) => Self::ready(value),
3107            Err(error) => Self::error(error),
3108        }
3109    }
3110}
3111
3112#[cfg(test)]
3113mod phase1_test;