dioxus-chimeras 0.2.0

Dioxus integration for the chimeras camera library. Provides a preview server, frame registry, camera pump, a use_camera_stream hook, and a StreamPreview component for rendering live chimeras frames inside a Dioxus desktop app via WebGL2.
docs.rs failed to build dioxus-chimeras-0.2.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

dioxus-chimeras is the Dioxus integration for the chimeras cross-platform camera library. It owns the glue between a chimeras::Camera and a <canvas> element: a loopback HTTP preview server, a WebGL2 renderer, a Registry that shares frames between the camera pump and the webview, and a handful of hooks that expose the stream lifecycle as Dioxus signals.

Every generic primitive (pause/resume pump, single-frame capture, unified CameraSource) lives upstream in chimeras itself so non-Dioxus callers can use it too.

Quick Start

[dependencies]
dioxus = { version = "0.7", features = ["desktop"] }
dioxus-chimeras = "0.2"
chimeras = "0.2"

dioxus-chimeras and chimeras ship in lockstep: both crates share the same major + minor version (0.2.x). Use matching versions in your Cargo.toml.

use chimeras::{CameraSource, PixelFormat, Resolution, StreamConfig};
use dioxus::prelude::*;
use dioxus_chimeras::{
    PreviewScript, StreamPreview, register_with, start_preview_server, use_camera_stream,
};

fn main() {
    let server = start_preview_server().expect("preview server");
    register_with(&server, dioxus::LaunchBuilder::desktop()).launch(App);
}

fn App() -> Element {
    let source = use_signal::<Option<CameraSource>>(|| None);
    let config = StreamConfig {
        resolution: Resolution { width: 1280, height: 720 },
        framerate: 30,
        pixel_format: PixelFormat::Bgra8,
    };
    let stream = use_camera_stream(0, source, config);

    rsx! {
        StreamPreview { id: 0 }
        p { "{stream.status}" }
        button {
            onclick: move |_| stream.active.clone().set(!*stream.active.read()),
            "Toggle preview"
        }
        button {
            onclick: move |_| { let _ = stream.capture_frame.call(()); },
            "Take picture"
        }
        PreviewScript {}
    }
}

register_with injects the preview server's Registry and port into the Dioxus context so every StreamPreview and use_camera_stream call downstream can find them.

What's in the box

Hooks

Hook Returns Purpose
use_camera_stream(id, source, config) UseCameraStream { status, active, capture_frame } Opens the camera, runs the pump, publishes frames to the preview, surfaces lifecycle as signals.
use_devices() UseDevices { devices, ready, refresh } Keeps a Signal<Vec<Device>> populated off a worker thread; refresh on demand.
use_streams() UseStreams { ids, add, remove } Manages a dynamic list of stream ids for multi-stream apps; monotonic, safe as Dioxus keys.

All returned handles are Copy + Clone + PartialEq data structs with public fields (no methods, no hidden state).

Components

Component Purpose
StreamPreview { id } A <canvas> bound to the preview server's /preview/{id}.bin URL; WebGL2-renders the live stream.
PreviewScript {} Injects the WebGL2 driver script once per page. Render it as the last child of your root.

Helpers

Function Purpose
start_preview_server() Binds a loopback HTTP server on an ephemeral port; returns a PreviewServer.
register_with(&server, launch) Injects registry + port + keep-alive into a LaunchBuilder.
get_or_create_sink(&registry, id) Returns the LatestFrame slot for id; used when running your own pump.
remove_sink(&registry, id) Drops the slot for id. Normally handled automatically on unmount.
publish_frame(&sink, frame) Writes a frame into a LatestFrame; used when running your own pump.

Live preview + take-picture

The hook returns both operations on one handle.

let stream = use_camera_stream(id, source, config);

// Pause the pump while the user is on another tab (no per-frame Rust work;
// camera stays open so capture stays fast):
stream.active.clone().set(false);

// Grab a fresh frame whether streaming or paused:
if let Some(frame) = stream.capture_frame.call(()) {
    // save, toast, upload, etc.
}

// Resume streaming:
stream.active.clone().set(true);

capture_frame is sync-blocking on the calling thread until the pump worker replies (typically one frame interval, plus up to 20ms of wake latency if paused). That's fine from an onclick; for rapid back-to-back captures, dispatch from a std::thread::spawn'd worker or a Dioxus spawn task.

Versioning

dioxus-chimeras is released in lockstep with chimeras: both crates share the same major + minor version (for example, chimeras 0.2.x pairs with dioxus-chimeras 0.2.x). Patch numbers can drift between the two; every 0.2.x of dioxus-chimeras will work with any 0.2.y of chimeras.

Features

Feature Default Description
rtsp on Forwards to chimeras/rtsp; enables CameraSource::Rtsp on macOS and Windows.

Disable with dioxus-chimeras = { version = "0.1", default-features = false }.

Source separation

The crate deliberately splits responsibilities:

  • chimeras owns the camera-side primitives: Camera, CameraSource, pump::Pump, etc. No Dioxus dependency.
  • dioxus-chimeras owns the UI-side glue: the preview server, Registry, hooks, and components. Depends on dioxus and chimeras.

If you're integrating chimeras into a non-Dioxus app (a CLI, a Tauri shell, a custom renderer), you do not need this crate. Use chimeras::pump directly for the pause + snapshot pattern.

Demo

The demo/ app in the parent repo exercises the full API: multi-stream grid, per-cell USB or RTSP source, live-preview toggle, take-picture button, add/remove streams, device refresh.

just run           # hot-reloading dev build
just run-release   # release build

Dependency surface

  • dioxus 0.7 with desktop feature
  • chimeras 0.1
  • futures-timer 3 (runtime-agnostic timer; keeps the crate from pinning tokio)
  • bytes 1

License

Licensed under either of

at your option.