visual-cortex 0.6.0

Watch screen regions and receive typed events over async streams when patterns match: OCR, template matching, and pixel conditions on live captures.
//! Template-matching demo against a scripted FakeSource — no real screen needed.
//! Run: cargo run -p visual_cortex --example template_demo

use visual_cortex::{FakeSource, Frame, Rate, Region, Session};

/// 8x8 black/white checkerboard PNG — our stand-in for a buff icon.
fn icon_png() -> Vec<u8> {
    let img = image::ImageBuffer::from_fn(8, 8, |x, y| {
        if (x + y) % 2 == 0 {
            image::Luma([255u8])
        } else {
            image::Luma([0u8])
        }
    });
    let mut out = Vec::new();
    img.write_to(&mut std::io::Cursor::new(&mut out), image::ImageFormat::Png)
        .expect("png encode");
    out
}

fn frame(with_icon: bool) -> Frame {
    Frame::from_fn(160, 90, move |x, y| {
        if with_icon && (76..84).contains(&x) && (41..49).contains(&y) {
            if ((x - 76) + (y - 41)) % 2 == 0 {
                [255, 255, 255, 255]
            } else {
                [0, 0, 0, 255]
            }
        } else {
            [25, 25, 25, 255]
        }
    })
}

#[tokio::main]
async fn main() -> visual_cortex::Result<()> {
    // 1.5s empty, 1s with the icon, then empty forever.
    let mut frames = vec![frame(false); 15];
    frames.extend(std::iter::repeat_with(|| frame(true)).take(10));
    frames.push(frame(false));

    let session = Session::builder()
        .source(FakeSource::new(frames))
        .build()
        .await?;

    let mut icon = session
        .watch("icon")
        .region(Region::Full)
        .rate(Rate::hz(10.0))
        .template(&icon_png(), 0.9)
        .subscribe()?;

    println!("watching for the icon...");
    for _ in 0..2 {
        if let Some(ev) = icon.next().await {
            println!("[{}] {:?}", &*ev.watcher, ev.kind);
        }
    }
    println!("done");
    Ok(())
}