Skip to content

veecore/iced_live_cast

Repository files navigation

iced_live_cast

crates.io docs.rs CI

Blazing-fast cross-platform monitor casting for iced.

iced_live_cast is the crate you reach for when you want a live preview in an iced app without routing frames through your application's message loop.

It gives you three layers:

  • CastView for actively rendering a live handle inside iced
  • CastHandle for callers that already own frames and want to push them
  • MonitorCapture for OS-backed monitor capture on macOS and Windows

The hot path stays small:

  • sources push frames into a shared handle
  • the widget owns redraw scheduling
  • the renderer reuses one GPU texture per handle instead of rebuilding per frame

Why this crate exists

If you already have frames, use CastHandle.

If you want the OS to produce frames for you, use MonitorCapture.

If you just want something on screen, use CastView.

That is the whole pitch.

What you get

  • an active iced widget with redraw scheduling
  • a reusable GPU texture per live handle
  • typed source markers and typed runtime errors
  • a BGRA upload path tuned for monitor capture
  • macOS support through screencapturekit
  • Windows support through windows-capture

Quick start

use iced::widget::container;
use iced::{Element, Length};
use iced_live_cast::{CastView, Monitor, MonitorCapture};

fn preview() -> Result<Element<'static, ()>, Box<dyn std::error::Error>> {
    let monitor = Monitor::all()?
        .into_iter()
        .next()
        .ok_or("no monitors are currently available")?;
    let capture = MonitorCapture::start(monitor)?;

    Ok(container(
        CastView::new(&capture)
            .width(Length::Fill)
            .height(400),
    )
    .into())
}

Add the crate normally:

iced_live_cast = "0.1.0"

For the full story, run:

cargo run --example basic

By default, the example uses the first available monitor.

If you want, you can still pass an argument and the example will treat it as either a real monitor id or a one-based monitor index:

cargo run --example basic
cargo run --example basic -- 2

That example uses the built-in monitor source.

Manual sources

If your frames come from somewhere other than the built-in monitor source, use CastHandle directly:

use iced_live_cast::{CastHandle, Frame};

let handle = CastHandle::new();
let frame = Frame::from_bgra(1280, 720, vec![0; 1280 * 720 * 4])?;
handle.present(frame);

You can then render the same handle with CastView::new(&handle).

Frame::to_handle() is available by default as a bridge into iced::widget::image.

If you want a full running example for that path, run:

cargo run --example manual_push

And here is that manual source path running for real:

Manual push example

Benchmarks

Quick local numbers from a short Criterion run on Apple silicon with 1080p frames:

Benchmark Size Result
frame_construction/from_rgba/packed 1080p about 1.52 ms
frame_construction/from_bgra/packed 1080p about 475 µs
frame_processing/rgba_pixels/packed_bgra 1080p about 328 µs
frame_handles/frame_to_handle/full_frame 1080p about 370 µs
cast_handle_updates/present_frame/prebuilt_bgra 1080p about 19 ns
cast_handle_updates/construct_and_present/bgra 1080p about 469 µs

The GPU upload bench is included too, but treat it as a renderer baseline rather than a full end-to-end crate benchmark. It measures the same wgpu upload shape the renderer uses, not the whole widget pipeline.

Platform notes

  • macOS requires Screen Recording permission from the OS before monitor capture can start.
  • The crate uses screencapturekit on macOS and windows-capture on Windows.
  • Linux support is not implemented yet.

Development

Useful checks from the workspace root:

cargo check --lib --examples --benches
cargo test --lib
cargo bench --no-run

About

Blazing-fast cross-platform display casting widgets and sources for iced

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages