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 error_types;
39
40pub mod security;
41
42/// Error state for fault isolation at the component level.
43#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
44pub struct ComponentErrorState {
45    pub has_error: bool,
46    pub error_message: Option<String>,
47    pub error_location: Option<String>,
48}
49impl ComponentErrorState {
50    pub fn clear() -> Self {
51        Self::default()
52    }
53
54    pub fn error(message: impl Into<String>, location: impl Into<String>) -> Self {
55        Self {
56            has_error: true,
57            error_message: Some(message.into()),
58            error_location: Some(location.into()),
59        }
60    }
61}
62
63/// Knowledge state for the agentic memory system.
64#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
65pub struct KnowledgeState {
66    pub thoughts: Vec<String>,
67    pub actions: Vec<String>,
68    pub context: HashMap<String, String>,
69    pub last_query_results: Vec<KnowledgeId>,
70    #[serde(alias = "items")]
71    pub fragments: std::collections::HashMap<KnowledgeId, KnowledgeFragment>,
72    /// The Temporal Graph nodes
73    pub nodes: Vec<TemporalNode>,
74    /// The Temporal Graph edges
75    pub edges: Vec<TemporalEdge>,
76    /// The current operational Realm (Midgard/Asgard)
77    pub realm: Realm,
78    /// Last known pointer position (X, Y)
79    pub last_pointer_pos: [f32; 2],
80    /// Resolved pointer velocity (pixels per frame)
81    pub pointer_velocity: [f32; 2],
82    /// The current 'Focus' node ID (Odin's Eye focus)
83    pub odin_focus: Option<String>,
84    /// Agent attention heatmap (node_id -> intensity)
85    pub agent_attention: HashMap<String, f32>,
86    // Component state storage for dynamic state
87    #[serde(skip)]
88    pub component_states: HashMap<u64, Arc<std::sync::RwLock<dyn std::any::Any + Send + Sync>>>,
89}
90
91impl KnowledgeState {
92    /// Apply activation decay to all temporal nodes and evolving components.
93    /// Nodes with weight below a threshold drift out of the primary context.
94    /// Components lose vitality (Fafnir's Decay) if not actively 'fed'.
95    pub fn apply_decay(&mut self, decay_factor: f32) {
96        for node in &mut self.nodes {
97            node.weight *= decay_factor;
98        }
99
100        // Fafnir's Decay: Components naturally revert to base state over time
101        for state in self.component_states.values() {
102            if let Ok(mut lock) = state.write()
103                && let Some(v) = lock.downcast_mut::<f32>()
104            {
105                *v = (*v * decay_factor).max(1.0);
106            }
107        }
108    }
109
110    /// Increase the importance weight of nodes associated with a successful task.
111    pub fn reinforce(&mut self, node_ids: &[String], boost: f32) {
112        for node in &mut self.nodes {
113            if node_ids.contains(&node.id) {
114                node.weight += boost;
115            }
116        }
117    }
118
119    /// Update pointer kinematics based on a new position.
120    pub fn update_pointer(&mut self, new_pos: [f32; 2]) {
121        self.pointer_velocity = [
122            new_pos[0] - self.last_pointer_pos[0],
123            new_pos[1] - self.last_pointer_pos[1],
124        ];
125        self.last_pointer_pos = new_pos;
126    }
127}
128// Knowledge System Types
129/// Unique identifier for knowledge fragments
130pub type KnowledgeId = String;
131
132/// A knowledge fragment stored in the memory system
133#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct KnowledgeFragment {
135    /// Unique identifier for this fragment
136    pub id: String,
137    /// Short summary for prompt injection and quick search
138    pub summary: String,
139    /// Reference source (e.g. filename, URL, or conversation ID)
140    pub source: String,
141    /// Frame number or timestamp of creation
142    pub created_at: u64,
143    /// Number of times this fragment has been retrieved
144    pub accessed_count: u32,
145    /// Full content (optional, can be loaded on-demand)
146    pub content: Option<String>,
147}
148
149impl KnowledgeFragment {
150    pub fn new(id: String, summary: String, source: String) -> Self {
151        Self {
152            id,
153            summary,
154            source,
155            created_at: 0,
156            accessed_count: 0,
157            content: None,
158        }
159    }
160}
161
162/// Memory layers for the layered cognitive engine
163#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
164pub enum MemoryLayer {
165    /// Raw mission events (short-term)
166    Episodic,
167    /// Extracted facts and tactical intelligence (long-term)
168    Semantic,
169    /// Successful command sequences and tool chains
170    Procedural,
171}
172
173/// The operational Realm of the UI.
174/// Midgard: Classic, functional, 2D tactical UI for mortals.
175/// Asgard: High-fidelity, cognitive, shader-heavy UI for the Singularity.
176#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Default)]
177pub enum Realm {
178    Midgard,
179    #[default]
180    Asgard,
181}
182
183/// A node in the Temporal Graph representing a cognitive anchor
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct TemporalNode {
186    /// Unique identifier for this node
187    pub id: String,
188    /// ID of the underlying knowledge fragment
189    pub fragment_id: KnowledgeId,
190    /// Timestamp of the event
191    pub timestamp: u64,
192    /// The memory layer this node belongs to
193    pub layer: MemoryLayer,
194    /// Importance weight for activation decay and retrieval
195    pub weight: f32,
196}
197
198/// An edge in the Temporal Graph representing a relationship between nodes
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct TemporalEdge {
201    /// Source node ID
202    pub source: String,
203    /// Target node ID
204    pub target: String,
205    /// Type of relationship (e.g. "causal", "semantic", "temporal")
206    pub relation: String,
207    /// Weight/strength of the connection
208    pub weight: f32,
209}
210
211#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
212pub struct AssetKey(pub String);
213
214impl EnvKey for AssetKey {
215    type Value = Arc<dyn AssetManager>;
216    fn default_value() -> Self::Value {
217        Arc::new(DefaultAssetManager::new())
218    }
219}
220
221/// Asset state for async resource loading.
222#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
223pub enum AssetState<T> {
224    Loading,
225    Ready(T),
226    Error(String),
227}
228
229/// Design token value that can adapt to light/dark mode
230#[derive(Debug, Clone, Serialize, Deserialize)]
231#[serde(untagged)]
232pub enum TokenValue {
233    /// Single value (same for light and dark)
234    Single { value: String },
235    /// Different values for light and dark mode
236    Adaptive { light: String, dark: String },
237}
238
239/// YggdrasilTokens is the authoritative container for all design tokens in the CVKG ecosystem.
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct YggdrasilTokens {
242    pub color: HashMap<String, TokenValue>,
243    pub font: HashMap<String, TokenValue>,
244    pub spacing: HashMap<String, TokenValue>,
245    pub radius: HashMap<String, TokenValue>,
246    pub shadow: HashMap<String, TokenValue>,
247    pub border: HashMap<String, TokenValue>,
248    pub anim: HashMap<String, TokenValue>,
249    pub bifrost: HashMap<String, TokenValue>,
250    pub gungnir: HashMap<String, TokenValue>,
251    pub mjolnir: HashMap<String, TokenValue>,
252    pub accessibility: HashMap<String, TokenValue>,
253}
254
255impl Default for YggdrasilTokens {
256    fn default() -> Self {
257        Self::new()
258    }
259}
260
261impl YggdrasilTokens {
262    pub fn new() -> Self {
263        Self {
264            color: HashMap::new(),
265            font: HashMap::new(),
266            spacing: HashMap::new(),
267            radius: HashMap::new(),
268            shadow: HashMap::new(),
269            border: HashMap::new(),
270            anim: HashMap::new(),
271            bifrost: HashMap::new(),
272            gungnir: HashMap::new(),
273            mjolnir: HashMap::new(),
274            accessibility: HashMap::new(),
275        }
276    }
277
278    /// Get a color token value for the current mode
279    pub fn get_color(&self, key: &str, is_dark: bool) -> Option<String> {
280        self.color.get(key).map(|token| match token {
281            TokenValue::Single { value } => value.clone(),
282            TokenValue::Adaptive { light, dark } => {
283                if is_dark {
284                    dark.clone()
285                } else {
286                    light.clone()
287                }
288            }
289        })
290    }
291
292    /// Get a token value of any type and parse it into the target type
293    pub fn get<T: FromStr>(&self, category: &str, key: &str, is_dark: bool) -> Option<T> {
294        let map = match category {
295            "color" => &self.color,
296            "font" => &self.font,
297            "spacing" => &self.spacing,
298            "radius" => &self.radius,
299            "shadow" => &self.shadow,
300            "border" => &self.border,
301            "anim" => &self.anim,
302            "bifrost" => &self.bifrost,
303            "gungnir" => &self.gungnir,
304            "mjolnir" => &self.mjolnir,
305            "accessibility" => &self.accessibility,
306            _ => return None,
307        };
308
309        map.get(key).and_then(|token| match token {
310            TokenValue::Single { value } => value.parse().ok(),
311            TokenValue::Adaptive { light, dark } => {
312                let value = if is_dark { dark } else { light };
313                value.parse().ok()
314            }
315        })
316    }
317}
318
319pub trait View: Sized + Send {
320    /// The concrete type produced after applying modifiers.
321    /// For primitive views this is Self.
322    type Body: View;
323
324    fn body(self) -> Self::Body;
325
326    /// Render this view into the provided renderer at the specified bounds.
327    /// Primitive views override this to perform drawing operations.
328    fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
329
330    /// Calculate the natural (intrinsic) size of this view given proposed constraints.
331    /// This allows views like Buttons or Labels to inform the layout engine of their needs.
332    fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
333        Size::ZERO
334    }
335
336    /// Optionally provide a layout implementation for this view.
337    fn layout(&self) -> Option<&dyn layout::LayoutView> {
338        None
339    }
340
341    /// Returns the flex weight of this view for proportional distribution in stacks.
342    fn flex_weight(&self) -> f32 {
343        0.0
344    }
345
346    /// Provided modifier entry point
347    fn modifier<M: ViewModifier>(self, m: M) -> ModifiedView<Self, M> {
348        ModifiedView::new(self, m)
349    }
350
351    /// Apply a Bifrost (Frosted Glass) effect to the view
352    fn bifrost(
353        self,
354        blur: f32,
355        saturation: f32,
356        opacity: f32,
357    ) -> ModifiedView<Self, BifrostModifier> {
358        self.modifier(BifrostModifier {
359            blur,
360            saturation,
361            opacity,
362        })
363    }
364
365    /// Apply a Gungnir (Neon Glow) effect to the view
366    fn gungnir(
367        self,
368        color: impl Into<String>,
369        radius: f32,
370        intensity: f32,
371    ) -> ModifiedView<Self, GungnirModifier> {
372        self.modifier(GungnirModifier {
373            color: color.into(),
374            radius,
375            intensity,
376        })
377    }
378
379    /// Apply a Mjolnir Slice (Geometric cut) to the view
380    fn mjolnir_slice(self, angle: f32, offset: f32) -> ModifiedView<Self, MjolnirSliceModifier> {
381        self.modifier(MjolnirSliceModifier { angle, offset })
382    }
383
384    /// Apply a Mjolnir Shatter (Fragmented transition) to the view
385    fn mjolnir_shatter(
386        self,
387        pieces: u32,
388        force: f32,
389    ) -> ModifiedView<Self, MjolnirShatterModifier> {
390        self.modifier(MjolnirShatterModifier { pieces, force })
391    }
392
393    /// Mark this view as a Bifrost Bridge (Shared Element) for cross-view persistence
394    fn bifrost_bridge(self, id: impl Into<String>) -> ModifiedView<Self, BifrostBridgeModifier> {
395        self.modifier(BifrostBridgeModifier { id: id.into() })
396    }
397
398    /// Add a background color to this view
399    fn background(self, color: [f32; 4]) -> ModifiedView<Self, BackgroundModifier> {
400        self.modifier(BackgroundModifier { color })
401    }
402
403    /// Add padding to this view
404    fn padding(self, amount: f32) -> ModifiedView<Self, PaddingModifier> {
405        self.modifier(PaddingModifier { amount })
406    }
407
408    /// Set the opacity (alpha) of this view in the range [0.0, 1.0].
409    fn opacity(self, opacity: f32) -> ModifiedView<Self, OpacityModifier> {
410        self.modifier(OpacityModifier {
411            opacity: opacity.clamp(0.0, 1.0),
412        })
413    }
414
415    /// Override the foreground (text / icon) color of this view.
416    fn foreground_color(self, color: [f32; 4]) -> ModifiedView<Self, ForegroundColorModifier> {
417        self.modifier(ForegroundColorModifier { color })
418    }
419
420    /// Constrain this view to an explicit width and/or height.
421    fn frame(self, width: Option<f32>, height: Option<f32>) -> ModifiedView<Self, FrameModifier> {
422        self.modifier(FrameModifier { width, height })
423    }
424
425    /// Give this view a flex weight for proportional space distribution in stacks.
426    fn flex(self, weight: f32) -> ModifiedView<Self, FlexModifier> {
427        self.modifier(FlexModifier { weight })
428    }
429
430    /// Automatically add padding to avoid overlapping with platform safe areas (notches, bars).
431    fn safe_area_padding(self) -> ModifiedView<Self, SafeAreaModifier> {
432        self.modifier(SafeAreaModifier { ignores: false })
433    }
434
435    /// Explicitly ignore platform safe areas and draw into the margins.
436    fn ignores_safe_area(self) -> ModifiedView<Self, SafeAreaModifier> {
437        self.modifier(SafeAreaModifier { ignores: true })
438    }
439
440    /// Clip all child drawing to this view's bounds.
441    fn clip_to_bounds(self) -> ModifiedView<Self, ClipModifier> {
442        self.modifier(ClipModifier)
443    }
444
445    /// Draw a colored border around this view.
446    fn border(self, color: [f32; 4], width: f32) -> ModifiedView<Self, BorderModifier> {
447        self.modifier(BorderModifier { color, width })
448    }
449
450    /// Add elevation (shadow) to the view. Level determines the shadow depth.
451    fn elevation(self, level: f32) -> ModifiedView<Self, ElevationModifier> {
452        self.modifier(ElevationModifier { level })
453    }
454
455    /// Add a magnetic effect that pulls the view towards the cursor.
456    fn magnetic(self, radius: f32, intensity: f32) -> ModifiedView<Self, MagneticModifier> {
457        self.modifier(MagneticModifier { radius, intensity })
458    }
459
460    /// Add a ManiGlow (Lunar Illuminator) effect that glows near the cursor.
461    fn mani_glow(self, color: [f32; 4], radius: f32) -> ModifiedView<Self, ManiGlowModifier> {
462        self.modifier(ManiGlowModifier { color, radius })
463    }
464
465    /// Theme this view based on a specific memory layer.
466    fn memory_layer(self, layer: MemoryLayer) -> ModifiedView<Self, BifrostLayerModifier> {
467        self.modifier(BifrostLayerModifier { layer })
468    }
469
470    /// Enable Fafnir's Evolution: The component grows and glows as it is used.
471    fn fafnir_evolve(self, id: u64) -> ModifiedView<Self, FafnirModifier> {
472        self.modifier(FafnirModifier { id })
473    }
474
475    /// Enable Mimir's Intent: The component anticipates user interaction via pointer kinematics.
476    fn mimir_intent(self) -> ModifiedView<Self, MimirIntentModifier> {
477        self.modifier(MimirIntentModifier)
478    }
479
480    /// Enable Kvasir's Vibes: Subconscious telemetry representing cognitive complexity.
481    fn kvasir_vibes(self, complexity: f32) -> ModifiedView<Self, KvasirVibeModifier> {
482        self.modifier(KvasirVibeModifier { complexity })
483    }
484
485    /// Bestow Odin's Eye: Global omniscient observability layer.
486    fn odins_eye(self) -> ModifiedView<Self, OdinsEyeModifier> {
487        self.modifier(OdinsEyeModifier)
488    }
489
490    /// Trigger an action when the view appears
491    fn on_appear<F: Fn() + Send + Sync + 'static>(
492        self,
493        action: F,
494    ) -> ModifiedView<Self, LifecycleModifier> {
495        self.modifier(LifecycleModifier {
496            on_appear: Some(Arc::new(action)),
497            on_disappear: None,
498        })
499    }
500
501    /// Trigger an action when the view disappears
502    fn on_disappear<F: Fn() + Send + Sync + 'static>(
503        self,
504        action: F,
505    ) -> ModifiedView<Self, LifecycleModifier> {
506        self.modifier(LifecycleModifier {
507            on_appear: None,
508            on_disappear: Some(Arc::new(action)),
509        })
510    }
511
512    /// Trigger an action when the view is clicked
513    fn on_click<F: Fn() + Send + Sync + 'static>(
514        self,
515        action: F,
516    ) -> ModifiedView<Self, OnClickModifier> {
517        self.modifier(OnClickModifier {
518            action: Arc::new(action),
519        })
520    }
521
522    /// Trigger an action when the pointer enters the view bounds
523    fn on_pointer_enter<F: Fn() + Send + Sync + 'static>(
524        self,
525        action: F,
526    ) -> ModifiedView<Self, OnPointerEnterModifier> {
527        self.modifier(OnPointerEnterModifier {
528            action: Arc::new(action),
529        })
530    }
531
532    /// Trigger an action when the pointer leaves the view bounds
533    fn on_pointer_leave<F: Fn() + Send + Sync + 'static>(
534        self,
535        action: F,
536    ) -> ModifiedView<Self, OnPointerLeaveModifier> {
537        self.modifier(OnPointerLeaveModifier {
538            action: Arc::new(action),
539        })
540    }
541
542    /// Trigger an action when the pointer moves inside the view bounds
543    fn on_pointer_move<F: Fn(f32, f32) + Send + Sync + 'static>(
544        self,
545        action: F,
546    ) -> ModifiedView<Self, OnPointerMoveModifier> {
547        self.modifier(OnPointerMoveModifier {
548            action: Arc::new(action),
549        })
550    }
551
552    /// Trigger an action when the pointer is pressed down
553    fn on_pointer_down<F: Fn() + Send + Sync + 'static>(
554        self,
555        action: F,
556    ) -> ModifiedView<Self, OnPointerDownModifier> {
557        self.modifier(OnPointerDownModifier {
558            action: Arc::new(action),
559        })
560    }
561
562    /// Trigger an action when the pointer is released
563    fn on_pointer_up<F: Fn() + Send + Sync + 'static>(
564        self,
565        action: F,
566    ) -> ModifiedView<Self, OnPointerUpModifier> {
567        self.modifier(OnPointerUpModifier {
568            action: Arc::new(action),
569        })
570    }
571
572    /// Type-erase this view into AnyView
573    fn erase(self) -> AnyView
574    where
575        Self: Clone + 'static,
576    {
577        AnyView::new(self)
578    }
579}
580
581/// An object-safe version of the View trait for type erasure.
582pub trait ErasedView: Send {
583    fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect);
584    fn name(&self) -> &'static str;
585    fn flex_weight_erased(&self) -> f32;
586    fn layout_erased(&self) -> Option<&dyn layout::LayoutView>;
587    fn clone_box(&self) -> Box<dyn ErasedView>;
588}
589
590impl<V: View + Clone + 'static> ErasedView for V {
591    fn render_erased(&self, renderer: &mut dyn Renderer, rect: Rect) {
592        self.render(renderer, rect);
593    }
594
595    fn name(&self) -> &'static str {
596        std::any::type_name::<V>()
597    }
598
599    fn flex_weight_erased(&self) -> f32 {
600        self.flex_weight()
601    }
602
603    fn layout_erased(&self) -> Option<&dyn layout::LayoutView> {
604        self.layout()
605    }
606
607    fn clone_box(&self) -> Box<dyn ErasedView> {
608        Box::new(self.clone())
609    }
610}
611
612/// A view that memoizes its rendering based on a stable ID and data hash.
613/// The renderer can use this to skip re-rendering the sub-tree if the data hasn't changed.
614pub struct MemoView<V, F> {
615    id: u64,
616    data_hash: u64,
617    builder: F,
618    _v: std::marker::PhantomData<V>,
619}
620
621impl<V: View, F: Fn() -> V + Send + Sync> MemoView<V, F> {
622    /// Create a new MemoView with a stable ID and a data hash.
623    pub fn new(id: u64, data_hash: u64, builder: F) -> Self {
624        Self {
625            id,
626            data_hash,
627            builder,
628            _v: std::marker::PhantomData,
629        }
630    }
631}
632
633impl<V: View + 'static, F: Fn() -> V + Send + Sync + 'static> View for MemoView<V, F> {
634    type Body = Never;
635    fn body(self) -> Self::Body {
636        unreachable!("MemoView does not have a body")
637    }
638
639    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
640        renderer.memoize(self.id, self.data_hash, &|r| {
641            let view = (self.builder)();
642            view.render(r, rect);
643        });
644    }
645}
646
647/// A type-erased View wrapper.
648pub struct AnyView {
649    inner: Box<dyn ErasedView>,
650}
651
652impl Clone for AnyView {
653    fn clone(&self) -> Self {
654        Self {
655            inner: self.inner.clone_box(),
656        }
657    }
658}
659
660impl AnyView {
661    pub fn new<V: View + Clone + 'static>(view: V) -> Self {
662        Self {
663            inner: Box::new(view),
664        }
665    }
666}
667
668impl View for AnyView {
669    type Body = Never;
670    fn body(self) -> Self::Body {
671        unreachable!()
672    }
673
674    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
675        renderer.push_vnode(rect, self.inner.name());
676        self.inner.render_erased(renderer, rect);
677        renderer.pop_vnode();
678    }
679
680    fn flex_weight(&self) -> f32 {
681        self.inner.flex_weight_erased()
682    }
683
684    fn layout(&self) -> Option<&dyn layout::LayoutView> {
685        self.inner.layout_erased()
686    }
687}
688
689/// BifrostBridgeModifier enables shared-element transitions.
690/// When two views share the same Bifrost Bridge ID, the Sleipnir solver will
691/// interpolate their geometry and effects (blur, glow) during the transition.
692#[derive(Debug, Clone, PartialEq)]
693pub struct BifrostBridgeModifier {
694    pub id: String,
695}
696
697impl ViewModifier for BifrostBridgeModifier {
698    fn modify<V: View>(self, content: V) -> impl View {
699        ModifiedView::new(content, self)
700    }
701
702    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
703        // Register this element with the renderer for shared-element transition logic
704        renderer.register_shared_element(&self.id, rect);
705    }
706}
707
708/// MjolnirSliceModifier implements the "Geometric Slice" aesthetic.
709/// It uses a signed distance field (SDF) to clip the view along a sharp angled line.
710#[derive(Debug, Clone, Copy, PartialEq)]
711pub struct MjolnirSliceModifier {
712    pub angle: f32,
713    pub offset: f32,
714}
715
716impl ViewModifier for MjolnirSliceModifier {
717    fn modify<V: View>(self, content: V) -> impl View {
718        ModifiedView::new(content, self)
719    }
720
721    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
722        renderer.push_mjolnir_slice(self.angle, self.offset);
723    }
724
725    fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
726        renderer.pop_mjolnir_slice();
727    }
728}
729
730/// MjolnirShatterModifier implements the "Shattering" effect.
731/// It breaks the view into discrete geometric fragments that can be animated.
732#[derive(Debug, Clone, Copy, PartialEq)]
733pub struct MjolnirShatterModifier {
734    pub pieces: u32,
735    pub force: f32,
736}
737
738impl ViewModifier for MjolnirShatterModifier {
739    fn modify<V: View>(self, content: V) -> impl View {
740        ModifiedView::new(content, self)
741    }
742
743    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
744        // RADIAL SHATTER: Fragment the view into wedges
745        let pieces = self.pieces.max(1);
746        for i in 0..pieces {
747            let progress = i as f32 / pieces as f32;
748            let next_progress = (i + 1) as f32 / pieces as f32;
749
750            let angle_start = progress * 360.0;
751            let angle_end = next_progress * 360.0;
752
753            // Wedge slice: intersection of two half-planes
754            renderer.push_mjolnir_slice(angle_start, 0.0);
755            renderer.push_mjolnir_slice(angle_end + 180.0, 0.0);
756
757            // Apply radial force offset
758            let mid_angle = (angle_start + angle_end) / 2.0;
759            let rad = mid_angle.to_radians();
760            let dx = rad.cos() * self.force;
761            let dy = rad.sin() * self.force;
762
763            let shard_rect = Rect {
764                x: rect.x + dx,
765                y: rect.y + dy,
766                ..rect
767            };
768
769            view.render(renderer, shard_rect);
770
771            renderer.pop_mjolnir_slice();
772            renderer.pop_mjolnir_slice();
773        }
774    }
775}
776
777/// BifrostModifier implements the Cyberpunk "Frosted Glass" aesthetic.
778/// It triggers backdrop blurring and light scattering in the render pipeline.
779#[derive(Debug, Clone, Copy, PartialEq)]
780pub struct BifrostModifier {
781    pub blur: f32,
782    pub saturation: f32,
783    pub opacity: f32,
784}
785
786impl ViewModifier for BifrostModifier {
787    fn modify<V: View>(self, content: V) -> impl View {
788        ModifiedView::new(content, self)
789    }
790
791    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
792        if renderer.is_over_budget() {
793            // Degrade: Use lower quality (half blur) if over budget
794            renderer.bifrost(rect, self.blur * 0.5, self.saturation, self.opacity);
795        } else {
796            renderer.bifrost(rect, self.blur, self.saturation, self.opacity);
797        }
798    }
799}
800
801/// A modifier that adds a background color to a view.
802#[derive(Debug, Clone, Copy, PartialEq)]
803pub struct BackgroundModifier {
804    pub color: [f32; 4],
805}
806
807impl ViewModifier for BackgroundModifier {
808    fn modify<V: View>(self, content: V) -> impl View {
809        ModifiedView::new(content, self)
810    }
811
812    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
813        renderer.fill_rect(rect, self.color);
814    }
815}
816
817/// A modifier that adds padding to a view.
818#[derive(Debug, Clone, Copy, PartialEq)]
819pub struct PaddingModifier {
820    pub amount: f32,
821}
822
823impl ViewModifier for PaddingModifier {
824    fn modify<V: View>(self, content: V) -> impl View {
825        ModifiedView::new(content, self)
826    }
827
828    fn transform_rect(&self, rect: Rect) -> Rect {
829        Rect {
830            x: rect.x + self.amount,
831            y: rect.y + self.amount,
832            width: (rect.width - 2.0 * self.amount).max(0.0),
833            height: (rect.height - 2.0 * self.amount).max(0.0),
834        }
835    }
836
837    fn transform_proposal(&self, mut proposal: SizeProposal) -> SizeProposal {
838        if let Some(w) = proposal.width {
839            proposal.width = Some((w - 2.0 * self.amount).max(0.0));
840        }
841        if let Some(h) = proposal.height {
842            proposal.height = Some((h - 2.0 * self.amount).max(0.0));
843        }
844        proposal
845    }
846
847    fn transform_size(&self, mut size: Size) -> Size {
848        size.width += 2.0 * self.amount;
849        size.height += 2.0 * self.amount;
850        size
851    }
852}
853
854/// GungnirModifier implements the "Neon Glow" aesthetic.
855/// It uses additive blending and multi-pass blurring to simulate glowing light.
856#[derive(Debug, Clone, PartialEq)]
857pub struct GungnirModifier {
858    pub color: String,
859    pub radius: f32,
860    pub intensity: f32,
861}
862
863impl ViewModifier for GungnirModifier {
864    fn modify<V: View>(self, content: V) -> impl View {
865        ModifiedView::new(content, self)
866    }
867
868    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
869        // Neon Glow using Mode 1 in the Surtr pipeline
870        renderer.stroke_rect(rect, [0.0, 1.0, 1.0, self.intensity], self.radius / 10.0);
871    }
872}
873
874/// GungnirPulseModifier implements a "breathing" neon effect.
875#[derive(Debug, Clone, Copy, PartialEq)]
876pub struct GungnirPulseModifier {
877    pub color: [f32; 4],
878    pub radius: f32,
879    pub speed: f32,
880}
881
882impl ViewModifier for GungnirPulseModifier {
883    fn modify<V: View>(self, content: V) -> impl View {
884        ModifiedView::new(content, self)
885    }
886
887    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
888        let time = std::time::SystemTime::now()
889            .duration_since(std::time::UNIX_EPOCH)
890            .unwrap_or_default()
891            .as_secs_f32();
892
893        // Mode 19: Dashed Border
894        // Mode 20: 9-Slice / Patch Scaling
895        let intensity = (time * self.speed).sin() * 0.5 + 0.5;
896        let mut color = self.color;
897        color[3] *= intensity;
898
899        // Mode 1 neon glow with dynamic intensity
900        renderer.stroke_rect(rect, color, self.radius);
901    }
902}
903
904/// MagneticModifier makes a view "magnetic", subtly leaning towards or pulling the cursor.
905#[derive(Debug, Clone, Copy, PartialEq)]
906pub struct MagneticModifier {
907    pub radius: f32,
908    pub intensity: f32,
909}
910
911impl ViewModifier for MagneticModifier {
912    fn modify<V: View>(self, content: V) -> impl View {
913        ModifiedView::new(content, self)
914    }
915
916    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
917        let [px, py] = renderer.get_pointer_position();
918        let center_x = rect.x + rect.width / 2.0;
919        let center_y = rect.y + rect.height / 2.0;
920
921        let dx = px - center_x;
922        let dy = py - center_y;
923        let dist = (dx * dx + dy * dy).sqrt();
924
925        let mut offset_x = 0.0;
926        let mut offset_y = 0.0;
927
928        if dist < self.radius && dist > 0.0 {
929            let force = (1.0 - dist / self.radius) * self.intensity;
930            offset_x = dx * force;
931            offset_y = dy * force;
932        }
933
934        let magnetic_rect = Rect {
935            x: rect.x + offset_x,
936            y: rect.y + offset_y,
937            ..rect
938        };
939
940        view.render(renderer, magnetic_rect);
941    }
942}
943
944/// ManiGlowModifier adds a soft, lunar-like cursor glow to a view.
945/// Named after Máni, the personification of the Moon.
946#[derive(Debug, Clone, Copy, PartialEq)]
947pub struct ManiGlowModifier {
948    pub color: [f32; 4],
949    pub radius: f32,
950}
951
952impl ViewModifier for ManiGlowModifier {
953    fn modify<V: View>(self, content: V) -> impl View {
954        ModifiedView::new(content, self)
955    }
956
957    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
958        if crate::load_system_state().realm == Realm::Asgard {
959            renderer.mani_glow(rect, self.color, self.radius);
960        }
961        view.render(renderer, rect);
962    }
963}
964
965/// BifrostLayerModifier themes a view based on its cognitive memory layer.
966/// Episodic: Shifting aurora clouds.
967/// Semantic: Crystalline gold.
968/// Procedural: Heavy obsidian stone.
969#[derive(Debug, Clone, Copy, PartialEq)]
970pub struct BifrostLayerModifier {
971    pub layer: MemoryLayer,
972}
973
974impl ViewModifier for BifrostLayerModifier {
975    fn modify<V: View>(self, content: V) -> impl View {
976        ModifiedView::new(content, self)
977    }
978
979    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
980        let realm = crate::load_system_state().realm;
981        match self.layer {
982            MemoryLayer::Episodic => {
983                if realm == Realm::Asgard {
984                    renderer.bifrost(rect, 40.0, 1.2, 0.7);
985                } else {
986                    renderer.fill_rect(rect, [0.1, 0.12, 0.15, 0.8]);
987                }
988            }
989            MemoryLayer::Semantic => {
990                if realm == Realm::Asgard {
991                    renderer.gungnir(rect, [1.0, 0.84, 0.0, 1.0], 15.0, 0.6);
992                } else {
993                    renderer.stroke_rect(rect, [0.4, 0.4, 0.4, 1.0], 1.5);
994                }
995            }
996            MemoryLayer::Procedural => {
997                renderer.fill_rect(rect, [0.05, 0.05, 0.07, 0.95]);
998                let stroke_color = if realm == Realm::Asgard {
999                    [0.3, 0.3, 0.3, 1.0]
1000                } else {
1001                    [0.2, 0.2, 0.2, 1.0]
1002                };
1003                renderer.stroke_rect(rect, stroke_color, 2.0);
1004            }
1005        }
1006        view.render(renderer, rect);
1007    }
1008}
1009
1010/// FafnirModifier enables self-evolving UI capabilities.
1011/// Named after Fafnir, the dragon who grows in power based on the gold he hoards.
1012/// In CVKG, 'Gold' is user attention/interaction.
1013#[derive(Debug, Clone, Copy, PartialEq)]
1014pub struct FafnirModifier {
1015    /// Unique ID for tracking this component's vitality across frames.
1016    pub id: u64,
1017}
1018
1019impl ViewModifier for FafnirModifier {
1020    fn modify<V: View>(self, content: V) -> impl View {
1021        ModifiedView::new(content, self)
1022    }
1023
1024    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1025        let state = crate::load_system_state();
1026        let vitality = state
1027            .get_component_state::<f32>(self.id)
1028            .map(|v| *v.read().unwrap())
1029            .unwrap_or(1.0);
1030
1031        // Calculate evolutionary growth factors
1032        // Max growth at vitality 5.0 (50% scale increase, strong glow)
1033        let growth = (vitality - 1.0).clamp(0.0, 4.0);
1034        let scale = 1.0 + growth * 0.12;
1035        let glow_intensity = growth * 0.25;
1036
1037        // Feed Fafnir: Register interaction to boost vitality
1038        let id = self.id;
1039        renderer.register_handler(
1040            "pointermove",
1041            std::sync::Arc::new(move |_| {
1042                crate::update_system_state(|s| {
1043                    let mut s = s.clone();
1044                    let v = s
1045                        .get_component_state::<f32>(id)
1046                        .map(|v| *v.read().unwrap())
1047                        .unwrap_or(1.0);
1048                    s.set_component_state(id, (v + 0.05).min(5.0)); // Cap at 5.0
1049                    s
1050                });
1051            }),
1052        );
1053
1054        if scale > 1.01 {
1055            renderer.push_transform([0.0, 0.0], [scale, scale], 0.0);
1056        }
1057
1058        if glow_intensity > 0.1 && state.realm == Realm::Asgard {
1059            renderer.gungnir(rect, [1.0, 0.84, 0.0, 1.0], 15.0 * vitality, glow_intensity);
1060        }
1061
1062        view.render(renderer, rect);
1063
1064        if scale > 1.01 {
1065            renderer.pop_transform();
1066        }
1067    }
1068}
1069
1070/// MimirIntentModifier anticipates user movement and manifests holographic ghosts.
1071#[derive(Debug, Clone, Copy, PartialEq)]
1072pub struct MimirIntentModifier;
1073
1074impl ViewModifier for MimirIntentModifier {
1075    fn modify<V: View>(self, content: V) -> impl View {
1076        ModifiedView::new(content, self)
1077    }
1078
1079    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1080        let state = crate::load_system_state();
1081        let pos = state.last_pointer_pos;
1082        let vel = state.pointer_velocity;
1083
1084        // Calculate if the cursor is moving towards this rect
1085        let center = [rect.x + rect.width / 2.0, rect.y + rect.height / 2.0];
1086        let dx = center[0] - pos[0];
1087        let dy = center[1] - pos[1];
1088
1089        // Dot product of velocity and direction to center
1090        let dot = vel[0] * dx + vel[1] * dy;
1091        let speed_sq = vel[0] * vel[0] + vel[1] * vel[1];
1092        let dist_sq = dx * dx + dy * dy;
1093
1094        if dot > 0.0 && dist_sq < 250.0 * 250.0 && speed_sq > 0.5 && state.realm == Realm::Asgard {
1095            // Intent detected: render a subtle "ghost" reveal
1096            let intent_strength = (dot / (speed_sq.sqrt() * dist_sq.sqrt())).clamp(0.0, 1.0);
1097            renderer.stroke_rect(rect, [0.0, 0.9, 1.0, 0.3 * intent_strength], 1.5);
1098        }
1099
1100        view.render(renderer, rect);
1101    }
1102}
1103
1104/// KvasirVibeModifier renders a cognitive telemetry cloud representing agent complexity.
1105#[derive(Debug, Clone, Copy, PartialEq)]
1106pub struct KvasirVibeModifier {
1107    pub complexity: f32,
1108}
1109
1110impl ViewModifier for KvasirVibeModifier {
1111    fn modify<V: View>(self, content: V) -> impl View {
1112        ModifiedView::new(content, self)
1113    }
1114
1115    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1116        if crate::load_system_state().realm == Realm::Asgard {
1117            let t = renderer.elapsed_time();
1118            let c = self.complexity.clamp(0.0, 1.0);
1119
1120            // 1. Core Cognitive Cloud (Bifrost)
1121            // Turbulence increases with complexity
1122            let blur = 20.0 + c * 40.0;
1123            let turbulence_x = (t * (1.0 + c * 2.0)).sin() * 8.0 * c;
1124            let turbulence_y = (t * (0.8 + c * 1.5)).cos() * 5.0 * c;
1125            renderer.bifrost(
1126                rect.offset(turbulence_x, turbulence_y),
1127                blur,
1128                0.8 + c * 0.4,
1129                0.25,
1130            );
1131
1132            // 2. Synaptic Discharge (Gungnir pulses)
1133            if c > 0.2 {
1134                let pulse = (t * (3.0 + c * 5.0)).sin().abs() * c;
1135                let color = [0.0, 0.9, 1.0, 0.4 * pulse]; // Cyan synaptic pulse
1136                renderer.gungnir(rect, color, 12.0 + c * 24.0, 0.6 * pulse);
1137            }
1138
1139            // 3. Unstable Resonance (Magenta/Red shift for high complexity)
1140            if c > 0.7 {
1141                let instability = (t * 15.0).cos().abs() * (c - 0.7) * 3.3;
1142                let warning_color = [1.0, 0.0, 0.4, 0.12 * instability];
1143                renderer.fill_rect(rect, warning_color);
1144                renderer.stroke_rect(rect, [1.0, 0.0, 0.2, 0.45 * instability], 1.8);
1145            }
1146        }
1147        view.render(renderer, rect);
1148    }
1149}
1150
1151/// OdinsEyeModifier bestows omniscient observability over the entire scene graph.
1152#[derive(Debug, Clone, Copy, PartialEq)]
1153pub struct OdinsEyeModifier;
1154
1155impl ViewModifier for OdinsEyeModifier {
1156    fn modify<V: View>(self, content: V) -> impl View {
1157        ModifiedView::new(content, self)
1158    }
1159
1160    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1161        let state = crate::load_system_state();
1162        let t = renderer.elapsed_time();
1163
1164        // 1. Render Background content
1165        view.render(renderer, rect);
1166
1167        if state.realm == Realm::Asgard {
1168            // 2. Bestow Odin's Eye (Atmospheric Overlay)
1169            // Soft, large circular pulse representing the 'Eye'
1170            let eye_pulse = (t * 0.5).sin().abs() * 0.05;
1171            renderer.draw_radial_gradient(
1172                rect,
1173                [0.0, 0.6, 0.8, 0.08 + eye_pulse], // Inner Cyan
1174                [0.0, 0.0, 0.0, 0.0],              // Outer Black
1175            );
1176
1177            // 3. Hugin (Thought) Telemetry - Left Side
1178            let hugin_rect = Rect {
1179                x: rect.x + 20.0,
1180                y: rect.y + 40.0,
1181                width: 200.0,
1182                height: rect.height - 80.0,
1183            };
1184            renderer.draw_text(
1185                "HUGIN: THOUGHT",
1186                hugin_rect.x,
1187                hugin_rect.y,
1188                10.0,
1189                [0.0, 1.0, 1.0, 0.6],
1190            );
1191            for (i, thought) in state.thoughts.iter().rev().take(10).enumerate() {
1192                renderer.draw_text(
1193                    thought,
1194                    hugin_rect.x,
1195                    hugin_rect.y + 20.0 + i as f32 * 14.0,
1196                    9.0,
1197                    [1.0, 1.0, 1.0, 0.4],
1198                );
1199            }
1200
1201            // 4. Munin (Memory) Telemetry - Right Side
1202            let munin_rect = Rect {
1203                x: rect.x + rect.width - 220.0,
1204                y: rect.y + 40.0,
1205                width: 200.0,
1206                height: rect.height - 80.0,
1207            };
1208            renderer.draw_text(
1209                "MUNIN: MEMORY",
1210                munin_rect.x,
1211                munin_rect.y,
1212                10.0,
1213                [1.0, 0.84, 0.0, 0.6],
1214            );
1215            for (i, node) in state.nodes.iter().take(10).enumerate() {
1216                let opacity = (node.weight.min(1.0)) * 0.5;
1217                renderer.draw_text(
1218                    &node.id,
1219                    munin_rect.x,
1220                    munin_rect.y + 20.0 + i as f32 * 14.0,
1221                    9.0,
1222                    [1.0, 1.0, 1.0, opacity],
1223                );
1224            }
1225
1226            // 5. Omniscient Focus Beams (Gungnir Beams)
1227            if let Some(focus_id) = &state.odin_focus {
1228                // Visualize causal links to the focus node
1229                renderer.draw_text(
1230                    &format!("EYE FOCUS: {}", focus_id),
1231                    rect.x + rect.width / 2.0 - 50.0,
1232                    rect.y + 20.0,
1233                    12.0,
1234                    [0.0, 1.0, 1.0, 0.8],
1235                );
1236
1237                // In a real implementation, we would find the rect of the focus_id component.
1238                // For the 'Eye', we manifest a central beam of wisdom.
1239                renderer.gungnir(
1240                    Rect {
1241                        x: rect.x + rect.width / 2.0 - 1.0,
1242                        y: rect.y,
1243                        width: 2.0,
1244                        height: rect.height,
1245                    },
1246                    [0.0, 1.0, 1.0, 1.0],
1247                    20.0,
1248                    0.4,
1249                );
1250            }
1251        }
1252    }
1253}
1254
1255/// Sleipnir spring parameters for the physics solver
1256#[derive(Debug, Clone, Copy, PartialEq)]
1257pub struct SleipnirParams {
1258    pub stiffness: f32,
1259    pub damping: f32,
1260    pub mass: f32,
1261}
1262
1263impl SleipnirParams {
1264    pub fn snappy() -> Self {
1265        Self {
1266            stiffness: 230.0,
1267            damping: 22.0,
1268            mass: 1.0,
1269        }
1270    }
1271    pub fn fluid() -> Self {
1272        Self {
1273            stiffness: 170.0,
1274            damping: 26.0,
1275            mass: 1.0,
1276        }
1277    }
1278    pub fn heavy() -> Self {
1279        Self {
1280            stiffness: 90.0,
1281            damping: 20.0,
1282            mass: 1.0,
1283        }
1284    }
1285    pub fn bouncy() -> Self {
1286        Self {
1287            stiffness: 190.0,
1288            damping: 14.0,
1289            mass: 1.0,
1290        }
1291    }
1292}
1293
1294impl Default for SleipnirParams {
1295    fn default() -> Self {
1296        Self::fluid()
1297    }
1298}
1299
1300#[derive(Debug, Clone, Copy, PartialEq)]
1301struct SolverState {
1302    x: f32,
1303    v: f32,
1304}
1305
1306/// SleipnirSolver implements a 4th-order Runge-Kutta (RK4) integration for springs.
1307/// This provides superior stability for high-fidelity interactive motion.
1308#[derive(Debug, Clone, Copy, PartialEq)]
1309pub struct SleipnirSolver {
1310    params: SleipnirParams,
1311    target: f32,
1312    state: SolverState,
1313}
1314
1315impl SleipnirSolver {
1316    /// Create a new solver with a target value and starting state.
1317    pub fn new(params: SleipnirParams, target: f32, current: f32) -> Self {
1318        Self {
1319            params,
1320            target,
1321            state: SolverState { x: current, v: 0.0 },
1322        }
1323    }
1324
1325    /// Advance the simulation by dt seconds using RK4 integration.
1326    pub fn tick(&mut self, dt: f32) -> f32 {
1327        if dt <= 0.0 {
1328            return self.state.x;
1329        }
1330
1331        // Use a fixed time step for stability if dt is too large
1332        let mut remaining = dt;
1333        let step = 1.0 / 120.0;
1334
1335        while remaining > 0.0 {
1336            let d = remaining.min(step);
1337            self.step(d);
1338            remaining -= d;
1339        }
1340
1341        self.state.x
1342    }
1343
1344    fn step(&mut self, dt: f32) {
1345        let a = self.evaluate(self.state, 0.0, SolverState { x: 0.0, v: 0.0 });
1346        let b = self.evaluate(self.state, dt * 0.5, a);
1347        let c = self.evaluate(self.state, dt * 0.5, b);
1348        let d = self.evaluate(self.state, dt, c);
1349
1350        let dxdt = 1.0 / 6.0 * (a.x + 2.0 * (b.x + c.x) + d.x);
1351        let dvdt = 1.0 / 6.0 * (a.v + 2.0 * (b.v + c.v) + d.v);
1352
1353        self.state.x += dxdt * dt;
1354        self.state.v += dvdt * dt;
1355    }
1356
1357    fn evaluate(&self, initial: SolverState, dt: f32, d: SolverState) -> SolverState {
1358        let state = SolverState {
1359            x: initial.x + d.x * dt,
1360            v: initial.v + d.v * dt,
1361        };
1362        let force =
1363            -self.params.stiffness * (state.x - self.target) - self.params.damping * state.v;
1364        let mass = self.params.mass.max(0.001);
1365        SolverState {
1366            x: state.v,
1367            v: force / mass,
1368        }
1369    }
1370
1371    pub fn is_settled(&self) -> bool {
1372        (self.state.x - self.target).abs() < 0.001 && self.state.v.abs() < 0.001
1373    }
1374
1375    pub fn set_target(&mut self, target: f32) {
1376        self.target = target;
1377    }
1378
1379    pub fn current_value(&self) -> f32 {
1380        self.state.x
1381    }
1382}
1383
1384/// SleipnirModifier handles physics-based animations via the Sleipnir RK4 solver.
1385#[derive(Debug, Clone, PartialEq)]
1386pub struct SleipnirModifier {
1387    pub id: u64,
1388    pub target: f32,
1389    pub params: SleipnirParams,
1390}
1391
1392impl ViewModifier for SleipnirModifier {
1393    fn modify<V: View>(self, content: V) -> impl View {
1394        ModifiedView::new(content, self)
1395    }
1396
1397    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1398        let state = load_system_state();
1399
1400        // Try to fetch the solver from persistent state.
1401        let solver_lock_opt = state.get_component_state::<SleipnirSolver>(self.id);
1402
1403        let current_val;
1404
1405        if let Some(lock) = solver_lock_opt {
1406            // Found a solver. Tick it.
1407            let mut solver = lock.write().unwrap();
1408            solver.set_target(self.target);
1409            current_val = solver.tick(renderer.delta_time());
1410
1411            // If the solver hasn't settled yet, request another frame.
1412            if !solver.is_settled() {
1413                renderer.request_redraw();
1414            }
1415        } else {
1416            // First time seeing this ID. Initialize solver state.
1417            let solver = SleipnirSolver::new(
1418                self.params,
1419                self.target,
1420                self.target, // Initialize at target to avoid jump on first frame
1421            );
1422
1423            // Insert into registry for next frame.
1424            get_system_state().rcu(|old| {
1425                let mut new_state = (**old).clone();
1426                new_state.set_component_state(self.id, solver);
1427                new_state
1428            });
1429
1430            current_val = self.target;
1431        }
1432
1433        // Apply the solved value as a vertical translation.
1434        renderer.push_transform([0.0, current_val], [1.0, 1.0], 0.0);
1435        view.render(renderer, rect);
1436        renderer.pop_transform();
1437    }
1438}
1439
1440/// TransformModifier applies a 2D transform (translation, scale, rotation) to its child.
1441/// This modifier is "layout-neutral" and can be animated without re-running the layout engine.
1442#[derive(Debug, Clone, Copy, PartialEq)]
1443pub struct TransformModifier {
1444    pub translation: [f32; 2],
1445    pub scale: [f32; 2],
1446    pub rotation: f32,
1447}
1448
1449impl Default for TransformModifier {
1450    fn default() -> Self {
1451        Self::new()
1452    }
1453}
1454
1455impl TransformModifier {
1456    pub fn new() -> Self {
1457        Self {
1458            translation: [0.0, 0.0],
1459            scale: [1.0, 1.0],
1460            rotation: 0.0,
1461        }
1462    }
1463
1464    pub fn translate(mut self, x: f32, y: f32) -> Self {
1465        self.translation = [x, y];
1466        self
1467    }
1468
1469    pub fn scale(mut self, x: f32, y: f32) -> Self {
1470        self.scale = [x, y];
1471        self
1472    }
1473
1474    pub fn rotate(mut self, radians: f32) -> Self {
1475        self.rotation = radians;
1476        self
1477    }
1478}
1479
1480impl ViewModifier for TransformModifier {
1481    fn modify<V: View>(self, content: V) -> impl View {
1482        ModifiedView::new(content, self)
1483    }
1484
1485    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1486        renderer.push_transform(self.translation, self.scale, self.rotation);
1487        view.render(renderer, rect);
1488        renderer.pop_transform();
1489    }
1490}
1491
1492/// LifecycleModifier handles on_appear and on_disappear hooks.
1493
1494#[derive(Clone)]
1495pub struct LifecycleModifier {
1496    pub on_appear: Option<Arc<dyn Fn() + Send + Sync>>,
1497    pub on_disappear: Option<Arc<dyn Fn() + Send + Sync>>,
1498}
1499
1500impl ViewModifier for LifecycleModifier {
1501    fn modify<V: View>(self, content: V) -> impl View {
1502        ModifiedView::new(content, self)
1503    }
1504}
1505
1506/// OpacityModifier fades this view and all its descendants to the given alpha.
1507/// The renderer is expected to honour `push_opacity`/`pop_opacity` on the Renderer trait.
1508#[derive(Debug, Clone, Copy, PartialEq)]
1509pub struct OpacityModifier {
1510    pub opacity: f32,
1511}
1512
1513impl ViewModifier for OpacityModifier {
1514    fn modify<V: View>(self, content: V) -> impl View {
1515        ModifiedView::new(content, self)
1516    }
1517
1518    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1519        renderer.push_opacity(self.opacity);
1520    }
1521
1522    fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1523        renderer.pop_opacity();
1524    }
1525}
1526
1527/// OnClickModifier registers a click handler for this view.
1528#[derive(Clone)]
1529pub struct OnClickModifier {
1530    pub action: Arc<dyn Fn() + Send + Sync>,
1531}
1532
1533impl ViewModifier for OnClickModifier {
1534    fn modify<V: View>(self, content: V) -> impl View {
1535        ModifiedView::new(content, self)
1536    }
1537
1538    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1539        let action = self.action.clone();
1540        renderer.register_handler(
1541            "pointerclick",
1542            std::sync::Arc::new(move |event| {
1543                if let Event::PointerClick { .. } = event {
1544                    (action)();
1545                }
1546            }),
1547        );
1548    }
1549}
1550
1551/// OnPointerEnterModifier registers a pointer enter handler.
1552#[derive(Clone)]
1553pub struct OnPointerEnterModifier {
1554    pub action: Arc<dyn Fn() + Send + Sync>,
1555}
1556
1557impl ViewModifier for OnPointerEnterModifier {
1558    fn modify<V: View>(self, content: V) -> impl View {
1559        ModifiedView::new(content, self)
1560    }
1561
1562    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1563        let action = self.action.clone();
1564        renderer.register_handler(
1565            "pointerenter",
1566            std::sync::Arc::new(move |event| {
1567                if let Event::PointerEnter = event {
1568                    (action)();
1569                }
1570            }),
1571        );
1572    }
1573}
1574
1575/// OnPointerLeaveModifier registers a pointer leave handler.
1576#[derive(Clone)]
1577pub struct OnPointerLeaveModifier {
1578    pub action: Arc<dyn Fn() + Send + Sync>,
1579}
1580
1581impl ViewModifier for OnPointerLeaveModifier {
1582    fn modify<V: View>(self, content: V) -> impl View {
1583        ModifiedView::new(content, self)
1584    }
1585
1586    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1587        let action = self.action.clone();
1588        renderer.register_handler(
1589            "pointerleave",
1590            std::sync::Arc::new(move |event| {
1591                if let Event::PointerLeave = event {
1592                    (action)();
1593                }
1594            }),
1595        );
1596    }
1597}
1598
1599/// OnPointerMoveModifier registers a pointer move handler.
1600#[derive(Clone)]
1601pub struct OnPointerMoveModifier {
1602    pub action: Arc<dyn Fn(f32, f32) + Send + Sync>,
1603}
1604
1605impl ViewModifier for OnPointerMoveModifier {
1606    fn modify<V: View>(self, content: V) -> impl View {
1607        ModifiedView::new(content, self)
1608    }
1609
1610    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1611        let action = self.action.clone();
1612        renderer.register_handler(
1613            "pointermove",
1614            std::sync::Arc::new(move |event| {
1615                if let Event::PointerMove { x, y } = event {
1616                    (action)(x, y);
1617                }
1618            }),
1619        );
1620    }
1621}
1622
1623/// OnPointerDownModifier registers a pointer down handler.
1624#[derive(Clone)]
1625pub struct OnPointerDownModifier {
1626    pub action: Arc<dyn Fn() + Send + Sync>,
1627}
1628
1629impl ViewModifier for OnPointerDownModifier {
1630    fn modify<V: View>(self, content: V) -> impl View {
1631        ModifiedView::new(content, self)
1632    }
1633
1634    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1635        let action = self.action.clone();
1636        renderer.register_handler(
1637            "pointerdown",
1638            std::sync::Arc::new(move |event| {
1639                if let Event::PointerDown { .. } = event {
1640                    (action)();
1641                }
1642            }),
1643        );
1644    }
1645}
1646
1647/// OnPointerUpModifier registers a pointer up handler.
1648#[derive(Clone)]
1649pub struct OnPointerUpModifier {
1650    pub action: Arc<dyn Fn() + Send + Sync>,
1651}
1652
1653impl ViewModifier for OnPointerUpModifier {
1654    fn modify<V: View>(self, content: V) -> impl View {
1655        ModifiedView::new(content, self)
1656    }
1657
1658    fn render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1659        let action = self.action.clone();
1660        renderer.register_handler(
1661            "pointerup",
1662            std::sync::Arc::new(move |event| {
1663                if let Event::PointerUp { .. } = event {
1664                    (action)();
1665                }
1666            }),
1667        );
1668    }
1669}
1670
1671/// ForegroundColorModifier overrides the foreground (text / icon) color inherited
1672/// by all descendants until another ForegroundColorModifier is encountered.
1673#[derive(Debug, Clone, Copy, PartialEq)]
1674pub struct ForegroundColorModifier {
1675    pub color: [f32; 4],
1676}
1677
1678impl ViewModifier for ForegroundColorModifier {
1679    fn modify<V: View>(self, content: V) -> impl View {
1680        ModifiedView::new(content, self)
1681    }
1682}
1683
1684/// ClipModifier restricts all child drawing to the view's layout rectangle.
1685/// The renderer must support `push_clip_rect`/`pop_clip_rect`.
1686#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1687pub struct ClipModifier;
1688
1689impl ViewModifier for ClipModifier {
1690    fn modify<V: View>(self, content: V) -> impl View {
1691        ModifiedView::new(content, self)
1692    }
1693
1694    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1695        renderer.push_clip_rect(rect);
1696    }
1697
1698    fn post_render(&self, renderer: &mut dyn Renderer, _rect: Rect) {
1699        renderer.pop_clip_rect();
1700    }
1701}
1702
1703/// BorderModifier draws a solid-color border around the view bounds.
1704#[derive(Debug, Clone, Copy, PartialEq)]
1705pub struct BorderModifier {
1706    pub color: [f32; 4],
1707    pub width: f32,
1708}
1709
1710impl ViewModifier for BorderModifier {
1711    fn modify<V: View>(self, content: V) -> impl View {
1712        ModifiedView::new(content, self)
1713    }
1714
1715    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1716        renderer.stroke_rect(rect, self.color, self.width);
1717    }
1718}
1719
1720// Primitive (leaf) views implement Never as body
1721#[doc(hidden)]
1722pub enum Never {}
1723
1724impl View for Never {
1725    type Body = Never;
1726    fn body(self) -> Never {
1727        unreachable!()
1728    }
1729}
1730
1731/// EmptyView - A view that renders nothing and takes up no space.
1732#[derive(Debug, Clone, Copy, Default)]
1733pub struct EmptyView;
1734
1735impl View for EmptyView {
1736    type Body = Never;
1737    fn body(self) -> Self::Body {
1738        unreachable!()
1739    }
1740    fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1741    fn intrinsic_size(&self, _renderer: &mut dyn Renderer, _proposal: SizeProposal) -> Size {
1742        Size {
1743            width: 0.0,
1744            height: 0.0,
1745        }
1746    }
1747}
1748
1749/// A view that has been transformed by a modifier.
1750/// Section 4.3: "Each modifier implements ViewModifier and produces a ModifiedView<Inner, Self>."
1751#[derive(Clone)]
1752pub struct ModifiedView<V, M> {
1753    view: V,
1754    modifier: M,
1755}
1756
1757impl<V: View, M: ViewModifier> ModifiedView<V, M> {
1758    #[doc(hidden)]
1759    pub fn new(view: V, modifier: M) -> Self {
1760        Self { view, modifier }
1761    }
1762}
1763
1764impl<V: View, M: ViewModifier> View for ModifiedView<V, M> {
1765    type Body = ModifiedView<V::Body, M>;
1766
1767    fn body(self) -> Self::Body {
1768        ModifiedView {
1769            view: self.view.body(),
1770            modifier: self.modifier.clone(),
1771        }
1772    }
1773
1774    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
1775        self.modifier.render_view(&self.view, renderer, rect);
1776    }
1777
1778    fn intrinsic_size(&self, renderer: &mut dyn Renderer, proposal: SizeProposal) -> Size {
1779        self.modifier.measure_view(&self.view, renderer, proposal)
1780    }
1781
1782    fn flex_weight(&self) -> f32 {
1783        self.modifier.child_flex_weight(&self.view)
1784    }
1785
1786    fn layout(&self) -> Option<&dyn layout::LayoutView> {
1787        self.modifier.layout().or_else(|| self.view.layout())
1788    }
1789}
1790
1791pub trait ViewModifier: Send + Clone {
1792    fn modify<V: View>(self, content: V) -> impl View;
1793
1794    /// Core rendering hook called before child views.
1795    fn render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1796
1797    /// Cleanup hook called after child views.
1798    fn post_render(&self, _renderer: &mut dyn Renderer, _rect: Rect) {}
1799
1800    /// Allows a modifier to completely override or wrap the rendering of its child.
1801    /// Default implementation performs a standard push -> transform -> render child -> pop sequence.
1802    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
1803        self.render(renderer, rect);
1804        let child_rect = self.transform_rect(rect);
1805        view.render(renderer, child_rect);
1806        self.post_render(renderer, rect);
1807    }
1808
1809    fn transform_rect(&self, rect: Rect) -> Rect {
1810        rect
1811    }
1812
1813    /// Allows a modifier to transform the layout proposal before it reaches the child.
1814    fn transform_proposal(&self, proposal: SizeProposal) -> SizeProposal {
1815        proposal
1816    }
1817
1818    /// Allows a modifier to transform the resulting size from the child.
1819    fn transform_size(&self, size: Size) -> Size {
1820        size
1821    }
1822
1823    /// Measure hook that coordinates size propagation.
1824    fn measure_view<V: View>(
1825        &self,
1826        view: &V,
1827        renderer: &mut dyn Renderer,
1828        proposal: SizeProposal,
1829    ) -> Size {
1830        let child_proposal = self.transform_proposal(proposal);
1831        let child_size = view.intrinsic_size(renderer, child_proposal);
1832        self.transform_size(child_size)
1833    }
1834
1835    /// Allows a modifier to override or pass through the child's flex weight.
1836    fn child_flex_weight<V: View>(&self, view: &V) -> f32 {
1837        view.flex_weight()
1838    }
1839
1840    fn layout(&self) -> Option<&dyn layout::LayoutView> {
1841        None
1842    }
1843}
1844
1845/// TelemetryData tracks real-time performance metrics for the GPU renderer.
1846#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
1847pub struct TelemetryData {
1848    pub frame_time_ms: f32,
1849    /// 99th percentile frame time over the last window, used to detect tail latency.
1850    pub p99_frame_time_ms: f32,
1851    /// Statistical jitter (variance in frame timing).
1852    pub frame_jitter_ms: f32,
1853    /// Indicates if a hardware stall (DRAM refresh, thermal spike) was detected.
1854    pub hardware_stall_detected: bool,
1855
1856    // Pass timing
1857    pub input_time_ms: f32,
1858    pub state_flush_time_ms: f32,
1859    pub layout_time_ms: f32,
1860    pub draw_time_ms: f32,
1861    pub gpu_submit_time_ms: f32,
1862
1863    pub draw_calls: u32,
1864    pub vertices: u32,
1865
1866    /// Global Berserker Pipeline Intensity (0.0 - 1.0+)
1867    pub berserker_rage: f32,
1868
1869    // Memory breakdown
1870    pub vram_usage_mb: f32,
1871    pub vram_textures_mb: f32,
1872    pub vram_buffers_mb: f32,
1873    pub vram_pipelines_mb: f32,
1874    /// Indicates if the Mega-Atlas or VRAM pools are at capacity.
1875    pub vram_exhausted: bool,
1876}
1877
1878/// Configuration for render-loop frame timing and degradation strategies.
1879#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1880pub struct FrameBudget {
1881    /// Target frame time in milliseconds (default: 16.0 for 60FPS)
1882    pub target_ms: f32,
1883    /// If true, the renderer is allowed to dynamically skip non-critical effects
1884    /// (like heavy blurs or complex shadows) when the budget is exceeded.
1885    pub allow_degradation: bool,
1886}
1887
1888impl Default for FrameBudget {
1889    fn default() -> Self {
1890        Self {
1891            target_ms: 16.0,
1892            allow_degradation: true,
1893        }
1894    }
1895}
1896
1897/// The Renderer trait defines the atomic drawing operations for all CVKG backends.
1898/// This trait is object-safe and used by the View::render system.
1899/// # Implementation Requirements
1900/// 1. Coordinate system is origin-top-left (0,0) with Y increasing downwards.
1901/// 2. Colors are [R, G, B, A] in the [0.0, 1.0] range.
1902/// 3. All operations must be batchable by the underlying backend.
1903///    Trait providing timing information for the render loop.
1904pub trait ElapsedTime {
1905    /// Returns the cumulative time since the renderer started in seconds.
1906    fn elapsed_time(&self) -> f32;
1907
1908    /// Returns the time elapsed since the last frame in seconds.
1909    fn delta_time(&self) -> f32;
1910}
1911
1912/// The Renderer trait defines the atomic drawing operations for all CVKG backends.
1913/// This trait is object-safe and used by the View::render system.
1914/// # Implementation Requirements
1915/// 1. Coordinate system is origin-top-left (0,0) with Y increasing downwards.
1916/// 2. Colors are [R, G, B, A] in the [0.0, 1.0] range.
1917/// 3. All operations must be batchable by the underlying backend.
1918pub trait Renderer: ElapsedTime + Send {
1919    /// Requests that the renderer redraws as soon as possible.
1920    /// Used for continuous animations.
1921    fn request_redraw(&mut self) {}
1922
1923    /// Returns true if the current frame is over the time budget.
1924    /// This can be used to skip expensive visual effects.
1925    fn is_over_budget(&self) -> bool {
1926        false
1927    }
1928
1929    // ── Filled shapes ────────────────────────────────────────────────────
1930    fn fill_rect(&mut self, rect: Rect, color: [f32; 4]);
1931    fn fill_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4]);
1932    /// Fill an ellipse/circle that fits inside `rect`.
1933    fn fill_ellipse(&mut self, rect: Rect, color: [f32; 4]);
1934
1935    /// Draw a high-fidelity 3D cube inside the given rectangle using specialized shader logic.
1936    /// `rotation` is [pitch, yaw, roll] in radians.
1937    fn draw_3d_cube(&mut self, _rect: Rect, _color: [f32; 4], _rotation: [f32; 3]) {}
1938
1939    // ── Stroked shapes ───────────────────────────────────────────────────
1940    fn stroke_rect(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1941    fn stroke_rounded_rect(&mut self, rect: Rect, radius: f32, color: [f32; 4], stroke_width: f32);
1942    /// Stroke an ellipse/circle that fits inside `rect`.
1943    fn stroke_ellipse(&mut self, rect: Rect, color: [f32; 4], stroke_width: f32);
1944    /// Draw a straight line from (x1,y1) to (x2,y2).
1945    fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, color: [f32; 4], stroke_width: f32);
1946    /// Fill a polygon defined by a set of vertices.
1947    fn fill_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4]) {}
1948    /// Stroke a polygon defined by a set of vertices.
1949    fn stroke_polygon(&mut self, _vertices: &[[f32; 2]], _color: [f32; 4], _stroke_width: f32) {}
1950
1951    // ── Text ─────────────────────────────────────────────────────────────
1952    fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: [f32; 4]);
1953    /// Measure the width and height of the specified text.
1954    fn measure_text(&mut self, text: &str, size: f32) -> (f32, f32);
1955
1956    // ── Images & textures ────────────────────────────────────────────────
1957    /// Draw a texture (GPU-side) at the specified rect.
1958    fn draw_texture(&mut self, _texture_id: u32, _rect: Rect) {}
1959    /// Draw an image asset by name or path.
1960    fn draw_image(&mut self, _image_name: &str, _rect: Rect) {}
1961    /// Load an image asset from memory.
1962    fn load_image(&mut self, _name: &str, _data: &[u8]) {}
1963    /// Pre-warm the renderer with assets. Implementations can use this
1964    /// to populate texture atlases or warm up shader caches.
1965    fn prewarm_vram(&mut self, _assets: Vec<(String, Vec<u8>)>) {}
1966
1967    /// Get the current pointer (mouse/touch) position.
1968    fn get_pointer_position(&self) -> [f32; 2] {
1969        [0.0, 0.0]
1970    }
1971
1972    // ── Data Visualization ───────────────────────────────────────────────
1973    /// Upload raw float data as a GPU texture for heatmap rendering.
1974    fn upload_data_texture(&mut self, _id: &str, _data: &[f32], _width: u32, _height: u32) {}
1975    /// Draw a heatmap using a previously uploaded data texture.
1976    fn draw_heatmap(&mut self, _texture_id: &str, _rect: Rect, _palette: &str) {}
1977
1978    // ── 3D Objects ───────────────────────────────────────────────────────
1979    /// Draw a 3D mesh.
1980    fn draw_mesh(&mut self, _mesh: &Mesh, _color: [f32; 4], _transform: glam::Mat4) {}
1981
1982    // ── Advanced Visual Effects ──────────────────────────────────────────
1983    /// Draw a linear gradient between two colors at the specified angle.
1984    fn draw_linear_gradient(
1985        &mut self,
1986        _rect: Rect,
1987        _start_color: [f32; 4],
1988        _end_color: [f32; 4],
1989        _angle: f32,
1990    ) {
1991    }
1992    /// Draw a radial gradient between two colors.
1993    fn draw_radial_gradient(
1994        &mut self,
1995        _rect: Rect,
1996        _inner_color: [f32; 4],
1997        _outer_color: [f32; 4],
1998    ) {
1999    }
2000    /// Draw a high-fidelity drop shadow for a rounded rectangle.
2001    fn draw_drop_shadow(
2002        &mut self,
2003        _rect: Rect,
2004        _radius: f32,
2005        _color: [f32; 4],
2006        _blur: f32,
2007        _spread: f32,
2008    ) {
2009    }
2010    /// Draw a dashed border for a rounded rectangle.
2011    fn stroke_dashed_rounded_rect(
2012        &mut self,
2013        _rect: Rect,
2014        _radius: f32,
2015        _color: [f32; 4],
2016        _width: f32,
2017        _dash: f32,
2018        _gap: f32,
2019    ) {
2020    }
2021    /// Draw a 9-slice / patch scaled image.
2022    fn draw_9slice(
2023        &mut self,
2024        _image_name: &str,
2025        _rect: Rect,
2026        _left: f32,
2027        _top: f32,
2028        _right: f32,
2029        _bottom: f32,
2030    ) {
2031    }
2032
2033    // ── Clipping ─────────────────────────────────────────────────────────
2034    /// Push a clip rectangle.  All subsequent drawing is clipped to `rect`.
2035    /// Implementations that do not support clipping may ignore this call.
2036    fn push_clip_rect(&mut self, _rect: Rect) {}
2037    /// Pop the most recently pushed clip rectangle.
2038    fn pop_clip_rect(&mut self) {}
2039    /// Get the current clip rectangle in screen coordinates.
2040    /// Returns a rect covering the entire screen if no clip is active.
2041    fn current_clip_rect(&self) -> Rect {
2042        Rect::new(-10000.0, -10000.0, 20000.0, 20000.0)
2043    }
2044
2045    // ── Global opacity ───────────────────────────────────────────────────
2046    /// Set a global opacity multiplier applied to all subsequent draw calls
2047    /// until `pop_opacity` is called.  `opacity` is in [0.0, 1.0].
2048    fn push_opacity(&mut self, _opacity: f32) {}
2049    /// Restore the previous opacity level.
2050    fn pop_opacity(&mut self) {}
2051
2052    // ── Berserker Pipeline State ─────────────────────────────────────────
2053    fn set_theme(&mut self, _theme: ColorTheme) {}
2054    fn set_rage(&mut self, _rage: f32) {}
2055    fn set_berserker_mode(&mut self, _state: BerserkerMode) {}
2056    fn trigger_shatter_event(&mut self, _origin: [f32; 2], _force: f32) {}
2057    /// Set the desktop scene preset (Aurora, Void, Nebula, Glitch, Yggdrasil).
2058    fn set_scene(&mut self, _scene: &str) {}
2059
2060    // ── Export & Print ───────────────────────────────────────────────────
2061    /// Capture the current frame as a PNG byte buffer.
2062    fn capture_png(&mut self) -> Vec<u8> {
2063        Vec::new()
2064    }
2065    /// Trigger a native print dialog or spooling operation.
2066    fn print(&mut self) {}
2067
2068    fn set_scene_preset(&mut self, _preset: u32) {}
2069
2070    // ── Cyberpunk Effects ────────────────────────────────────────────────
2071    /// Apply a Bifrost (Frosted Glass) effect to the specified rect.
2072    fn bifrost(&mut self, _rect: Rect, _blur: f32, _saturation: f32, _opacity: f32) {}
2073    /// Apply a Gungnir (Neon Glow) effect to the specified rect.
2074    fn gungnir(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32, _intensity: f32) {}
2075    /// Apply a ManiGlow (Lunar Illuminator) effect.
2076    fn mani_glow(&mut self, _rect: Rect, _color: [f32; 4], _radius: f32) {}
2077    /// Push a Mjolnir Slice (geometric clipping).
2078    fn push_mjolnir_slice(&mut self, _angle: f32, _offset: f32) {}
2079    fn pop_mjolnir_slice(&mut self) {}
2080    /// Execute a render function with memoization.
2081    /// If the renderer supports caching and the `id` + `data_hash` match a previous run,
2082    /// it may replay cached commands instead of executing the function.
2083    fn memoize(&mut self, id: u64, data_hash: u64, render_fn: &dyn Fn(&mut dyn Renderer));
2084    /// Apply a Mjolnir Shatter effect (fragmentation) to the specified rect.
2085    fn mjolnir_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
2086    fn mjolnir_fluid_shatter(&mut self, _rect: Rect, _pieces: u32, _force: f32, _color: [f32; 4]) {}
2087    /// Draw a Mjolnir Bolt (lightning strike) between two points.
2088    fn draw_mjolnir_bolt(&mut self, _from: [f32; 2], _to: [f32; 2], _color: [f32; 4]) {}
2089
2090    // ── Accessibility (ShieldWall) ───────────────────────────────────────
2091    fn set_aria_role(&mut self, _role: &str) {}
2092    fn set_aria_label(&mut self, _label: &str) {}
2093
2094    /// Register a shared element for Bifrost Bridge transitions.
2095    fn register_shared_element(&mut self, _id: &str, _rect: Rect) {}
2096
2097    /// Set a unique key for the current VDOM node to ensure stable identity during diffing.
2098    fn set_key(&mut self, _key: &str) {}
2099
2100    // ── Telemetry ────────────────────────────────────────────────────────
2101    /// Get real-time performance telemetry.
2102    fn get_telemetry(&self) -> TelemetryData {
2103        TelemetryData::default()
2104    }
2105
2106    // ── GPU State Management ─────────────────────────────────────────────
2107    /// Push a shadow state to the stack. All following draw calls will have this shadow.
2108    fn push_shadow(&mut self, _radius: f32, _color: [f32; 4], _offset: [f32; 2]) {}
2109    /// Pop the last shadow state from the stack.
2110    fn pop_shadow(&mut self) {}
2111
2112    // ── VDOM & Scene Graph ───────────────────────────────────────────────
2113    /// Push a Virtual DOM node onto the stack for hierarchy tracking.
2114    fn push_vnode(&mut self, _rect: Rect, _name: &'static str) {}
2115    /// Pop the current Virtual DOM node from the stack.
2116    fn pop_vnode(&mut self) {}
2117    /// Register an event handler for the current VDOM node.
2118    fn register_handler(
2119        &mut self,
2120        _event_type: &str,
2121        _handler: std::sync::Arc<dyn Fn(Event) + Send + Sync>,
2122    ) {
2123    }
2124
2125    // ── Z-Index & Depth ──────────────────────────────────────────────────
2126    /// Set the current Z-index for depth sorting.
2127    /// Higher values appear closer to the viewer.
2128    fn set_z_index(&mut self, _z: f32) {}
2129    /// Get the current Z-index.
2130    fn get_z_index(&self) -> f32 {
2131        0.0
2132    }
2133
2134    // ── Vector Graphics ──────────────────────────────────────────────────
2135    /// Load an SVG model from raw bytes.
2136    fn load_svg(&mut self, _name: &str, _svg_data: &[u8]) {}
2137    /// Draw a pre-loaded SVG model.
2138    fn draw_svg(&mut self, _name: &str, _rect: Rect) {}
2139
2140    // ── GPU Transformations ──────────────────────────────────────────────
2141    /// Push a 2D transform (translation, scale, rotation) onto the stack.
2142    /// This transform should be applied to all subsequent draw calls until popped.
2143    /// Transform-only animations use this to avoid re-triggering the layout engine.
2144    fn push_transform(&mut self, _translation: [f32; 2], _scale: [f32; 2], _rotation: f32) {}
2145    /// Pop the last 2D transform from the stack.
2146    fn pop_transform(&mut self) {}
2147    /// Return the resolved layout bounds for a specific node ID if it exists.
2148    fn query_layout(&self, _node_id: scene_graph::NodeId) -> Option<Rect> {
2149        None
2150    }
2151    /// Enable or disable the layout debug overlay (bounds, padding, margin).
2152    fn set_debug_layout(&mut self, _enabled: bool) {}
2153    /// Check if the layout debug overlay is currently enabled.
2154    fn get_debug_layout(&self) -> bool {
2155        false
2156    }
2157
2158    // ── Material Routing ─────────────────────────────────────────────────
2159    /// Set the active material for subsequent draw calls.
2160    /// Controls which pass a draw call is routed to in the multi-pass pipeline.
2161    fn set_material(&mut self, _material: crate::material::DrawMaterial) {}
2162    /// Return the currently active material (defaults to Opaque).
2163    fn current_material(&self) -> crate::material::DrawMaterial {
2164        crate::material::DrawMaterial::Opaque
2165    }
2166}
2167
2168/// Utility for accessibility compliance (WCAG 2.1).
2169pub mod accessibility {
2170    /// Calculate the relative luminance of an sRGB color.
2171    pub fn relative_luminance(color: [f32; 4]) -> f32 {
2172        let f = |c: f32| {
2173            if c <= 0.03928 {
2174                c / 12.92
2175            } else {
2176                ((c + 0.055) / 1.055).powf(2.4)
2177            }
2178        };
2179        0.2126 * f(color[0]) + 0.7152 * f(color[1]) + 0.0722 * f(color[2])
2180    }
2181
2182    /// Calculate the contrast ratio between two colors.
2183    pub fn contrast_ratio(c1: [f32; 4], c2: [f32; 4]) -> f32 {
2184        let l1 = relative_luminance(c1);
2185        let l2 = relative_luminance(c2);
2186        let (light, dark) = if l1 > l2 { (l1, l2) } else { (l2, l1) };
2187        (light + 0.05) / (dark + 0.05)
2188    }
2189}
2190/// Defines the hardware acceleration tier and feature set available to the renderer.
2191#[derive(
2192    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
2193)]
2194pub enum RenderTier {
2195    /// High-performance GPU path (WebGPU / Vulkan / Metal / DX12) with full shader support.
2196    Tier1GPU = 0,
2197    /// Mid-tier GPU path (WebGL2 / OpenGL 3.3) with standard shader support.
2198    Tier2GPU = 1,
2199    /// Fallback software or basic hardware path (Canvas 2D / GDI+) with limited effects.
2200    Tier3Fallback = 2,
2201}
2202// =============================================================================
2203// BERSERKER UNIFORMS
2204// =============================================================================
2205use bytemuck::{Pod, Zeroable};
2206/// Fully themeable color palette for the Berserker pipeline.
2207#[repr(C)]
2208#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
2209pub struct ColorTheme {
2210    pub primary_neon: [f32; 4], // (R, G, B, intensity)
2211    pub shatter_neon: [f32; 4],
2212    pub glass_base: [f32; 4],
2213    pub glass_edge: [f32; 4],
2214    pub rune_glow: [f32; 4],
2215    pub ember_core: [f32; 4],
2216    pub background_deep: [f32; 4],
2217    pub mani_glow: [f32; 4], // (R, G, B, radius)
2218    pub glass_blur_strength: f32,
2219    pub shatter_edge_width: f32,
2220    pub neon_bloom_radius: f32,
2221    pub rune_opacity: f32,
2222}
2223impl ColorTheme {
2224    /// Asgard Mode: The high-fidelity "Cyberpunk Viking" aesthetic.
2225    pub fn asgard() -> Self {
2226        Self {
2227            primary_neon: [0.0, 1.0, 0.95, 1.2],
2228            shatter_neon: [1.0, 0.0, 0.75, 1.5],
2229            glass_base: [0.04, 0.04, 0.06, 0.82],
2230            glass_edge: [0.0, 0.45, 0.55, 0.6],
2231            rune_glow: [0.75, 0.98, 1.0, 0.9],
2232            ember_core: [0.95, 0.12, 0.12, 1.0],
2233            background_deep: [0.01, 0.01, 0.03, 1.0],
2234            mani_glow: [0.7, 0.9, 1.0, 0.05],
2235            glass_blur_strength: 0.6,
2236            shatter_edge_width: 1.8,
2237            neon_bloom_radius: 0.022,
2238            rune_opacity: 0.55,
2239        }
2240    }
2241
2242    /// Midgard Mode: A clean, functional tactical HUD for standard operations.
2243    pub fn midgard() -> Self {
2244        Self {
2245            primary_neon: [0.2, 0.4, 0.6, 1.0], // Muted blue
2246            shatter_neon: [0.5, 0.5, 0.5, 1.0], // Neutral gray
2247            glass_base: [0.1, 0.12, 0.15, 1.0], // Solid slate
2248            glass_edge: [0.3, 0.35, 0.4, 1.0],  // Subtle border
2249            rune_glow: [0.8, 0.8, 0.8, 0.0],    // Runes disabled
2250            ember_core: [0.5, 0.5, 0.5, 1.0],
2251            background_deep: [0.05, 0.05, 0.07, 1.0],
2252            mani_glow: [0.0, 0.0, 0.0, 0.0], // No cursor glow
2253            glass_blur_strength: 0.0,        // No blur
2254            shatter_edge_width: 1.0,
2255            neon_bloom_radius: 0.0,
2256            rune_opacity: 0.0,
2257        }
2258    }
2259
2260    pub fn cyberpunk_viking() -> Self {
2261        Self::asgard()
2262    }
2263    pub fn vibrant_glass() -> Self {
2264        Self {
2265            primary_neon: [0.0, 1.0, 0.95, 1.2],
2266            shatter_neon: [1.0, 0.0, 0.75, 1.5],
2267            glass_base: [0.55, 0.6, 0.7, 0.08], // Luminous cool tint
2268            glass_edge: [0.7, 0.85, 1.0, 0.45], // Subtle blue-white rim
2269            rune_glow: [0.75, 0.98, 1.0, 0.9],
2270            ember_core: [1.0, 0.4, 0.1, 1.0],
2271            background_deep: [0.05, 0.05, 0.1, 1.0],
2272            mani_glow: [0.7, 0.9, 1.0, 0.05],
2273            glass_blur_strength: 0.9,
2274            shatter_edge_width: 1.8,
2275            neon_bloom_radius: 0.022,
2276            rune_opacity: 0.55,
2277        }
2278    }
2279}
2280impl Default for ColorTheme {
2281    fn default() -> Self {
2282        Self::vibrant_glass()
2283    }
2284}
2285/// Per-frame scene state for the Berserker pipeline.
2286#[repr(C)]
2287#[derive(Copy, Clone, Debug, Pod, Zeroable, serde::Serialize, serde::Deserialize)]
2288pub struct SceneUniforms {
2289    pub view: glam::Mat4,
2290    pub proj: glam::Mat4,
2291    pub time: f32,
2292    pub delta_time: f32,
2293    pub resolution: [f32; 2],
2294    pub mouse: [f32; 2],
2295    pub mouse_velocity: [f32; 2],
2296    pub shatter_origin: [f32; 2],
2297    pub shatter_time: f32,
2298    pub shatter_force: f32,
2299    pub berzerker_rage: f32,
2300    pub berzerker_mode: u32,
2301    pub scroll_offset: f32,
2302    pub scale_factor: f32,
2303    pub scene_type: u32,
2304    pub _pad: [f32; 3], // Align to 16 bytes if needed, but current struct is 4x16 + 4x16 + 4x16 + ...
2305}
2306
2307pub const SCENE_AURORA: u32 = 0;
2308pub const SCENE_VOID: u32 = 1;
2309pub const SCENE_NEBULA: u32 = 2;
2310pub const SCENE_GLITCH: u32 = 3;
2311pub const SCENE_YGGDRASIL: u32 = 4;
2312
2313impl SceneUniforms {
2314    pub fn new(width: f32, height: f32) -> Self {
2315        Self {
2316            view: glam::Mat4::IDENTITY,
2317            proj: glam::Mat4::orthographic_lh(0.0, width, height, 0.0, -100.0, 100.0),
2318            time: 0.0,
2319            delta_time: 0.016,
2320            resolution: [width, height],
2321            mouse: [0.5, 0.5],
2322            mouse_velocity: [0.0, 0.0],
2323            shatter_origin: [0.5, 0.5],
2324            shatter_time: -100.0,
2325            shatter_force: 0.0,
2326            berzerker_rage: 0.0,
2327            berzerker_mode: 0,
2328            scroll_offset: 0.0,
2329            scale_factor: 1.0,
2330            scene_type: SCENE_AURORA,
2331            _pad: [0.0; 3],
2332        }
2333    }
2334}
2335/// A 3D mesh containing vertex and index data.
2336#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
2337pub struct Mesh {
2338    pub vertices: Vec<[f32; 3]>,
2339    pub normals: Vec<[f32; 3]>,
2340    pub indices: Vec<u32>,
2341}
2342impl Mesh {
2343    pub fn from_obj(data: &[u8]) -> anyhow::Result<Vec<Self>> {
2344        let mut cursor = std::io::Cursor::new(data);
2345        let (models, _) = tobj::load_obj_buf(&mut cursor, &tobj::LoadOptions::default(), |_| {
2346            Ok((Vec::new(), Default::default()))
2347        })?;
2348        let mut meshes = Vec::new();
2349        for m in models {
2350            let mesh = m.mesh;
2351            let vertices: Vec<[f32; 3]> = mesh
2352                .positions
2353                .chunks(3)
2354                .map(|c| [c[0], c[1], c[2]])
2355                .collect();
2356            let normals = if mesh.normals.is_empty() {
2357                vec![[0.0, 0.0, 1.0]; vertices.len()]
2358            } else {
2359                mesh.normals.chunks(3).map(|c| [c[0], c[1], c[2]]).collect()
2360            };
2361            meshes.push(Mesh {
2362                vertices,
2363                normals,
2364                indices: mesh.indices,
2365            });
2366        }
2367        Ok(meshes)
2368    }
2369    pub fn from_stl(data: &[u8]) -> anyhow::Result<Self> {
2370        let mut cursor = std::io::Cursor::new(data);
2371        let stl = stl_io::read_stl(&mut cursor)?;
2372        let vertices: Vec<[f32; 3]> = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
2373        let mut indices = Vec::new();
2374        for face in stl.faces {
2375            indices.push(face.vertices[0] as u32);
2376            indices.push(face.vertices[1] as u32);
2377            indices.push(face.vertices[2] as u32);
2378        }
2379        let normals = vec![[0.0, 0.0, 1.0]; vertices.len()];
2380        Ok(Mesh {
2381            vertices,
2382            normals,
2383            indices,
2384        })
2385    }
2386}
2387/// FrameRenderer extends Renderer with frame lifecycle management.
2388/// It is typically implemented by the host windowing/rendering environment.
2389pub trait FrameRenderer<E = ()>: Renderer {
2390    fn begin_frame(&mut self) -> E;
2391    fn render_frame(&mut self) {
2392        // Default implementation does nothing - override for custom frame rendering
2393    }
2394    fn end_frame(&mut self, encoder: E);
2395}
2396use std::sync::Arc;
2397type SubscriberList<T> = Arc<std::sync::Mutex<Vec<Box<dyn Fn(&T) + Send + Sync>>>>;
2398/// State wrapper that owns a value and notifies subscribers when changed
2399#[derive(Clone)]
2400pub struct State<T: Clone + Send + Sync + 'static> {
2401    swap: Arc<arc_swap::ArcSwap<T>>,
2402    metadata_swap: Arc<arc_swap::ArcSwap<Option<agents::MutationMetadata>>>,
2403    #[cfg(not(target_arch = "wasm32"))]
2404    tvar: Arc<stm::TVar<T>>,
2405    #[cfg(not(target_arch = "wasm32"))]
2406    metadata_tvar: Arc<stm::TVar<Option<agents::MutationMetadata>>>,
2407    subscribers: SubscriberList<T>,
2408    version: Arc<std::sync::atomic::AtomicU64>,
2409    resolution: agents::ConflictResolution,
2410}
2411impl<T: Clone + Send + Sync + 'static> State<T> {
2412    /// Create a new State with initial value
2413    pub fn new(value: T) -> Self {
2414        #[cfg(not(target_arch = "wasm32"))]
2415        let tvar = Arc::new(stm::TVar::new(value.clone()));
2416        #[cfg(not(target_arch = "wasm32"))]
2417        let metadata_tvar = Arc::new(stm::TVar::new(None));
2418        Self {
2419            swap: Arc::new(arc_swap::ArcSwap::from_pointee(value)),
2420            metadata_swap: Arc::new(arc_swap::ArcSwap::new(Arc::new(None))),
2421            #[cfg(not(target_arch = "wasm32"))]
2422            tvar,
2423            #[cfg(not(target_arch = "wasm32"))]
2424            metadata_tvar,
2425            subscribers: Arc::new(std::sync::Mutex::new(Vec::new())),
2426            version: Arc::new(std::sync::atomic::AtomicU64::new(0)),
2427            resolution: agents::ConflictResolution::default(),
2428        }
2429    }
2430    /// Set the conflict resolution strategy for this state.
2431    pub fn with_resolution(mut self, resolution: agents::ConflictResolution) -> Self {
2432        self.resolution = resolution;
2433        self
2434    }
2435    /// Get the current value
2436    pub fn get(&self) -> T {
2437        (**self.swap.load()).clone()
2438    }
2439    /// Set a new value, notifying all subscribers. Applies conflict resolution if agents are present.
2440    pub fn set(&self, value: T) {
2441        #[cfg(not(target_arch = "wasm32"))]
2442        let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
2443            let new_meta = agents::get_current_mutation_metadata();
2444            let existing_meta = self.metadata_tvar.read(tx)?;
2445            let mut skip = false;
2446            if self.resolution == agents::ConflictResolution::PriorityWins
2447                && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
2448                && new_m.priority < old_m.priority
2449            {
2450                skip = true;
2451            }
2452            if !skip {
2453                self.tvar.write(tx, value.clone())?;
2454                self.metadata_tvar.write(tx, new_meta)?;
2455                Ok((false, value.clone(), new_meta))
2456            } else {
2457                Ok((true, self.tvar.read(tx)?, existing_meta))
2458            }
2459        });
2460        #[cfg(target_arch = "wasm32")]
2461        let (was_skipped, final_val, final_meta) =
2462            (false, value, agents::get_current_mutation_metadata());
2463        if was_skipped {
2464            if let (Some(new_m), Some(old_m)) =
2465                (agents::get_current_mutation_metadata(), final_meta)
2466            {
2467                agents::notify_conflict(agents::ConflictEvent {
2468                    agent_id: new_m.agent_id,
2469                    priority: new_m.priority,
2470                    existing_agent_id: old_m.agent_id,
2471                    existing_priority: old_m.priority,
2472                    timestamp_ms: new_m.timestamp_ms,
2473                });
2474            }
2475            return;
2476        }
2477        self.swap.store(Arc::new(final_val.clone()));
2478        self.metadata_swap.store(Arc::new(final_meta));
2479        self.version
2480            .fetch_add(1, std::sync::atomic::Ordering::Release);
2481        let subs = Arc::clone(&self.subscribers);
2482        if crate::is_batching() {
2483            crate::enqueue_batch_task(Box::new(move || {
2484                let s = subs.lock().unwrap();
2485                for cb in s.iter() {
2486                    cb(&final_val);
2487                }
2488            }));
2489        } else {
2490            let s = subs.lock().unwrap();
2491            for cb in s.iter() {
2492                cb(&final_val);
2493            }
2494        }
2495    }
2496    pub fn mutate<F: Fn(&T) -> T>(&self, f: F) {
2497        #[cfg(not(target_arch = "wasm32"))]
2498        {
2499            let (was_skipped, final_val, final_meta) = stm::atomically(|tx| {
2500                let new_meta = agents::get_current_mutation_metadata();
2501                let existing_meta = self.metadata_tvar.read(tx)?;
2502                let mut skip = false;
2503                if self.resolution == agents::ConflictResolution::PriorityWins
2504                    && let (Some(new_m), Some(old_m)) = (new_meta, existing_meta)
2505                    && new_m.priority < old_m.priority
2506                {
2507                    skip = true;
2508                }
2509                if !skip {
2510                    let current = self.tvar.read(tx)?;
2511                    let next = f(&current);
2512                    self.tvar.write(tx, next.clone())?;
2513                    self.metadata_tvar.write(tx, new_meta)?;
2514                    Ok((false, next, new_meta))
2515                } else {
2516                    Ok((true, self.tvar.read(tx)?, existing_meta))
2517                }
2518            });
2519            if was_skipped {
2520                if let (Some(new_m), Some(old_m)) =
2521                    (agents::get_current_mutation_metadata(), final_meta)
2522                {
2523                    agents::notify_conflict(agents::ConflictEvent {
2524                        agent_id: new_m.agent_id,
2525                        priority: new_m.priority,
2526                        existing_agent_id: old_m.agent_id,
2527                        existing_priority: old_m.priority,
2528                        timestamp_ms: new_m.timestamp_ms,
2529                    });
2530                }
2531                return;
2532            }
2533            self.swap.store(Arc::new(final_val.clone()));
2534            self.metadata_swap.store(Arc::new(final_meta));
2535            self.version
2536                .fetch_add(1, std::sync::atomic::Ordering::Release);
2537            let subs = Arc::clone(&self.subscribers);
2538            if crate::is_batching() {
2539                crate::enqueue_batch_task(Box::new(move || {
2540                    let s = subs.lock().unwrap();
2541                    for cb in s.iter() {
2542                        cb(&final_val);
2543                    }
2544                }));
2545            } else {
2546                let s = subs.lock().unwrap();
2547                for cb in s.iter() {
2548                    cb(&final_val);
2549                }
2550            }
2551        }
2552        #[cfg(target_arch = "wasm32")]
2553        {
2554            self.set(f(&self.get()));
2555        }
2556    }
2557    /// Get current version
2558    pub fn version(&self) -> u64 {
2559        self.version.load(std::sync::atomic::Ordering::Acquire)
2560    }
2561    /// Subscribe to state changes
2562    pub fn subscribe<F: Fn(&T) + Send + Sync + 'static>(&self, callback: F) {
2563        self.subscribers.lock().unwrap().push(Box::new(callback));
2564    }
2565}
2566use crate::runtime::NodeStateSnapshot;
2567use std::sync::OnceLock;
2568use std::sync::atomic::{AtomicBool, Ordering};
2569/// Global application state registry.
2570pub static SYSTEM_STATE: OnceLock<Arc<arc_swap::ArcSwap<KnowledgeState>>> = OnceLock::new();
2571#[cfg(not(target_arch = "wasm32"))]
2572static KNOWLEDGE_TVAR: OnceLock<stm::TVar<KnowledgeState>> = OnceLock::new();
2573static IS_BATCHING: AtomicBool = AtomicBool::new(false);
2574pub static IS_RENDERING: AtomicBool = AtomicBool::new(false);
2575pub static LAYOUT_DIRTY: AtomicBool = AtomicBool::new(false);
2576type BatchQueue = OnceLock<std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync>>>>;
2577static BATCH_QUEUE: BatchQueue = OnceLock::new();
2578/// Global write lock to serialize updates to SYSTEM_STATE and KNOWLEDGE_TVAR,
2579/// preventing parallel race conditions between STM transactions and the lock-free reader state.
2580static STATE_WRITE_MUTEX: std::sync::Mutex<()> = std::sync::Mutex::new(());
2581/// Returns true if state updates are currently being batched.
2582pub fn is_batching() -> bool {
2583    IS_BATCHING.load(Ordering::Acquire)
2584}
2585/// Returns true if the system is currently in the render phase.
2586pub fn is_rendering() -> bool {
2587    IS_RENDERING.load(Ordering::Acquire)
2588}
2589/// Signals the start of the render phase. Mutations during this phase trigger warnings.
2590pub fn begin_render_phase() {
2591    IS_RENDERING.store(true, Ordering::Release);
2592}
2593/// Signals the end of the render phase.
2594pub fn end_render_phase() {
2595    IS_RENDERING.store(false, Ordering::Release);
2596}
2597/// Enqueues a notification task to be run when the current batch flushes.
2598pub fn enqueue_batch_task(task: Box<dyn FnOnce() + Send + Sync>) {
2599    let mut queue = BATCH_QUEUE
2600        .get_or_init(|| std::sync::Mutex::new(Vec::new()))
2601        .lock()
2602        .unwrap();
2603    queue.push(task);
2604}
2605/// Executes multiple state updates in a single batch, deferring all subscriber
2606/// notifications until the closure completes. This prevents layout thrashing
2607/// and redundant render cycles when modifying multiple independent states.
2608pub fn batch<F: FnOnce()>(f: F) {
2609    if IS_BATCHING.swap(true, Ordering::AcqRel) {
2610        // Already inside a batch, just execute
2611        f();
2612        return;
2613    }
2614    f();
2615    IS_BATCHING.store(false, Ordering::Release);
2616    let mut queue = BATCH_QUEUE
2617        .get_or_init(|| std::sync::Mutex::new(Vec::new()))
2618        .lock()
2619        .unwrap();
2620    let tasks: Vec<_> = queue.drain(..).collect();
2621    drop(queue);
2622    for task in tasks {
2623        task();
2624    }
2625}
2626/// Get a reference to the global system state.
2627pub fn get_system_state() -> Arc<arc_swap::ArcSwap<KnowledgeState>> {
2628    SYSTEM_STATE
2629        .get_or_init(|| Arc::new(arc_swap::ArcSwap::from_pointee(KnowledgeState::default())))
2630        .clone()
2631}
2632pub fn load_system_state() -> arc_swap::Guard<Arc<KnowledgeState>> {
2633    get_system_state().load()
2634}
2635pub fn update_system_state<F>(f: F)
2636where
2637    F: Fn(&KnowledgeState) -> KnowledgeState,
2638{
2639    let _lock = STATE_WRITE_MUTEX.lock().unwrap();
2640    if is_rendering() {
2641        log::warn!(
2642            "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2643        );
2644    }
2645    LAYOUT_DIRTY.store(true, Ordering::SeqCst);
2646    let swap = get_system_state();
2647    let current = swap.load();
2648    let new_state = Arc::new(f(&current));
2649    swap.store(Arc::clone(&new_state));
2650    #[cfg(not(target_arch = "wasm32"))]
2651    {
2652        let tvar = KNOWLEDGE_TVAR.get_or_init(|| stm::TVar::new((*new_state).clone()));
2653        stm::atomically(|tx| tvar.write(tx, (*new_state).clone()));
2654    }
2655}
2656pub fn transact_system_state<F>(f: F)
2657where
2658    F: Fn(&KnowledgeState) -> KnowledgeState,
2659{
2660    let _lock = STATE_WRITE_MUTEX.lock().unwrap();
2661    #[cfg(not(target_arch = "wasm32"))]
2662    {
2663        if is_rendering() {
2664            log::warn!(
2665                "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2666            );
2667        }
2668        let tvar = KNOWLEDGE_TVAR
2669            .get_or_init(|| stm::TVar::new((**get_system_state().load()).clone()))
2670            .clone();
2671        let new_state = stm::atomically(move |tx| {
2672            let current = tvar.read(tx)?;
2673            let next = f(&current);
2674            tvar.write(tx, next.clone())?;
2675            Ok(next)
2676        });
2677        get_system_state().store(Arc::new(new_state));
2678    }
2679    #[cfg(target_arch = "wasm32")]
2680    {
2681        if is_rendering() {
2682            log::warn!(
2683                "LAYOUT THRASH DETECTED: System state mutated during render phase. This may trigger redundant layout passes and impact performance."
2684            );
2685        }
2686        update_system_state(f);
2687    }
2688}
2689impl KnowledgeState {
2690    /// Create a new empty KnowledgeState.
2691    pub fn new() -> Self {
2692        Self::default()
2693    }
2694    /// Set a component's internal state.
2695    pub fn set_component_state<T: 'static + Send + Sync>(&mut self, id: u64, state: T) {
2696        self.component_states
2697            .insert(id, Arc::new(std::sync::RwLock::new(state)));
2698    }
2699    /// Get a reference to a component's internal state.
2700    pub fn get_component_state<T: 'static + Send + Sync>(
2701        &self,
2702        id: u64,
2703    ) -> Option<Arc<std::sync::RwLock<T>>> {
2704        let lock = self.component_states.get(&id)?;
2705        // Attempt to clone the Arc and downcast the inner RwLock<dyn Any> to RwLock<T>
2706        // We use a two-step approach: check if the inner type matches via Any, then transmute the Arc
2707        // SAFETY: We verify the type via Any::is::<T> before transmuting
2708        let any_ref = lock.read().ok()?;
2709        if any_ref.is::<T>() {
2710            // Type matches — safe to transmute the Arc
2711            drop(any_ref);
2712            let cloned: Arc<std::sync::RwLock<dyn std::any::Any + Send + Sync>> = Arc::clone(lock);
2713            // Transmute Arc<RwLock<dyn Any>> to Arc<RwLock<T>>
2714            // This is safe because we just verified the inner type is T
2715            Some(unsafe {
2716                let raw = Arc::into_raw(cloned);
2717                Arc::from_raw(raw as *const std::sync::RwLock<T>)
2718            })
2719        } else {
2720            None
2721        }
2722    }
2723    /// Add a new fragment to memory.
2724    pub fn remember(&mut self, fragment: KnowledgeFragment) {
2725        self.fragments.insert(fragment.id.clone(), fragment);
2726    }
2727    /// Process a search query against the local knowledge base.
2728    pub fn process_query(&mut self, query: &str) {
2729        let query_lower = query.to_lowercase();
2730        let mut results: Vec<(f32, String)> = self
2731            .fragments
2732            .iter()
2733            .map(|(id, frag)| {
2734                let mut score = 0.0;
2735                if frag.summary.to_lowercase().contains(&query_lower) {
2736                    score += 1.0;
2737                }
2738                if frag.source.to_lowercase().contains(&query_lower) {
2739                    score += 0.5;
2740                }
2741                (score, id.clone())
2742            })
2743            .filter(|(score, _)| *score > 0.0)
2744            .collect();
2745        // Sort by relevance score
2746        results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
2747        self.last_query_results = results.into_iter().map(|(_, id)| id).take(5).collect();
2748    }
2749    /// Captures a snapshot of the current state for debugging and hot-reloading.
2750    pub fn snapshot(&self) -> Vec<NodeStateSnapshot> {
2751        let mut snapshots = Vec::new();
2752        // Snapshots of agentic fragments
2753        for frag in self.fragments.values() {
2754            if let Ok(val) = serde_json::to_value(frag) {
2755                snapshots.push(NodeStateSnapshot { id: 0, state: val });
2756            }
2757        }
2758        snapshots
2759    }
2760}
2761/// A read/write projection into a `State<T>` owned elsewhere.
2762#[derive(Clone)]
2763pub struct Binding<T: Clone + Send + Sync + 'static> {
2764    swap: Arc<arc_swap::ArcSwap<T>>,
2765    #[cfg(not(target_arch = "wasm32"))]
2766    tvar: Arc<stm::TVar<T>>,
2767    version: Arc<std::sync::atomic::AtomicU64>,
2768}
2769impl<T: Clone + Send + Sync + 'static> Binding<T> {
2770    /// Create a binding from a State
2771    pub fn from_state(state: &State<T>) -> Self {
2772        Self {
2773            swap: Arc::clone(&state.swap),
2774            #[cfg(not(target_arch = "wasm32"))]
2775            tvar: Arc::clone(&state.tvar),
2776            version: Arc::clone(&state.version),
2777        }
2778    }
2779    /// Get the current value
2780    pub fn get(&self) -> T {
2781        (**self.swap.load()).clone()
2782    }
2783    /// Set a new value
2784    pub fn set(&self, value: T) {
2785        self.swap.store(Arc::new(value.clone()));
2786        #[cfg(not(target_arch = "wasm32"))]
2787        {
2788            let tvar = Arc::clone(&self.tvar);
2789            let v = value.clone();
2790            stm::atomically(move |tx| tvar.write(tx, v.clone()));
2791        }
2792        self.version
2793            .fetch_add(1, std::sync::atomic::Ordering::Release);
2794    }
2795    /// Get current version
2796    pub fn version(&self) -> u64 {
2797        self.version.load(std::sync::atomic::Ordering::Acquire)
2798    }
2799}
2800#[cfg(not(target_arch = "wasm32"))]
2801pub fn transact_pair<A, B, F>(state_a: &State<A>, state_b: &State<B>, f: F)
2802where
2803    A: Clone + Send + Sync + 'static,
2804    B: Clone + Send + Sync + 'static,
2805    F: Fn(&A, &B) -> (A, B),
2806{
2807    let tvar_a = Arc::clone(&state_a.tvar);
2808    let tvar_b = Arc::clone(&state_b.tvar);
2809    let (new_a, new_b) = stm::atomically(move |tx| {
2810        let a = tvar_a.read(tx)?;
2811        let b = tvar_b.read(tx)?;
2812        let (na, nb) = f(&a, &b);
2813        tvar_a.write(tx, na.clone())?;
2814        tvar_b.write(tx, nb.clone())?;
2815        Ok((na, nb))
2816    });
2817    state_a.swap.store(Arc::new(new_a.clone()));
2818    state_b.swap.store(Arc::new(new_b.clone()));
2819    state_a
2820        .version
2821        .fetch_add(1, std::sync::atomic::Ordering::Release);
2822    state_b
2823        .version
2824        .fetch_add(1, std::sync::atomic::Ordering::Release);
2825    let subs_a = Arc::clone(&state_a.subscribers);
2826    let subs_b = Arc::clone(&state_b.subscribers);
2827    if crate::is_batching() {
2828        crate::enqueue_batch_task(Box::new(move || {
2829            {
2830                let s = subs_a.lock().unwrap();
2831                for cb in s.iter() {
2832                    cb(&new_a);
2833                }
2834            }
2835            {
2836                let s = subs_b.lock().unwrap();
2837                for cb in s.iter() {
2838                    cb(&new_b);
2839                }
2840            }
2841        }));
2842    } else {
2843        {
2844            let s = subs_a.lock().unwrap();
2845            for cb in s.iter() {
2846                cb(&new_a);
2847            }
2848        }
2849        {
2850            let s = subs_b.lock().unwrap();
2851            for cb in s.iter() {
2852                cb(&new_b);
2853            }
2854        }
2855    }
2856}
2857use std::any::TypeId;
2858use std::sync::Mutex;
2859/// Global environment storage using TypeId as keys.
2860pub(crate) static ENVIRONMENT: OnceLock<
2861    Mutex<HashMap<TypeId, Box<dyn std::any::Any + Send + Sync>>>,
2862> = OnceLock::new();
2863/// Environment key type for accessing ambient values
2864/// Implement this trait to define a new environment key.
2865pub trait EnvKey: 'static + Send + Sync {
2866    /// The type of value stored in the environment
2867    type Value: Clone + Send + Sync + 'static;
2868    /// Get a default value for this key
2869    fn default_value() -> Self::Value;
2870}
2871/// Key for accessing the Yggdrasil design token tree
2872pub struct YggdrasilKey;
2873impl EnvKey for YggdrasilKey {
2874    type Value = YggdrasilTokens;
2875    fn default_value() -> Self::Value {
2876        default_tokens()
2877    }
2878}
2879// Duplicate AssetKey removed - original definition at line 63
2880/// System appearance (Light/Dark mode)
2881#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2882pub enum Appearance {
2883    Light,
2884    Dark,
2885}
2886/// Orientation for layouts
2887#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2888pub enum Orientation {
2889    Horizontal,
2890    Vertical,
2891}
2892/// Cross-axis alignment for layout containers.
2893#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2894pub enum Alignment {
2895    #[default]
2896    Center,
2897    Leading,
2898    Trailing,
2899    Top,
2900    Bottom,
2901}
2902/// Main-axis distribution for linear layout containers.
2903#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2904pub enum Distribution {
2905    #[default]
2906    Fill,
2907    Center,
2908    Leading,
2909    Trailing,
2910    SpaceBetween,
2911    SpaceAround,
2912    SpaceEvenly,
2913}
2914/// A color represented by RGBA components in the [0.0, 1.0] range.
2915#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
2916pub struct Color {
2917    pub r: f32,
2918    pub g: f32,
2919    pub b: f32,
2920    pub a: f32,
2921}
2922impl Color {
2923    pub const BLACK: Color = Color {
2924        r: 0.0,
2925        g: 0.0,
2926        b: 0.0,
2927        a: 1.0,
2928    };
2929    pub const WHITE: Color = Color {
2930        r: 1.0,
2931        g: 1.0,
2932        b: 1.0,
2933        a: 1.0,
2934    };
2935    pub const TRANSPARENT: Color = Color {
2936        r: 0.0,
2937        g: 0.0,
2938        b: 0.0,
2939        a: 0.0,
2940    };
2941    pub const RED: Color = Color {
2942        r: 1.0,
2943        g: 0.0,
2944        b: 0.0,
2945        a: 1.0,
2946    };
2947    pub const GREEN: Color = Color {
2948        r: 0.0,
2949        g: 1.0,
2950        b: 0.0,
2951        a: 1.0,
2952    };
2953    pub const BLUE: Color = Color {
2954        r: 0.0,
2955        g: 0.0,
2956        b: 1.0,
2957        a: 1.0,
2958    };
2959    pub const VIKING_GOLD: Color = Color {
2960        r: 1.0,
2961        g: 0.84,
2962        b: 0.0,
2963        a: 1.0,
2964    };
2965    pub const MAGENTA_LIQUID: Color = Color {
2966        r: 1.0,
2967        g: 0.0,
2968        b: 1.0,
2969        a: 1.0,
2970    };
2971    pub const TACTICAL_OBSIDIAN: Color = Color {
2972        r: 0.05,
2973        g: 0.05,
2974        b: 0.07,
2975        a: 1.0,
2976    };
2977    /// Calculate the relative luminance of the color as defined by WCAG 2.x
2978    pub fn relative_luminance(&self) -> f32 {
2979        fn res(c: f32) -> f32 {
2980            if c <= 0.03928 {
2981                c / 12.92
2982            } else {
2983                ((c + 0.055) / 1.055).powf(2.4)
2984            }
2985        }
2986        0.2126 * res(self.r) + 0.7152 * res(self.g) + 0.0722 * res(self.b)
2987    }
2988    /// Calculate the contrast ratio between this color and another color
2989    pub fn contrast_ratio(&self, other: &Color) -> f32 {
2990        let l1 = self.relative_luminance();
2991        let l2 = other.relative_luminance();
2992        if l1 > l2 {
2993            (l1 + 0.05) / (l2 + 0.05)
2994        } else {
2995            (l2 + 0.05) / (l1 + 0.05)
2996        }
2997    }
2998    pub const CYAN: Color = Color {
2999        r: 0.0,
3000        g: 1.0,
3001        b: 1.0,
3002        a: 1.0,
3003    };
3004    pub const YELLOW: Color = Color {
3005        r: 1.0,
3006        g: 1.0,
3007        b: 0.0,
3008        a: 1.0,
3009    };
3010    pub const MAGENTA: Color = Color {
3011        r: 1.0,
3012        g: 0.0,
3013        b: 1.0,
3014        a: 1.0,
3015    };
3016    pub const GRAY: Color = Color {
3017        r: 0.5,
3018        g: 0.5,
3019        b: 0.5,
3020        a: 1.0,
3021    };
3022    /// Create a new color from RGBA components.
3023    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
3024        Self { r, g, b, a }
3025    }
3026    /// Convert the color to a [r, g, b, a] array.
3027    pub fn as_array(&self) -> [f32; 4] {
3028        [self.r, self.g, self.b, self.a]
3029    }
3030}
3031impl View for Color {
3032    type Body = Never;
3033    fn body(self) -> Self::Body {
3034        unreachable!()
3035    }
3036    fn render(&self, renderer: &mut dyn Renderer, rect: Rect) {
3037        renderer.fill_rect(rect, self.as_array());
3038    }
3039}
3040/// Key for accessing the current system appearance
3041pub struct AppearanceKey;
3042impl EnvKey for AppearanceKey {
3043    type Value = Appearance;
3044    fn default_value() -> Self::Value {
3045        Appearance::Dark // Default to Dark (Ginnungagap) for Berserker aesthetic
3046    }
3047}
3048/// StyleResolver provides high-level access to themed values from the environment.
3049pub struct StyleResolver;
3050impl StyleResolver {
3051    /// Resolve a color from the current environment
3052    pub fn color(key: &str) -> String {
3053        let tokens = Environment::<YggdrasilKey>::new().get();
3054        let appearance = Environment::<AppearanceKey>::new().get();
3055        let is_dark = appearance == Appearance::Dark;
3056        tokens
3057            .get_color(key, is_dark)
3058            .unwrap_or_else(|| "#FF00FF".to_string()) // Default to MuspelMagenta on failure
3059    }
3060    /// Resolve a generic token value
3061    pub fn get<T: FromStr>(category: &str, key: &str) -> Option<T> {
3062        let tokens = Environment::<YggdrasilKey>::new().get();
3063        let appearance = Environment::<AppearanceKey>::new().get();
3064        let is_dark = appearance == Appearance::Dark;
3065        tokens.get(category, key, is_dark)
3066    }
3067    /// Resolve a color from the current environment as a [f32; 4] RGBA array.
3068    /// Returns the color value for the current appearance (light/dark).
3069    /// Falls back to magenta (#FF00FF) if the key is not found.
3070    pub fn color_array(key: &str) -> [f32; 4] {
3071        let hex = Self::color(key);
3072        parse_hex_color(&hex)
3073    }
3074}
3075
3076/// Parse a hex color string (#RRGGBB or #RRGGBBAA) into [f32; 4] RGBA.
3077fn parse_hex_color(hex: &str) -> [f32; 4] {
3078    let hex = hex.trim_start_matches('#');
3079    if hex.len() >= 6 {
3080        let r = u8::from_str_radix(&hex[0..2], 16).unwrap_or(255) as f32 / 255.0;
3081        let g = u8::from_str_radix(&hex[2..4], 16).unwrap_or(0) as f32 / 255.0;
3082        let b = u8::from_str_radix(&hex[4..6], 16).unwrap_or(255) as f32 / 255.0;
3083        let a = if hex.len() >= 8 {
3084            u8::from_str_radix(&hex[6..8], 16).unwrap_or(255) as f32 / 255.0
3085        } else {
3086            1.0
3087        };
3088        [r, g, b, a]
3089    } else {
3090        [1.0, 0.0, 1.0, 1.0] // Magenta fallback
3091    }
3092}
3093
3094/// The authoritative Cyberpunk Viking default tokens
3095pub fn default_tokens() -> YggdrasilTokens {
3096    let mut tokens = YggdrasilTokens::new();
3097    // Core Norse Colorways
3098    tokens.color.insert(
3099        "background".to_string(),
3100        TokenValue::Single {
3101            value: "#000000".to_string(), // Ginnungagap (The Void)
3102        },
3103    );
3104    tokens.color.insert(
3105        "primary".to_string(),
3106        TokenValue::Single {
3107            value: "#00FFFF".to_string(), // NiflCyan (Aesir Primary)
3108        },
3109    );
3110    tokens.color.insert(
3111        "secondary".to_string(),
3112        TokenValue::Single {
3113            value: "#FF00FF".to_string(), // MuspelMagenta (Berserker Secondary)
3114        },
3115    );
3116    tokens.color.insert(
3117        "surface".to_string(),
3118        TokenValue::Adaptive {
3119            light: "#FFFFFF".to_string(),
3120            dark: "#121212".to_string(),
3121        },
3122    );
3123    tokens.color.insert(
3124        "text".to_string(),
3125        TokenValue::Adaptive {
3126            light: "#000000".to_string(),
3127            dark: "#FFFFFF".to_string(),
3128        },
3129    );
3130    // Semantic component tokens
3131    tokens.color.insert(
3132        "surface_elevated".to_string(),
3133        TokenValue::Adaptive {
3134            light: "#FFFFFF".to_string(),
3135            dark: "#1A1A24".to_string(),
3136        },
3137    );
3138    tokens.color.insert(
3139        "surface_overlay".to_string(),
3140        TokenValue::Adaptive {
3141            light: "#FFFFFF".to_string(),
3142            dark: "#1E1E2E".to_string(),
3143        },
3144    );
3145    tokens.color.insert(
3146        "border".to_string(),
3147        TokenValue::Adaptive {
3148            light: "#D0D0D8".to_string(),
3149            dark: "#2A2A3A".to_string(),
3150        },
3151    );
3152    tokens.color.insert(
3153        "border_strong".to_string(),
3154        TokenValue::Adaptive {
3155            light: "#A0A0B0".to_string(),
3156            dark: "#3A3A50".to_string(),
3157        },
3158    );
3159    tokens.color.insert(
3160        "text_muted".to_string(),
3161        TokenValue::Adaptive {
3162            light: "#606070".to_string(),
3163            dark: "#8080A0".to_string(),
3164        },
3165    );
3166    tokens.color.insert(
3167        "text_dim".to_string(),
3168        TokenValue::Adaptive {
3169            light: "#9090A0".to_string(),
3170            dark: "#505070".to_string(),
3171        },
3172    );
3173    tokens.color.insert(
3174        "accent".to_string(),
3175        TokenValue::Single {
3176            value: "#00FFFF".to_string(), // NiflCyan
3177        },
3178    );
3179    tokens.color.insert(
3180        "accent_hover".to_string(),
3181        TokenValue::Single {
3182            value: "#33FFFF".to_string(),
3183        },
3184    );
3185    tokens.color.insert(
3186        "success".to_string(),
3187        TokenValue::Single {
3188            value: "#00E676".to_string(),
3189        },
3190    );
3191    tokens.color.insert(
3192        "warning".to_string(),
3193        TokenValue::Single {
3194            value: "#FFB300".to_string(),
3195        },
3196    );
3197    tokens.color.insert(
3198        "error".to_string(),
3199        TokenValue::Single {
3200            value: "#FF5252".to_string(),
3201        },
3202    );
3203    tokens.color.insert(
3204        "info".to_string(),
3205        TokenValue::Single {
3206            value: "#448AFF".to_string(),
3207        },
3208    );
3209    tokens.color.insert(
3210        "hover".to_string(),
3211        TokenValue::Adaptive {
3212            light: "#F0F0F5".to_string(),
3213            dark: "#252535".to_string(),
3214        },
3215    );
3216    tokens.color.insert(
3217        "active".to_string(),
3218        TokenValue::Adaptive {
3219            light: "#E0E0EB".to_string(),
3220            dark: "#303045".to_string(),
3221        },
3222    );
3223    tokens.color.insert(
3224        "disabled".to_string(),
3225        TokenValue::Adaptive {
3226            light: "#E8E8F0".to_string(),
3227            dark: "#1A1A28".to_string(),
3228        },
3229    );
3230    tokens.color.insert(
3231        "disabled_text".to_string(),
3232        TokenValue::Adaptive {
3233            light: "#B0B0C0".to_string(),
3234            dark: "#404060".to_string(),
3235        },
3236    );
3237    tokens.color.insert(
3238        "focus_ring".to_string(),
3239        TokenValue::Single {
3240            value: "#00FFFF".to_string(),
3241        },
3242    );
3243    tokens.color.insert(
3244        "shadow".to_string(),
3245        TokenValue::Adaptive {
3246            light: "#00000020".to_string(),
3247            dark: "#00000060".to_string(),
3248        },
3249    );
3250    tokens.color.insert(
3251        "code_bg".to_string(),
3252        TokenValue::Adaptive {
3253            light: "#F5F5FA".to_string(),
3254            dark: "#0D0D18".to_string(),
3255        },
3256    );
3257    // Bifrost (Glassmorphism) - Frosted Style
3258    tokens.bifrost.insert(
3259        "blur".to_string(),
3260        TokenValue::Single {
3261            value: "25.0".to_string(),
3262        },
3263    );
3264    tokens.bifrost.insert(
3265        "saturation".to_string(),
3266        TokenValue::Single {
3267            value: "1.2".to_string(),
3268        },
3269    );
3270    tokens.bifrost.insert(
3271        "opacity".to_string(),
3272        TokenValue::Single {
3273            value: "0.65".to_string(),
3274        },
3275    );
3276    // Gungnir (Neon Glow)
3277    tokens.gungnir.insert(
3278        "intensity".to_string(),
3279        TokenValue::Single {
3280            value: "1.0".to_string(),
3281        },
3282    );
3283    tokens.gungnir.insert(
3284        "radius".to_string(),
3285        TokenValue::Single {
3286            value: "15.0".to_string(),
3287        },
3288    );
3289    // Mjolnir (Sharp Geometry)
3290    tokens.mjolnir.insert(
3291        "clip_angle".to_string(),
3292        TokenValue::Single {
3293            value: "12.0".to_string(),
3294        },
3295    );
3296    tokens.mjolnir.insert(
3297        "border_width".to_string(),
3298        TokenValue::Single {
3299            value: "2.0".to_string(),
3300        },
3301    );
3302    // Sleipnir (Spring Animation)
3303    tokens.anim.insert(
3304        "stiffness".to_string(),
3305        TokenValue::Single {
3306            value: "170.0".to_string(),
3307        },
3308    );
3309    tokens.anim.insert(
3310        "damping".to_string(),
3311        TokenValue::Single {
3312            value: "26.0".to_string(),
3313        },
3314    );
3315    tokens.anim.insert(
3316        "mass".to_string(),
3317        TokenValue::Single {
3318            value: "1.0".to_string(),
3319        },
3320    );
3321    // Accessibility
3322    tokens.accessibility.insert(
3323        "reduce_motion".to_string(),
3324        TokenValue::Single {
3325            value: "false".to_string(),
3326        },
3327    );
3328    tokens
3329}
3330/// Environment wrapper for accessing ambient values
3331pub struct Environment<K: EnvKey> {
3332    _marker: std::marker::PhantomData<K>,
3333}
3334impl<K: EnvKey> Default for Environment<K> {
3335    fn default() -> Self {
3336        Self::new()
3337    }
3338}
3339impl<K: EnvKey> Environment<K> {
3340    /// Create a new Environment
3341    pub fn new() -> Self {
3342        Self {
3343            _marker: std::marker::PhantomData,
3344        }
3345    }
3346    /// Get the current value from the environment
3347    pub fn get(&self) -> K::Value {
3348        if let Some(env_store) = ENVIRONMENT.get() {
3349            let env_lock = env_store.lock().unwrap();
3350            if let Some(val) = env_lock.get(&std::any::TypeId::of::<K>()) {
3351                if let Some(typed_val) = val.downcast_ref::<K::Value>() {
3352                    return typed_val.clone();
3353                } else {
3354                    log::warn!(
3355                        "Environment: Downcast failed for key type {:?}",
3356                        std::any::type_name::<K>()
3357                    );
3358                }
3359            } else {
3360                log::debug!(
3361                    "Environment: Key not found: {:?}. Returning default.",
3362                    std::any::type_name::<K>()
3363                );
3364            }
3365        } else {
3366            log::debug!(
3367                "Environment: Store not initialized. Key: {:?}. Returning default.",
3368                std::any::type_name::<K>()
3369            );
3370        }
3371        K::default_value()
3372    }
3373}
3374/// Ambient environment management
3375pub mod env {
3376    /// Insert a value into the environment
3377    pub fn insert<K: super::EnvKey>(value: K::Value) {
3378        let store = super::ENVIRONMENT
3379            .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
3380        let mut env_map = store.lock().unwrap();
3381        env_map.insert(std::any::TypeId::of::<K>(), Box::new(value));
3382    }
3383    /// Remove a value from the environment.
3384    pub fn remove<K: super::EnvKey>() {
3385        if let Some(store) = super::ENVIRONMENT.get() {
3386            let mut env_map = store.lock().unwrap();
3387            env_map.remove(&std::any::TypeId::of::<K>());
3388        }
3389    }
3390}
3391/// Geometry modifiers
3392/// Size of the view in logical pixels
3393#[derive(Debug, Clone, Copy, PartialEq)]
3394pub struct Size {
3395    pub width: f32,
3396    pub height: f32,
3397}
3398
3399impl Size {
3400    pub const ZERO: Self = Self {
3401        width: 0.0,
3402        height: 0.0,
3403    };
3404
3405    pub fn new(width: f32, height: f32) -> Self {
3406        Self { width, height }
3407    }
3408}
3409
3410/// Insets for padding
3411#[derive(Debug, Clone, Copy, PartialEq)]
3412pub struct EdgeInsets {
3413    pub top: f32,
3414    pub leading: f32,
3415    pub bottom: f32,
3416    pub trailing: f32,
3417}
3418
3419impl EdgeInsets {
3420    /// Equal insets on all edges
3421    pub fn all(value: f32) -> Self {
3422        Self {
3423            top: value,
3424            leading: value,
3425            bottom: value,
3426            trailing: value,
3427        }
3428    }
3429
3430    /// Vertical insets (top and bottom)
3431    pub fn vertical(value: f32) -> Self {
3432        Self {
3433            top: value,
3434            leading: 0.0,
3435            bottom: value,
3436            trailing: 0.0,
3437        }
3438    }
3439
3440    /// Horizontal insets (leading and trailing)
3441    pub fn horizontal(value: f32) -> Self {
3442        Self {
3443            top: 0.0,
3444            leading: value,
3445            bottom: 0.0,
3446            trailing: value,
3447        }
3448    }
3449}
3450
3451/// Modifier to set the size of a view
3452#[derive(Debug, Clone, Copy, PartialEq)]
3453pub struct FrameModifier {
3454    pub width: Option<f32>,
3455    pub height: Option<f32>,
3456}
3457
3458impl Default for FrameModifier {
3459    fn default() -> Self {
3460        Self::new()
3461    }
3462}
3463
3464impl FrameModifier {
3465    pub fn new() -> Self {
3466        Self {
3467            width: None,
3468            height: None,
3469        }
3470    }
3471
3472    pub fn width(mut self, width: f32) -> Self {
3473        self.width = Some(width);
3474        self
3475    }
3476
3477    pub fn height(mut self, height: f32) -> Self {
3478        self.height = Some(height);
3479        self
3480    }
3481
3482    pub fn size(mut self, width: f32, height: f32) -> Self {
3483        self.width = Some(width);
3484        self.height = Some(height);
3485        self
3486    }
3487}
3488
3489impl ViewModifier for FrameModifier {
3490    fn modify<V: View>(self, content: V) -> impl View {
3491        ModifiedView::new(content, self)
3492    }
3493}
3494
3495/// Modifier to set the flex weight of a view
3496#[derive(Debug, Clone, Copy, PartialEq)]
3497pub struct FlexModifier {
3498    pub weight: f32,
3499}
3500
3501impl ViewModifier for FlexModifier {
3502    fn modify<V: View>(self, content: V) -> impl View {
3503        ModifiedView::new(content, self)
3504    }
3505
3506    fn child_flex_weight<V: View>(&self, _view: &V) -> f32 {
3507        self.weight
3508    }
3509}
3510
3511/// Modifier to offset a view
3512#[derive(Debug, Clone, Copy, PartialEq)]
3513pub struct OffsetModifier {
3514    pub x: f32,
3515    pub y: f32,
3516}
3517
3518impl OffsetModifier {
3519    pub fn new(x: f32, y: f32) -> Self {
3520        Self { x, y }
3521    }
3522}
3523
3524impl ViewModifier for OffsetModifier {
3525    fn modify<V: View>(self, content: V) -> impl View {
3526        ModifiedView::new(content, self)
3527    }
3528}
3529
3530/// Modifier to set the z-index of a view
3531#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3532pub struct ZIndexModifier {
3533    pub z_index: i32,
3534}
3535
3536impl ZIndexModifier {
3537    pub fn new(z_index: i32) -> Self {
3538        Self { z_index }
3539    }
3540}
3541
3542impl ViewModifier for ZIndexModifier {
3543    fn modify<V: View>(self, content: V) -> impl View {
3544        ModifiedView::new(content, self)
3545    }
3546}
3547
3548/// Layout constraints for views
3549#[derive(Debug, Clone, Copy, PartialEq, Default)]
3550pub struct LayoutConstraints {
3551    pub min_width: Option<f32>,
3552    pub max_width: Option<f32>,
3553    pub min_height: Option<f32>,
3554    pub max_height: Option<f32>,
3555}
3556
3557/// Modifier to set layout constraints
3558#[derive(Debug, Clone, Copy, PartialEq)]
3559pub struct LayoutModifier {
3560    pub constraints: LayoutConstraints,
3561}
3562
3563impl LayoutModifier {
3564    pub fn new(constraints: LayoutConstraints) -> Self {
3565        Self { constraints }
3566    }
3567}
3568
3569impl ViewModifier for LayoutModifier {
3570    fn modify<V: View>(self, content: V) -> impl View {
3571        ModifiedView::new(content, self)
3572    }
3573}
3574
3575/// Modifier to handle platform safe areas
3576#[derive(Debug, Clone, Copy, PartialEq)]
3577pub struct SafeAreaModifier {
3578    pub ignores: bool,
3579}
3580
3581impl ViewModifier for SafeAreaModifier {
3582    fn modify<V: View>(self, content: V) -> impl View {
3583        ModifiedView::new(content, self)
3584    }
3585}
3586
3587/// Modifier to add elevation (shadow) to a view
3588#[derive(Debug, Clone, Copy, PartialEq)]
3589pub struct ElevationModifier {
3590    pub level: f32,
3591}
3592
3593impl ViewModifier for ElevationModifier {
3594    fn modify<V: View>(self, content: V) -> impl View {
3595        ModifiedView::new(content, self)
3596    }
3597
3598    fn render_view<V: View>(&self, view: &V, renderer: &mut dyn Renderer, rect: Rect) {
3599        if self.level > 0.0 {
3600            let radius = self.level * 2.0;
3601            let offset_y = self.level * 0.5;
3602            let shadow_color = [0.0, 0.0, 0.0, 0.3];
3603            renderer.push_shadow(radius, shadow_color, [0.0, offset_y]);
3604            view.render(renderer, rect);
3605            renderer.pop_shadow();
3606        } else {
3607            view.render(renderer, rect);
3608        }
3609    }
3610}
3611
3612// Layout subsystem
3613pub mod layout {
3614    use super::*;
3615
3616    /// Key used to identify a cached layout entry.
3617    /// Combines a view hash with a generation counter for cache invalidation.
3618    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3619    pub struct LayoutKey {
3620        pub view_hash: u64,
3621        pub generation: u64,
3622    }
3623
3624    // Layout pass scratch space
3625    pub struct LayoutCache {
3626        pub safe_area: SafeArea,
3627        size_cache: HashMap<(u64, u32, u32), Size>, // (ViewHash, ProposalW, ProposalH)
3628        /// Monotonically increasing generation counter for cache invalidation.
3629        /// When a view tree changes, bumping the generation causes stale entries
3630        /// to be treated as invalid without eagerly clearing the entire cache.
3631        generation: u64,
3632    }
3633
3634    impl Default for LayoutCache {
3635        fn default() -> Self {
3636            Self::new()
3637        }
3638    }
3639
3640    impl LayoutCache {
3641        pub fn new() -> Self {
3642            Self {
3643                safe_area: SafeArea::default(),
3644                size_cache: HashMap::new(),
3645                generation: 0,
3646            }
3647        }
3648
3649        /// Returns the current generation counter.
3650        pub fn generation(&self) -> u64 {
3651            self.generation
3652        }
3653
3654        /// Bump the generation counter, logically invalidating all cached entries
3655        /// without eagerly clearing them. Subsequent lookups with the old generation
3656        /// will miss until re-populated.
3657        pub fn invalidate(&mut self) {
3658            self.generation = self.generation.wrapping_add(1);
3659        }
3660
3661        /// Check whether a cached entry for the given key is still valid
3662        /// against the current generation.
3663        pub fn is_valid(&self, key: LayoutKey, current_gen: u64) -> bool {
3664            key.generation == current_gen && key.generation == self.generation
3665        }
3666
3667        pub fn clear(&mut self) {
3668            self.safe_area = SafeArea::default();
3669            self.size_cache.clear();
3670        }
3671
3672        pub fn get_size(&self, view_hash: u64, proposal: SizeProposal) -> Option<Size> {
3673            let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
3674            let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
3675            self.size_cache.get(&(view_hash, pw, ph)).copied()
3676        }
3677
3678        pub fn set_size(&mut self, view_hash: u64, proposal: SizeProposal, size: Size) {
3679            let pw = (proposal.width.unwrap_or(-1.0) * 100.0) as u32;
3680            let ph = (proposal.height.unwrap_or(-1.0) * 100.0) as u32;
3681            self.size_cache.insert((view_hash, pw, ph), size);
3682        }
3683
3684        /// Remove all cached size entries for a specific view hash.
3685        pub fn invalidate_view(&mut self, view_hash: u64) {
3686            self.size_cache.retain(|&(hash, _, _), _| hash != view_hash);
3687        }
3688    }
3689
3690    /// Proposed size from parent view
3691    #[derive(Debug, Clone, Copy, PartialEq)]
3692    pub struct SizeProposal {
3693        pub width: Option<f32>,
3694        pub height: Option<f32>,
3695    }
3696
3697    impl SizeProposal {
3698        pub fn unspecified() -> Self {
3699            Self {
3700                width: None,
3701                height: None,
3702            }
3703        }
3704
3705        pub fn width(width: f32) -> Self {
3706            Self {
3707                width: Some(width),
3708                height: None,
3709            }
3710        }
3711
3712        pub fn height(height: f32) -> Self {
3713            Self {
3714                width: None,
3715                height: Some(height),
3716            }
3717        }
3718
3719        pub fn tight(width: f32, height: f32) -> Self {
3720            Self {
3721                width: Some(width),
3722                height: Some(height),
3723            }
3724        }
3725
3726        pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
3727            Self { width, height }
3728        }
3729    }
3730
3731    /// A view that can participate in layout
3732    pub trait LayoutView: Send {
3733        /// Propose a size for this view given the available space
3734        fn size_that_fits(
3735            &self,
3736            proposal: SizeProposal,
3737            subviews: &[&dyn LayoutView],
3738            cache: &mut LayoutCache,
3739        ) -> Size;
3740
3741        /// Place subviews within the given bounds
3742        fn place_subviews(
3743            &self,
3744            bounds: Rect,
3745            subviews: &mut [&mut dyn LayoutView],
3746            cache: &mut LayoutCache,
3747        );
3748
3749        /// Returns the flex weight of this view (default is 0.0, which means fixed/intrinsic)
3750        fn flex_weight(&self) -> f32 {
3751            0.0
3752        }
3753
3754        /// Return a debug representation of this layout subtree.
3755        /// The `indent` parameter controls the indentation level for nested display.
3756        fn debug_layout(&self, indent: usize) -> String {
3757            let prefix = " ".repeat(indent);
3758            format!("{}LayoutView", prefix)
3759        }
3760    }
3761    /// Edge insets for padding, margins, and safe areas
3762    #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
3763    pub struct EdgeInsets {
3764        pub top: f32,
3765        pub leading: f32,
3766        pub bottom: f32,
3767        pub trailing: f32,
3768    }
3769
3770    impl EdgeInsets {
3771        pub fn new(top: f32, leading: f32, bottom: f32, trailing: f32) -> Self {
3772            Self {
3773                top,
3774                leading,
3775                bottom,
3776                trailing,
3777            }
3778        }
3779
3780        pub fn all(value: f32) -> Self {
3781            Self {
3782                top: value,
3783                leading: value,
3784                bottom: value,
3785                trailing: value,
3786            }
3787        }
3788    }
3789
3790    /// SafeArea constraints provided by the platform
3791    #[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
3792    pub struct SafeArea {
3793        pub insets: EdgeInsets,
3794    }
3795
3796    /// Rectangle in logical pixels
3797    #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
3798    pub struct Rect {
3799        pub x: f32,
3800        pub y: f32,
3801        pub width: f32,
3802        pub height: f32,
3803    }
3804
3805    impl Rect {
3806        pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
3807            Self {
3808                x,
3809                y,
3810                width,
3811                height,
3812            }
3813        }
3814
3815        pub fn inset(&self, amount: f32) -> Self {
3816            Self {
3817                x: self.x + amount,
3818                y: self.y + amount,
3819                width: (self.width - amount * 2.0).max(0.0),
3820                height: (self.height - amount * 2.0).max(0.0),
3821            }
3822        }
3823
3824        pub fn offset(&self, dx: f32, dy: f32) -> Self {
3825            Self {
3826                x: self.x + dx,
3827                y: self.y + dy,
3828                ..*self
3829            }
3830        }
3831
3832        pub fn zero() -> Self {
3833            Self {
3834                x: 0.0,
3835                y: 0.0,
3836                width: 0.0,
3837                height: 0.0,
3838            }
3839        }
3840
3841        pub fn contains(&self, x: f32, y: f32) -> bool {
3842            x >= self.x && x <= self.x + self.width && y >= self.y && y <= self.y + self.height
3843        }
3844
3845        pub fn size(&self) -> Size {
3846            Size {
3847                width: self.width,
3848                height: self.height,
3849            }
3850        }
3851
3852        /// Split the rect horizontally into N equal pieces
3853        pub fn split_horizontal(&self, n: usize) -> Vec<Rect> {
3854            if n == 0 {
3855                return vec![];
3856            }
3857            let item_width = self.width / n as f32;
3858            (0..n)
3859                .map(|i| Rect {
3860                    x: self.x + i as f32 * item_width,
3861                    y: self.y,
3862                    width: item_width,
3863                    height: self.height,
3864                })
3865                .collect()
3866        }
3867
3868        /// Split the rect vertically into N equal pieces
3869        pub fn split_vertical(&self, n: usize) -> Vec<Rect> {
3870            if n == 0 {
3871                return vec![];
3872            }
3873            let item_height = self.height / n as f32;
3874            (0..n)
3875                .map(|i| Rect {
3876                    x: self.x,
3877                    y: self.y + i as f32 * item_height,
3878                    width: self.width,
3879                    height: item_height,
3880                })
3881                .collect()
3882        }
3883    }
3884}
3885
3886// Re-export layout items for convenience
3887pub use layout::{LayoutCache, LayoutKey, LayoutView, Rect, SizeProposal};
3888// Size and FrameRenderer are pub items in this module; no re-export alias needed.
3889
3890pub mod agents;
3891pub mod animation;
3892pub mod gpu;
3893pub mod material;
3894pub mod runtime;
3895pub mod scene_graph;
3896pub mod sdf_shadow;
3897
3898pub use scene_graph::{NodeId, bifrost_registry};
3899pub use material::DrawMaterial;
3900
3901// Duplicate AssetState removed - original definition at line 67
3902
3903/// AssetManager defines the interface for loading and caching external resources.
3904pub trait AssetManager: Send + Sync {
3905    /// Request an image asset. Returns the current state (Loading, Ready, or Error).
3906    fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>>;
3907
3908    /// Pre-load an image into the cache.
3909    fn preload_image(&self, url: &str);
3910}
3911
3912/// User input event types
3913#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
3914pub enum Event {
3915    PointerDown {
3916        x: f32,
3917        y: f32,
3918        button: u32,
3919    },
3920    PointerUp {
3921        x: f32,
3922        y: f32,
3923        button: u32,
3924    },
3925    PointerMove {
3926        x: f32,
3927        y: f32,
3928    },
3929    PointerClick {
3930        x: f32,
3931        y: f32,
3932        button: u32,
3933    },
3934    PointerEnter,
3935    PointerLeave,
3936    /// Mouse wheel / trackpad scroll event.
3937    /// `delta_x` is the horizontal scroll amount, `delta_y` is the vertical scroll amount (positive = scroll down).
3938    PointerWheel {
3939        x: f32,
3940        y: f32,
3941        delta_x: f32,
3942        delta_y: f32,
3943    },
3944    /// Double-click event (rapid successive clicks).
3945    PointerDoubleClick {
3946        x: f32,
3947        y: f32,
3948        button: u32,
3949    },
3950    /// Drag-and-drop: drag started (pointer moved while button held past threshold).
3951    DragStart {
3952        x: f32,
3953        y: f32,
3954        button: u32,
3955    },
3956    /// Drag-and-drop: drag in progress.
3957    DragMove {
3958        x: f32,
3959        y: f32,
3960    },
3961    /// Drag-and-drop: drag ended (pointer released).
3962    DragEnd {
3963        x: f32,
3964        y: f32,
3965    },
3966    KeyDown {
3967        key: String,
3968    },
3969    KeyUp {
3970        key: String,
3971    },
3972    /// Focus gained by a node.
3973    FocusIn,
3974    /// Focus lost by a node.
3975    FocusOut,
3976    /// Clipboard copy event.
3977    Copy,
3978    /// Clipboard cut event.
3979    Cut,
3980    /// Clipboard paste event with the pasted text content.
3981    Paste(String),
3982    /// Input Method Editor event (e.g. CJK character composition)
3983    Ime(String),
3984    /// Touch began at the given position.
3985    TouchStart {
3986        x: f32,
3987        y: f32,
3988        touch_id: u64,
3989    },
3990    /// Touch moved to a new position.
3991    TouchMove {
3992        x: f32,
3993        y: f32,
3994        touch_id: u64,
3995    },
3996    /// Touch ended at the given position.
3997    TouchEnd {
3998        x: f32,
3999        y: f32,
4000        touch_id: u64,
4001    },
4002    /// Touch cancelled.
4003    TouchCancel {
4004        touch_id: u64,
4005    },
4006    /// Multi-touch pinch gesture.
4007    GesturePinch {
4008        scale: f32,
4009        velocity: f32,
4010    },
4011    /// Multi-touch swipe/pan gesture.
4012    GestureSwipe {
4013        dx: f32,
4014        dy: f32,
4015        velocity_x: f32,
4016        velocity_y: f32,
4017    },
4018}
4019
4020impl Event {
4021    /// Returns the canonical string name of the event for lookup in handler maps.
4022    pub fn name(&self) -> &'static str {
4023        match self {
4024            Self::PointerDown { .. } => "pointerdown",
4025            Self::PointerUp { .. } => "pointerup",
4026            Self::PointerMove { .. } => "pointermove",
4027            Self::PointerClick { .. } => "pointerclick",
4028            Self::PointerEnter => "pointerenter",
4029            Self::PointerLeave => "pointerleave",
4030            Self::PointerWheel { .. } => "pointerwheel",
4031            Self::PointerDoubleClick { .. } => "pointerdoubleclick",
4032            Self::DragStart { .. } => "dragstart",
4033            Self::DragMove { .. } => "dragmove",
4034            Self::DragEnd { .. } => "dragend",
4035            Self::KeyDown { .. } => "keydown",
4036            Self::KeyUp { .. } => "keyup",
4037            Self::FocusIn => "focusin",
4038            Self::FocusOut => "focusout",
4039            Self::Copy => "copy",
4040            Self::Cut => "cut",
4041            Self::Paste(_) => "paste",
4042            Self::Ime(_) => "ime",
4043            Self::TouchStart { .. } => "touchstart",
4044            Self::TouchMove { .. } => "touchmove",
4045            Self::TouchEnd { .. } => "touchend",
4046            Self::TouchCancel { .. } => "touchcancel",
4047            Self::GesturePinch { .. } => "gesturepinch",
4048            Self::GestureSwipe { .. } => "gestureswipe",
4049        }
4050    }
4051}
4052
4053/// Response from an event handler
4054#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4055pub enum EventResponse {
4056    Handled,
4057    Ignored,
4058}
4059
4060/// A basic implementation of AssetManager that can be overridden by platform backends.
4061pub struct DefaultAssetManager {
4062    cache: AssetCache,
4063}
4064type AssetCache = Arc<arc_swap::ArcSwap<HashMap<String, AssetState<Arc<Vec<u8>>>>>>;
4065
4066impl Default for DefaultAssetManager {
4067    fn default() -> Self {
4068        Self::new()
4069    }
4070}
4071
4072impl DefaultAssetManager {
4073    pub fn new() -> Self {
4074        Self {
4075            cache: Arc::new(arc_swap::ArcSwap::from_pointee(HashMap::new())),
4076        }
4077    }
4078}
4079
4080impl AssetManager for DefaultAssetManager {
4081    fn load_image(&self, url: &str) -> AssetState<Arc<Vec<u8>>> {
4082        if let Some(state) = self.cache.load().get(url) {
4083            return state.clone();
4084        }
4085
4086        self.cache.rcu(|map| {
4087            let mut m = (**map).clone();
4088            m.entry(url.to_string()).or_insert(AssetState::Loading);
4089            m
4090        });
4091        AssetState::Loading
4092    }
4093
4094    fn preload_image(&self, _url: &str) {}
4095}
4096
4097use std::future::Future;
4098
4099/// Suspense wrapper for asynchronous state management.
4100/// Integrates with State<T> to provide loading/error/ready states for async operations.
4101pub struct Suspense<T: Clone + Send + Sync + 'static> {
4102    inner: State<AssetState<T>>,
4103}
4104
4105impl<T: Clone + Send + Sync + 'static> Default for Suspense<T> {
4106    fn default() -> Self {
4107        Self::new()
4108    }
4109}
4110
4111impl<T: Clone + Send + Sync + 'static> Suspense<T> {
4112    pub fn new() -> Self {
4113        Self {
4114            inner: State::new(AssetState::Loading),
4115        }
4116    }
4117
4118    pub fn new_async<F>(future: F) -> Self
4119    where
4120        F: Future<Output = Result<T, String>> + Send + 'static,
4121    {
4122        let suspense = Self::new();
4123        let suspense_clone = suspense.clone();
4124
4125        #[cfg(not(target_arch = "wasm32"))]
4126        {
4127            // Try to use an existing tokio runtime, or fallback to a dedicated thread
4128            if let Ok(handle) = tokio::runtime::Handle::try_current() {
4129                handle.spawn(async move {
4130                    let result = future.await;
4131                    match result {
4132                        Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
4133                        Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
4134                    }
4135                });
4136            } else {
4137                std::thread::spawn(move || {
4138                    let rt = tokio::runtime::Builder::new_current_thread()
4139                        .enable_all()
4140                        .build()
4141                        .unwrap();
4142                    rt.block_on(async {
4143                        let result = future.await;
4144                        match result {
4145                            Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
4146                            Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
4147                        }
4148                    });
4149                });
4150            }
4151        }
4152        #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
4153        {
4154            wasm_bindgen_futures::spawn_local(async move {
4155                let result = future.await;
4156                match result {
4157                    Ok(val) => suspense_clone.inner.set(AssetState::Ready(val)),
4158                    Err(err) => suspense_clone.inner.set(AssetState::Error(err)),
4159                }
4160            });
4161        }
4162
4163        suspense
4164    }
4165
4166    pub fn ready(value: T) -> Self {
4167        Self {
4168            inner: State::new(AssetState::Ready(value)),
4169        }
4170    }
4171
4172    pub fn error(message: impl Into<String>) -> Self {
4173        Self {
4174            inner: State::new(AssetState::Error(message.into())),
4175        }
4176    }
4177
4178    pub fn get(&self) -> AssetState<T> {
4179        self.inner.get()
4180    }
4181
4182    pub fn get_ref(&self) -> AssetState<T> {
4183        self.inner.get()
4184    }
4185
4186    pub fn is_loading(&self) -> bool {
4187        matches!(self.get(), AssetState::Loading)
4188    }
4189
4190    pub fn is_ready(&self) -> bool {
4191        matches!(self.get(), AssetState::Ready(_))
4192    }
4193
4194    pub fn is_error(&self) -> bool {
4195        matches!(self.get(), AssetState::Error(_))
4196    }
4197
4198    pub fn ready_value(&self) -> Option<T> {
4199        match self.get() {
4200            AssetState::Ready(value) => Some(value),
4201            _ => None,
4202        }
4203    }
4204
4205    pub fn error_message(&self) -> Option<String> {
4206        match self.get() {
4207            AssetState::Error(message) => Some(message),
4208            _ => None,
4209        }
4210    }
4211
4212    pub fn subscribe<F: Fn(&AssetState<T>) + Send + Sync + 'static>(&self, callback: F) {
4213        self.inner.subscribe(callback)
4214    }
4215
4216    pub fn inner_state(&self) -> &State<AssetState<T>> {
4217        &self.inner
4218    }
4219}
4220
4221impl<T: Clone + Send + Sync + 'static> Clone for Suspense<T> {
4222    fn clone(&self) -> Self {
4223        Self {
4224            inner: self.inner.clone(),
4225        }
4226    }
4227}
4228
4229impl<T: Clone + Send + Sync + 'static> From<T> for Suspense<T> {
4230    fn from(value: T) -> Self {
4231        Self::ready(value)
4232    }
4233}
4234
4235impl<T: Clone + Send + Sync + 'static> From<Result<T, String>> for Suspense<T> {
4236    fn from(result: Result<T, String>) -> Self {
4237        match result {
4238            Ok(value) => Self::ready(value),
4239            Err(error) => Self::error(error),
4240        }
4241    }
4242}
4243
4244#[cfg(test)]
4245mod phase1_test;
4246
4247/// Berserker mode states for the rendering pipeline.
4248#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4249pub enum BerserkerMode {
4250    Normal,
4251    Rage,    // Red tint, slight shake
4252    Frenzy,  // Heavy red tint, motion blur, aggressive shake
4253    GodMode, // Golden aura, lightning arcs
4254}
4255
4256/// Seer trait for AI-assisted UI components.
4257/// Allows components to receive "prophecies" (predictions) from an AI backend.
4258pub trait Seer: Send + Sync {
4259    /// Provide a prediction for the next user action or content.
4260    fn predict(&self, context: &str) -> String;
4261    /// Stream real-time "whispers" (transcriptions/intent).
4262    fn whispers(&self) -> Vec<String>;
4263}