framewatch Install

Shippingv0.8.5 on crates.ioMIT or Apache-2.0Rust · Windows API

framewatch

A screen recorder that only writes a frame when something worth keeping happens.

cargo install framewatch --features wgc
cargo install framewatch --features macos
cargo install framewatch --features linux-x11
cargo add framewatch --no-default-features

Add gui for the window picker, or record for narrated capture. On macOS you’ll be asked for Screen Recording permission the first time it runs. Wayland isn’t supported yet.

One session

Five seconds of tests, three frames worth keeping.

If you record a screen continuously, a coding agent drowns in near-identical frames. If you take a screenshot on demand, you miss everything that happened in between. framewatch watches one window and saves a frame only when something meaningful happens.

Terminal — cargo test
$ cargo test
   Compiling framewatch v0.8.5
running 10 tests
test engine_static::static_window_emits_only_initial ... ok
test engine_static::single_change_then_static_settles_once ... ok
test engine_spinner::spinner_collapses_to_busy_then_settled ... ok
test engine_value::volatile_region_is_throttled_not_per_frame ... ok
test engine_auto_spinner::auto_spinner_collapses_to_busy_then_settled ... ok
test engine_auto_spinner::scattered_churn_is_not_an_auto_spinner ... ok
test engine_sustained_motion::sustained_change_produces_periodic_keyframes ... ok
test dedup::identical_busy_end_frame_is_deduped ... ok
test crop::crop_clamps_and_handles_out_of_bounds ... ok
test crop::watch_with_crop_produces_cropped_images ... ok

test result: ok. 10 passed; 0 failed

.framewatch/2026-06-14T06-22-17_Terminal/timeline.jsonl

  1. {"seq":0,"kind":"initial","elapsed_ms":0,"image":"frames/000000_initial.png","note":"Session start."}
  2. {"seq":1,"kind":"busy_start","elapsed_ms":1200,"image":null,"note":"Test runner started (spinner active)."}
  3. {"seq":2,"kind":"busy_end","elapsed_ms":4830,"image":"frames/000002_busy_end.png","coalesced_frames":71,"note":"Spinner stopped after 3.63s; 71 animation frames collapsed."}
  4. {"seq":3,"kind":"settled","elapsed_ms":5180,"image":"frames/000003_settled.png","note":"Settled: test results rendered."}
  1. $ cargo test
    initial 0.00s
  2. $ cargo test
       Compiling framewatch v0.8.5
    running 10 tests
    test engine_static::static_window_emits_only_initial ... ok
    test engine_static::single_change_then_static_settles_once ... ok
    test engine_spinner::spinner_collapses_to_busy_then_settled ... ok
    test engine_value::volatile_region_is_throttled_not_per_frame ... ok
    test engine_auto_spinner::auto_spinner_collapses_to_busy_then_settled ... ok
    test engine_auto_spinner::scattered_churn_is_not_an_auto_spinner ... ok
    test engine_sustained_motion::sustained_change_produces_periodic_keyframes ... ok
    test dedup::identical_busy_end_frame_is_deduped ... ok
    test crop::crop_clamps_and_handles_out_of_bounds ... ok
    test crop::watch_with_crop_produces_cropped_images ... ok
    busy_end 4.83s
  3. $ cargo test
       Compiling framewatch v0.8.5
    running 10 tests
    test engine_static::static_window_emits_only_initial ... ok
    test engine_static::single_change_then_static_settles_once ... ok
    test engine_spinner::spinner_collapses_to_busy_then_settled ... ok
    test engine_value::volatile_region_is_throttled_not_per_frame ... ok
    test engine_auto_spinner::auto_spinner_collapses_to_busy_then_settled ... ok
    test engine_auto_spinner::scattered_churn_is_not_an_auto_spinner ... ok
    test engine_sustained_motion::sustained_change_produces_periodic_keyframes ... ok
    test dedup::identical_busy_end_frame_is_deduped ... ok
    test crop::crop_clamps_and_handles_out_of_bounds ... ok
    test crop::watch_with_crop_produces_cropped_images ... ok
    
    test result: ok. 10 passed; 0 failed
    settled 5.18s
A recorder at 14 fps would keep
73 frames
framewatch keeps
3 frames, 4 events
An animated illustration of a capture session. The events, timings and notes are the “run tests” example from framewatch’s README, and the test names are real tests from its repository.

When it saves a frame

Everything else gets collapsed.

Detection is heuristic and runs on every frame with no model call. You can mark where the spinners and counters live, or let it find small loading animations on its own.

  1. initial

    The first frame

    So the story has a starting point.

  2. settled

    When the window goes quiet

    After a burst of change ends. This is usually the frame that matters.

  3. busy_start · busy_end

    When a spinner starts and stops

    The animation in between collapses into one count, not seventy images.

  4. volatile

    When a counter or log tail moves

    Sampled on a throttle, never once per frame.

  5. manual · mark

    When you ask

    A manual trigger, or a label your app writes into the timeline.

What an agent gets

A folder it can read in order.

Read session.json, stream timeline.jsonl, and open only the images the settled and busy_end events point to. coalesced_frames says how much activity each saved image stands for.

.framewatch/<session_id>/
├── frames/
│   ├── 000000_initial.png
│   ├── 000002_busy_end.png
│   └── 000003_settled.png
├── timeline.jsonl      # one event per line
├── session.json        # target, config, counts
└── README_FOR_AGENT.md # how to read it

Quickstart

Pick a window and watch it.

The window picker needs the gui feature. Without it, point framewatch at a window by title or at a saved config.

# see what can be captured
framewatch windows

# pick a window and mark spinner regions
framewatch gui

# or run headless by title
framewatch watch --title "Visual Studio Code" --out ./.framewatch

Capabilities

What it does.

Anyone whose screen recordings are 99% nothing and 1% the thing they needed.

  1. 01

    Captures when the window settles, when a loading indicator starts or stops, and when busy regions change

  2. 02

    Timestamped metadata with every frame explaining why it was taken

  3. 03

    Published on crates.io, with docs on docs.rs and CI

  4. 04

    A single Rust binary with no runtime dependencies

Specification

What it’s built with, and when.

Pulled from the repository each time this site is built.

State
Shipping
Discipline
Developer tooling
Shape
Installed software
Started
Jun 2026
Last change
Sep 2026
Commits
42
  • Rust
  • Windows API
  • ScreenCaptureKit
  • X11
  • Rust 100%

Next

Install framewatch

It’s on crates.io. Pick the capture backend for your platform. The detection engine is the same on all three.

Windows cargo install framewatch --features wgc
macOS 14+ cargo install framewatch --features macos
Linux (X11) cargo install framewatch --features linux-x11
As a library cargo add framewatch --no-default-features

Add gui for the window picker, or record for narrated capture. On macOS you’ll be asked for Screen Recording permission the first time it runs. Wayland isn’t supported yet.

Questions, or something it doesn’t do yet? Email dmoore@dwmmholdings.com

This site isn't finished. Anything on it may still change, and none of it is binding until the site is live.