Skip to main content

repose_devtools/
lib.rs

1use std::sync::Arc;
2
3use web_time::Instant;
4
5use repose_core::{Color, Rect, Scene, SceneNode};
6
7pub struct Hud {
8    pub inspector_enabled: bool,
9    pub hovered: Option<Rect>,
10    frame_count: u64,
11    last_frame: Option<Instant>,
12    fps_smooth: f32,
13    pub metrics: Option<Metrics>,
14}
15
16impl Default for Hud {
17    fn default() -> Self {
18        Self::new()
19    }
20}
21
22impl Hud {
23    pub fn new() -> Self {
24        Self {
25            inspector_enabled: false,
26            hovered: None,
27            frame_count: 0,
28            last_frame: None,
29            fps_smooth: 0.0,
30            metrics: None,
31        }
32    }
33    pub fn toggle_inspector(&mut self) {
34        self.inspector_enabled = !self.inspector_enabled;
35    }
36    pub fn set_hovered(&mut self, r: Option<Rect>) {
37        self.hovered = r;
38    }
39
40    pub fn overlay(&mut self, scene: &mut Scene) {
41        self.frame_count += 1;
42        // FPS
43        let now = Instant::now();
44        if let Some(prev) = self.last_frame.replace(now) {
45            let dt = (now - prev).as_secs_f32();
46            if dt > 0.0 {
47                let fps = 1.0 / dt;
48                // simple EMA
49                let a = 0.2;
50                self.fps_smooth = if self.fps_smooth == 0.0 {
51                    fps
52                } else {
53                    (1.0 - a) * self.fps_smooth + a * fps
54                };
55            }
56        }
57        let mut lines = vec![
58            format!("frame: {}", self.frame_count),
59            format!("fps: {:.1}", self.fps_smooth),
60        ];
61        if let Some(m) = &self.metrics {
62            lines.push(format!("build+layout: {:.2} ms", m.build_layout_ms));
63            lines.push(format!("nodes: {}", m.scene_nodes));
64        }
65        let text = lines.join("  |  ");
66        scene.nodes.push(SceneNode::Text {
67            rect: Rect {
68                x: 8.0,
69                y: 8.0,
70                w: 200.0,
71                h: 16.0,
72            },
73            text: Arc::<str>::from(text),
74            color: Color::from_hex("#AAAAAA"),
75            size: 14.0,
76        });
77
78        if let Some(r) = self.hovered {
79            scene.nodes.push(SceneNode::Border {
80                rect: r,
81                color: Color::from_hex("#44AAFF"),
82                width: 2.0,
83                radius: 0.0,
84            });
85        }
86    }
87}
88
89#[derive(Clone, Debug, Default)]
90pub struct Metrics {
91    pub build_layout_ms: f32,
92    pub scene_nodes: usize,
93}
94
95pub struct Inspector {
96    pub hud: Hud,
97}
98impl Default for Inspector {
99    fn default() -> Self {
100        Self::new()
101    }
102}
103
104impl Inspector {
105    pub fn new() -> Self {
106        Self { hud: Hud::new() }
107    }
108    pub fn frame(&mut self, scene: &mut Scene) {
109        if self.hud.inspector_enabled {
110            self.hud.overlay(scene);
111        }
112    }
113}