visual-cortex 0.9.0

Watch screen regions and receive typed events over async streams when patterns match: OCR, template matching, and pixel conditions on live captures.
//! Watch screen regions and receive typed events over async streams when
//! patterns match — OCR, template matching, and pixel conditions on live
//! captures.
//!
//! # Concepts
//!
//! - A [`Session`] owns one capture stream (a real display/window via
//!   [`Target`], or a scripted [`FakeSource`] for headless use). Each new
//!   frame lands in a latest-frame slot — newest wins, stale frames drop.
//! - A **watcher** ([`Session::watch`]) evaluates one [`Region`] at its own
//!   [`Rate`]: cheap **gates** run first (an implicit pixels-changed gate,
//!   plus any you add), then the main [`Detector`].
//! - **Emission modes** decide when detector output becomes an [`Event`]:
//!
//!   | builder call | fires |
//!   |---|---|
//!   | default / `.on_change()` | [`EventKind::Changed`] on output transitions |
//!   | `.on_threshold(pred)` | [`EventKind::ThresholdCrossed`] when the predicate flips |
//!   | `.template(png, thr)` | [`EventKind::TemplateAppeared`] / `TemplateVanished` |
//!   | `.on_every_match()` | [`EventKind::Matched`] every matching tick |
//!
//! - Heavy detectors (OCR — anything with [`Detector::is_heavy`]) run on the
//!   blocking thread pool; the async scheduler never stalls on inference.
//!
//! # Quickstart (headless)
//!
//! ```
//! use visual_cortex::{Brightness, EventKind, FakeSource, Frame, Rate, Region, Session};
//!
//! # fn main() -> visual_cortex::Result<()> {
//! let rt = tokio::runtime::Runtime::new().expect("tokio runtime");
//! rt.block_on(async {
//!     let session = Session::builder()
//!         .source(FakeSource::new([Frame::solid(64, 64, [200, 200, 200, 255])]))
//!         .build()
//!         .await?;
//!
//!     let mut events = session
//!         .watch("bright")
//!         .region(Region::Full)
//!         .rate(Rate::hz(50.0))
//!         .detector(Brightness)
//!         .subscribe()?;
//!
//!     let ev = events.next().await.expect("stream open");
//!     assert!(matches!(ev.kind, EventKind::Changed { .. }));
//!     Ok(())
//! })
//! # }
//! ```
//!
//! Real capture (macOS): swap the source for
//! `.target(Target::display(0))`. OCR: add the `visual-cortex-ocr-onnx`
//! crate and use `.ocr_text(PaddleOcr::new().await.map_err(Error::engine)?)`.
//! See the [guide](https://github.com/benjamin-small/visual-cortex/blob/main/docs/guide.md)
//! for the full walk-through.
//!
//! # macOS permissions
//!
//! Real capture needs the Screen Recording permission, granted to the
//! *process that runs your binary* (your terminal/IDE). The first request
//! after a fresh grant may still report `PermissionDenied` — macOS applies
//! the grant per process launch, so re-run once after granting.

mod error;
mod event;
mod session;
mod stream;
mod watcher;

pub use error::{Error, Result};
pub use event::{Event, EventKind, ThresholdDirection};
pub use session::{Session, SessionBuilder};
pub use stream::EventStream;
pub use watcher::WatcherBuilder;

// Re-export the building blocks so consumers only need `visual_cortex`.
#[cfg(target_os = "macos")]
pub use visual_cortex_capture::{list_targets, ScapSource, TargetInfo};
pub use visual_cortex_capture::{
    CaptureError, FakeSource, Frame, FrameSource, FrameView, PxRect, Rate, Region, Target,
};
pub use visual_cortex_vision::{
    filters, from_fn, patterns, Brightness, Channel, ColorDominance, ColorMatch, DebugSink,
    DebugStage, Detector, DetectorError, DetectorOutput, FrameDiff, OcrDetector, OcrEngine,
    PngDump, Preprocessor, StabilityMask, TemplateMatcher, TextSpan,
};