Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 92 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,81 @@
# MatteLoop

MatteLoop is a desktop app for previewing local videos, removing their
backgrounds, and exporting lossless transparent animated WebP files. V1
targets macOS 15+ arm64 and Windows x64; Linux artifacts remain deferred. The
current native qualification covers macOS 15+ arm64 only, and native artifacts
are unsigned.
MatteLoop cuts the background out of a video on your own machine and gives you
back a transparent animated WebP that loops.

![The MatteLoop main window: a source video on the left with a crop rectangle,
the cut-out result on the right over a transparency checkerboard, and the
inspector on the far right](assets/screenshots/main-window.png)

Nothing leaves your computer. The video, the model weights, every intermediate
frame and the finished loop stay on your disk — there is no account, no upload,
and no network call except the one that fetches a model weight the first time
you use it.

## What it is for

You have a clip of a subject — a person, a pet, a product — and you want it
without its background, as a loop you can drop onto any page or into any
composite. MatteLoop is the whole path from that clip to that loop:

- **Open a local video** and scrub to the part you want.
- **Pick the frames** with IN and OUT points on the timeline.
- **Preview a single frame** to judge the cutout before committing to a render.
- **Trim, crop and resize** the finished cut, and watch it loop on screen until
it is right.
- **Render** a lossless transparent animated WebP.

The result is lossless and genuinely transparent — an alpha channel, not a
matte painted onto a colour.

### Judge the loop before you render it

The transform stage works on the cut you already have. Trimming, cropping and
resizing never touch the stored frames; they are a specification applied when
the file is encoded, so you can change your mind as often as you like without
segmenting anything again.

![The inspector's Transform section expanded, showing trim first and last
frame, crop position and size, and resize width, height and
percent](assets/screenshots/transform-expanded.png)

### Choose the model that suits the shot

Different subjects want different weights. MatteLoop ships a catalog of them
and downloads only what you ask for, so a first run costs one model rather than
the whole set. The manager shows what is on disk, what a weight costs, and
which weights are left over from an earlier version of the segmentation
runtime.

![The model manager listing the model catalog with size, cache status and which
model is active, and buttons to download, remove or re-download outdated
weights](assets/screenshots/model-manager.png)

Weights are not bundled with the application. They download on first use and
are cached locally; `birefnet-portrait` alone is about 928 MiB and the complete
catalog is about 6.35 GiB, which is exactly why you fetch them one at a time.

## Built on rembg

The segmentation in MatteLoop is [rembg](https://github.com/danielgatis/rembg)
by Daniel Gatis. The model catalog, the session classes that run each
architecture, and the whole approach to background removal come from that
project, and the weights MatteLoop downloads are its release artifacts, listed
with their checksums in `resources/model-manifest.json`. MatteLoop is the
desktop application around it: the timeline, the preview, the transform stage
and the WebP encoder.

The authors of the individual model architectures behind those weights are
credited in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md), along with every
other component and its licence.

## Getting it

Native builds for macOS 15+ arm64 and Windows x64 are published on the
[releases page](https://github.com/smb/MatteLoop/releases). They are unsigned:
Windows warns through SmartScreen, and macOS needs a right-click Open the first
time. Linux artifacts are deferred, and the current native qualification covers
macOS 15+ arm64 only.

## Run from source

Expand All @@ -15,14 +86,10 @@ uv sync --frozen --all-groups
uv run matteloop
```

The 13 V1 models come from the upstream rembg release artifacts listed in
`resources/model-manifest.json`. They download on first use, are cached
locally, and are not bundled: `birefnet-portrait` is about 928 MiB and the
complete V1 catalog is about 6.35 GiB.

For quick diagnostics, `uv run matteloop --version` avoids Qt and model access;
`uv run matteloop --smoke-test` exercises the local runtime without downloading
weights.
weights; and `uv run matteloop --providers` reports which ONNX Runtime
execution providers the installed runtime actually offers.

Run the checks with:

Expand All @@ -35,6 +102,17 @@ QT_QPA_PLATFORM=offscreen uv run pytest -q
Model weights and generated workspaces are intentionally local and are never
committed.

The screenshots above are generated rather than collected, so a layout change
never leaves them quietly out of date. Regenerate them with:

```sh
QT_QPA_PLATFORM=offscreen uv run python scripts/screenshots.py
```

It decodes `assets/demo/golden-retriever.mp4`, segments it with
`birefnet-general-lite` — which has to be in the local model cache already —
and rewrites `assets/screenshots/`.

New installs use the MatteLoop cache and workspace names. Existing model
weights, compiled provider caches and thumbnails under
`~/Library/Caches/rembggui/` and promoted cuts in an output directory's
Expand All @@ -50,6 +128,9 @@ instructions. See [docs/building.md](docs/building.md) for local and manual
Actions commands, the five inseparable distribution outputs, unsigned-artifact
launch warnings, and current platform qualification status.

Notes for people writing decoder tests live in
[docs/testing-fixtures.md](docs/testing-fixtures.md).

## License

MatteLoop's original source code, documentation, and visual assets are licensed
Expand All @@ -68,12 +149,3 @@ and [LGPL version 3](legal/LGPL-3.0.txt) texts, prominent
[Qt/PySide notice](legal/QT-PYSIDE-LGPL-NOTICE.md), and practical
[replacement instructions](legal/RELINK.md) are kept in the repository and
inside every native app; they do not change MatteLoop's 0BSD license.

### Synthetic fixture rotation

`tests.fixtures.media_factory.make_video(..., rotation=...)` writes a sorted,
versioned adjacent sidecar named `<video>.matteloop.json`. It records the
counter-clockwise presentation rotation as `rotation_ccw`. The locked PyAV 16
wheel cannot author portable MP4 display-matrix metadata, so future synthetic
source-decoder tests must consume this explicit fixture contract instead of
expecting a display matrix in the video container.
Binary file added assets/demo/golden-retriever.mp4
Binary file not shown.
Binary file added assets/screenshots/main-window.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/model-manager.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/transform-expanded.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions docs/testing-fixtures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Test fixtures

## Synthetic fixture rotation

`tests.fixtures.media_factory.make_video(..., rotation=...)` writes a sorted,
versioned adjacent sidecar named `<video>.matteloop.json`. It records the
counter-clockwise presentation rotation as `rotation_ccw`. The locked PyAV 16
wheel cannot author portable MP4 display-matrix metadata, so future synthetic
source-decoder tests must consume this explicit fixture contract instead of
expecting a display matrix in the video container.
Loading
Loading