Skip to main content

dioxuscut_renderer/
render_frames.rs

1//! Frame rendering configuration and error types.
2//!
3//! Frame rasterization is handled natively by `dioxuscut-rasterizer` via CPU (tiny-skia) or GPU (wgpu).
4
5use thiserror::Error;
6
7/// Error type for the renderer.
8#[derive(Debug, Error)]
9pub enum RenderError {
10    #[error("IO error: {0}")]
11    Io(#[from] std::io::Error),
12    #[error("Server error: {0}")]
13    Server(#[from] crate::server::ServerError),
14    #[error("Encode error: {0}")]
15    Encode(String),
16    #[error("Frame {0} failed: {1}")]
17    FrameFailed(u32, String),
18}
19
20/// Configuration for a render job.
21#[derive(Debug, Clone)]
22pub struct RenderConfig {
23    /// URL of the Dioxus app or server.
24    pub url: String,
25    /// Output directory for frame PNGs.
26    pub output_dir: std::path::PathBuf,
27    /// Width of the video.
28    pub width: u32,
29    /// Height of the video.
30    pub height: u32,
31    /// Frames per second.
32    pub fps: f64,
33    /// Total duration in frames.
34    pub duration_in_frames: u32,
35    /// Frame range to render (`None` = all frames).
36    pub frame_range: Option<std::ops::RangeInclusive<u32>>,
37    /// Concurrency — how many frames to render in parallel.
38    pub concurrency: usize,
39}
40
41impl RenderConfig {
42    /// Create a new render config with sensible defaults.
43    pub fn new(
44        url: String,
45        output_dir: impl Into<std::path::PathBuf>,
46        width: u32,
47        height: u32,
48        fps: f64,
49        duration_in_frames: u32,
50    ) -> Self {
51        Self {
52            url,
53            output_dir: output_dir.into(),
54            width,
55            height,
56            fps,
57            duration_in_frames,
58            frame_range: None,
59            concurrency: num_cpus(),
60        }
61    }
62
63    /// Returns the frame range, defaulting to all frames.
64    pub fn effective_range(&self) -> std::ops::RangeInclusive<u32> {
65        self.frame_range
66            .clone()
67            .unwrap_or(0..=self.duration_in_frames.saturating_sub(1))
68    }
69}
70
71fn num_cpus() -> usize {
72    std::thread::available_parallelism()
73        .map(|n| n.get())
74        .unwrap_or(4)
75}