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