Frame-exact clip exporter for movies & series. Search a line, mark in/out, export MP4. Windows & macOS.
Kotlin
4
3,139 commits
updated Oct 4, 2026
A desktop clipping tool for movies and series.
Find the moment, mark in and out, export a shareable MP4.
StreamCut is in alpha and built for its author. Releases are unsigned (macOS and Windows), and breaking changes land without notice — stored clips, settings and compatibility can all change between builds. Don't rely on it for anything you can't redo.
StreamCut is a fork of Nuvio Desktop turned into a clip-export tool. Upstream is a media client that happens to play video; StreamCut makes the clip the subject and the player the instrument.
What it does differently:
I and O bring the in/out point to the playhead instead of
moving the playhead to a handle, so you never lose the frame you just found. Fine
adjustments pause first.A and export them as a queue.Upstream's viewing features (next-episode cards, intro skip, parental guides, the app-icon
picker and so on) are gated, not deleted — they sit behind
AppFeaturePolicy.viewingChromeEnabled, which is false on desktop, so merges from
NuvioMedia/NuvioDesktop keep applying cleanly.
Browsing, catalogs and stream resolution still come from user-installed addons and user-provided sources, exactly as upstream.
| Key | Action |
|---|---|
I / O | Mark in / out at the playhead |
, / . | Step one frame back / forward (pauses first) |
← / → on a focused handle | Move that point one frame (Shift: one second) |
A | Add the current range to the draft |
X | Export |
R | Loop-preview the range |
B | Show / hide the filmstrip |
Backspace | Undo: the current draft first, then set-aside ranges newest-first |
/ or Cmd/Ctrl + F | Subtitle phrase search |
? | Show every shortcut |
With unexported ranges, the first Esc only warns; press it again to leave the player.
Download the latest build from Releases.
Published builds:
macOS, Apple Silicon (.dmg). Ad-hoc signed and not notarized, so Gatekeeper blocks
it on first launch. Approve it under System Settings → Privacy & Security → "Open Anyway",
or strip the quarantine flag:
xattr -dr com.apple.quarantine /Applications/StreamCut.app
ffmpeg is bundled, so clipping works without installing anything else.
Windows x64 (.msi). Not signed, so SmartScreen shows "Windows protected your PC":
click More info, then Run anyway. The installer bundles ffmpeg, so clipping works
without installing anything else.
Linux packaging is inherited from upstream and untested here; build from source if you need it.
Installed builds check this repository's releases and offer updates in the app.
Your data stays on your computer unless you sign in to sync; see the privacy policy.
prepareMacosFfmpeg; -Pnuvio.macos.ffmpeg.dir swaps in a local folder). On Linux they
must be installed: the build must include libass (subtitle burn-in) and libzimg
(zscale, for HDR tonemapping). Homebrew's ffmpeg has neither; jellyfin-ffmpeg does.
StreamCut probes each candidate binary for those filters and picks the first that has
both; NUVIO_FFMPEG_PATH overrides the search.git clone https://github.com/julianbou/streamcut.git
cd streamcut
local.properties is gitignored, and Gradle fails configuration without it. Blank values
are fine — only sign-in and cross-device sync depend on them:
NUVIO_SUPABASE_URL=
NUVIO_SUPABASE_ANON_KEY=
To run the backend yourself, point those at your own Supabase project and apply
supabase/schema.sql (tables, RPCs, RLS and triggers) in its SQL
editor, then enable email auth. Clipping, playback and the local library all work without it.
Run from source:
export JAVA_HOME=/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
./gradlew :composeApp:run
On Windows PowerShell:
.\gradlew.bat :composeApp:run
Compile-only check (~2 min cold):
./gradlew :composeApp:compileKotlinDesktop
Tests:
./gradlew :composeApp:desktopTest
Package a release for the current host:
./gradlew :composeApp:packageReleaseDmg -Pcompose.desktop.packaging.checkJdkVendor=false \
--no-configuration-cache --no-daemon
The DMG lands in composeApp/build/compose/release-dmgs/. Other hosts:
# Windows
./gradlew :composeApp:packageReleaseMsi --rerun-tasks
# Linux
./gradlew :composeApp:packageReleaseDeb
# macOS, both architectures (needs an x86_64 JDK for the Intel slice)
./scripts/build-macos-release-dmgs.sh --package-only
The Windows MSI is built on GitHub Actions: run the Windows build workflow
(.github/workflows/windows-build.yml) and download the MSI from the run's artifacts. It
fetches a pinned ffmpeg build and bundles it; a local Windows build bundles one only when
-Pnuvio.windows.ffmpeg.dir points at a folder with ffmpeg.exe and ffprobe.exe.
.github/workflows/desktop-release.yml is upstream's and cannot run in this repo — it
requires Apple signing certificates, notarytool credentials, a Sentry DSN and a base64
local.properties with third-party API keys. macOS releases are built locally.
Upstream releases are merged, never cherry-picked, with scripts/upstream/sync-upstream.sh
(status, start <tag>, verify). It resets the files StreamCut owns, re-deletes what
StreamCut removed, re-applies the branding, and checks that no fork decision was undone.
The sync-upstream Claude skill in .claude/skills/ drives the whole process.
composeApp/src/commonMain/ — shared UI, features and repositories, including
features/clip/ (the clip library, models, repository and filename templating).composeApp/src/desktopMain/kotlin/.../features/clip/ — the export path:
ClipExtractor.desktop.kt (ffmpeg graph: tonemap → crop → subtitles) and
ClipStrip.desktop.kt (filmstrip extraction and caching).composeApp/src/desktopMain/resources/player-ui/ — the player chrome, rendered in a
webview. Clipper code is kept in its own clip-controls.{js,css} and
clip-search.{js,css} to stay off upstream's merge surface.composeApp/src/*/kotlin/com/nuvio/app/core/build/AppFeaturePolicy* — one expect and six
per-target actuals; this is what gates viewing chrome.composeApp/src/commonMain/composeResources/values/clip_strings.xml — clipper strings,
separate from upstream's strings.xml for the same reason.branding/make_brand.py — regenerates every icon, launch mark and wordmark from
branding/logo-source.jpg.composeApp/Configuration/DesktopVersion.properties — release version and build code.composeApp/Configuration/UpstreamVersion.properties — the Nuvio Desktop release last
merged, shown in About.fork.* properties in
gradle.properties.Android and iOS source sets are still present, but clipping is desktop-only and neither mobile target is built or verified here.
VERSION_NAME=0.1.0-alpha
VERSION_CODE=1
Use the helper, and keep the bump as the last commit before the tag. Tags carry no v
prefix — the tag is the version verbatim.
./scripts/set-version.sh --desktop 0.1.1-alpha --desktop-code 2
./scripts/set-version.sh --show
StreamCut is a client-side interface for browsing metadata and playing media provided by user-installed addons and/or user-provided sources. It does not host, store, or distribute any media, and it is not affiliated with any addon, catalog, source, or content provider.
Clipping is intended for content you own or are otherwise authorized to use, and for uses permitted by applicable law. What you export is your responsibility.
Upstream's Legal & Disclaimer page covers the inherited addon and DMCA policy.
GPL-3.0, inherited from Nuvio Desktop. See LICENSE.
Kotlin
88.7%
C++
2.1%
JavaScript
1.6%
C
1.3%
CSS
1.3%
Objective-C++
1.1%
Swift
1.1%
Frame-exact clip exporter for movies & series. Search a line, mark in/out, export MP4. Windows & macOS.
Kotlin
4
3,139 commits
updated Oct 4, 2026
A desktop clipping tool for movies and series.
Find the moment, mark in and out, export a shareable MP4.
StreamCut is in alpha and built for its author. Releases are unsigned (macOS and Windows), and breaking changes land without notice — stored clips, settings and compatibility can all change between builds. Don't rely on it for anything you can't redo.
StreamCut is a fork of Nuvio Desktop turned into a clip-export tool. Upstream is a media client that happens to play video; StreamCut makes the clip the subject and the player the instrument.
What it does differently:
I and O bring the in/out point to the playhead instead of
moving the playhead to a handle, so you never lose the frame you just found. Fine
adjustments pause first.A and export them as a queue.Upstream's viewing features (next-episode cards, intro skip, parental guides, the app-icon
picker and so on) are gated, not deleted — they sit behind
AppFeaturePolicy.viewingChromeEnabled, which is false on desktop, so merges from
NuvioMedia/NuvioDesktop keep applying cleanly.
Browsing, catalogs and stream resolution still come from user-installed addons and user-provided sources, exactly as upstream.
| Key | Action |
|---|---|
I / O | Mark in / out at the playhead |
, / . | Step one frame back / forward (pauses first) |
← / → on a focused handle | Move that point one frame (Shift: one second) |
A | Add the current range to the draft |
X | Export |
R | Loop-preview the range |
B | Show / hide the filmstrip |
Backspace | Undo: the current draft first, then set-aside ranges newest-first |
/ or Cmd/Ctrl + F | Subtitle phrase search |
? | Show every shortcut |
With unexported ranges, the first Esc only warns; press it again to leave the player.
Download the latest build from Releases.
Published builds:
macOS, Apple Silicon (.dmg). Ad-hoc signed and not notarized, so Gatekeeper blocks
it on first launch. Approve it under System Settings → Privacy & Security → "Open Anyway",
or strip the quarantine flag:
xattr -dr com.apple.quarantine /Applications/StreamCut.app
ffmpeg is bundled, so clipping works without installing anything else.
Windows x64 (.msi). Not signed, so SmartScreen shows "Windows protected your PC":
click More info, then Run anyway. The installer bundles ffmpeg, so clipping works
without installing anything else.
Linux packaging is inherited from upstream and untested here; build from source if you need it.
Installed builds check this repository's releases and offer updates in the app.
Your data stays on your computer unless you sign in to sync; see the privacy policy.
prepareMacosFfmpeg; -Pnuvio.macos.ffmpeg.dir swaps in a local folder). On Linux they
must be installed: the build must include libass (subtitle burn-in) and libzimg
(zscale, for HDR tonemapping). Homebrew's ffmpeg has neither; jellyfin-ffmpeg does.
StreamCut probes each candidate binary for those filters and picks the first that has
both; NUVIO_FFMPEG_PATH overrides the search.git clone https://github.com/julianbou/streamcut.git
cd streamcut
local.properties is gitignored, and Gradle fails configuration without it. Blank values
are fine — only sign-in and cross-device sync depend on them:
NUVIO_SUPABASE_URL=
NUVIO_SUPABASE_ANON_KEY=
To run the backend yourself, point those at your own Supabase project and apply
supabase/schema.sql (tables, RPCs, RLS and triggers) in its SQL
editor, then enable email auth. Clipping, playback and the local library all work without it.
Run from source:
export JAVA_HOME=/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
./gradlew :composeApp:run
On Windows PowerShell:
.\gradlew.bat :composeApp:run
Compile-only check (~2 min cold):
./gradlew :composeApp:compileKotlinDesktop
Tests:
./gradlew :composeApp:desktopTest
Package a release for the current host:
./gradlew :composeApp:packageReleaseDmg -Pcompose.desktop.packaging.checkJdkVendor=false \
--no-configuration-cache --no-daemon
The DMG lands in composeApp/build/compose/release-dmgs/. Other hosts:
# Windows
./gradlew :composeApp:packageReleaseMsi --rerun-tasks
# Linux
./gradlew :composeApp:packageReleaseDeb
# macOS, both architectures (needs an x86_64 JDK for the Intel slice)
./scripts/build-macos-release-dmgs.sh --package-only
The Windows MSI is built on GitHub Actions: run the Windows build workflow
(.github/workflows/windows-build.yml) and download the MSI from the run's artifacts. It
fetches a pinned ffmpeg build and bundles it; a local Windows build bundles one only when
-Pnuvio.windows.ffmpeg.dir points at a folder with ffmpeg.exe and ffprobe.exe.
.github/workflows/desktop-release.yml is upstream's and cannot run in this repo — it
requires Apple signing certificates, notarytool credentials, a Sentry DSN and a base64
local.properties with third-party API keys. macOS releases are built locally.
Upstream releases are merged, never cherry-picked, with scripts/upstream/sync-upstream.sh
(status, start <tag>, verify). It resets the files StreamCut owns, re-deletes what
StreamCut removed, re-applies the branding, and checks that no fork decision was undone.
The sync-upstream Claude skill in .claude/skills/ drives the whole process.
composeApp/src/commonMain/ — shared UI, features and repositories, including
features/clip/ (the clip library, models, repository and filename templating).composeApp/src/desktopMain/kotlin/.../features/clip/ — the export path:
ClipExtractor.desktop.kt (ffmpeg graph: tonemap → crop → subtitles) and
ClipStrip.desktop.kt (filmstrip extraction and caching).composeApp/src/desktopMain/resources/player-ui/ — the player chrome, rendered in a
webview. Clipper code is kept in its own clip-controls.{js,css} and
clip-search.{js,css} to stay off upstream's merge surface.composeApp/src/*/kotlin/com/nuvio/app/core/build/AppFeaturePolicy* — one expect and six
per-target actuals; this is what gates viewing chrome.composeApp/src/commonMain/composeResources/values/clip_strings.xml — clipper strings,
separate from upstream's strings.xml for the same reason.branding/make_brand.py — regenerates every icon, launch mark and wordmark from
branding/logo-source.jpg.composeApp/Configuration/DesktopVersion.properties — release version and build code.composeApp/Configuration/UpstreamVersion.properties — the Nuvio Desktop release last
merged, shown in About.fork.* properties in
gradle.properties.Android and iOS source sets are still present, but clipping is desktop-only and neither mobile target is built or verified here.
VERSION_NAME=0.1.0-alpha
VERSION_CODE=1
Use the helper, and keep the bump as the last commit before the tag. Tags carry no v
prefix — the tag is the version verbatim.
./scripts/set-version.sh --desktop 0.1.1-alpha --desktop-code 2
./scripts/set-version.sh --show
StreamCut is a client-side interface for browsing metadata and playing media provided by user-installed addons and/or user-provided sources. It does not host, store, or distribute any media, and it is not affiliated with any addon, catalog, source, or content provider.
Clipping is intended for content you own or are otherwise authorized to use, and for uses permitted by applicable law. What you export is your responsibility.
Upstream's Legal & Disclaimer page covers the inherited addon and DMCA policy.
GPL-3.0, inherited from Nuvio Desktop. See LICENSE.
Kotlin
88.7%
C++
2.1%
JavaScript
1.6%
C
1.3%
CSS
1.3%
Objective-C++
1.1%
Swift
1.1%