Skip to content

Cut a clip: a video editor (quick trim + timeline editor), Join videos, window zoom - #326

Closed
flexeykinDev wants to merge 11 commits into
KnifeLemon:mainfrom
flexeykinDev:feature/clip-cut
Closed

flexeykinDev wants to merge 11 commits into
KnifeLemon:mainfrom
flexeykinDev:feature/clip-cut

Conversation

@flexeykinDev

@flexeykinDev flexeykinDev commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What does this change?

Adds two tool presets on the back of the video donut (Tab / wheel), and a window zoom:

  1. Cut a clip: makes a clip out of a longer video without leaving Filee. It opens in a quick trim mode (the window described in the first version of this PR) and has an Editor mode for a full timeline edit.
  2. Join videos: joins the dropped videos into one file, by copying when they share a format.
  3. Window zoom: Ctrl + wheel, Ctrl + / Ctrl −, Ctrl + 0 in every window.

Settings schema 34 adds both presets to existing libraries (33: Cut a clip, 34: Join videos).

Quick trim

  • The frame at the start, end or playhead is shown large. An overview of the whole video sits above a sequence of V1 (picture), A1 (its sound) and A2 (music).
  • Handles, 15 / 30 / 60 s buttons, and Z to zoom in on the clip.
  • Space plays the clip as it will be written, with sound. Frames come from FFmpeg as raw BGRA over a pipe; the sound plays through ffplay from Filee's own FFmpeg download.
  • Blade (C), Delete (leaves a gap with a Close gap button) and Shift+Delete (closes up). Dragging a piece's edge takes back or cuts away.
  • Per-piece volume, mute and speed (0.25×–4×, pitch kept). Multi-select, magnet (M), Remove silence (silencedetect), fades, undo and redo.
  • One plain stretch is copied without re-encoding (Fast, no re-encoding); anything else becomes one filter graph.

Editor

The Editor button turns the window into a CapCut-like editor. The same clip carries over, and going back asks first when the edit has more than a quick trim can show.

  • Files panel: videos, sounds and pictures, dropped there or straight onto the timeline. Right-click a file for On the timeline, Reveal in folder or Remove from project; removing a file also removes everything of it on the timeline, and undo brings both back.
  • Tracks:
    • T: texts;
    • I: pictures over the video;
    • V1: the video;
    • A1: its sound;
    • A2, A3…: sounds from other files, up to 8 tracks.
      New sounds go in a row after the last one. Sounds drag in time and between tracks; their edges trim them, and a line sets each one's volume.
  • Frame: Video, 16:9, 9:16, 1:1 or 4:5. Video of another shape is shown whole with bars, cropped, or whole on a blurred copy of itself. In the preview, the part, the pictures and the texts are moved, sized by a corner and turned by a round handle that snaps to 0°, 90°, and so on.
  • Texts: title, caption or label style; any system font; colour, size, opacity, rotation and time shown.
  • Pictures: size, opacity, rotation and time shown.
  • Parts:
    • transitions (crossfade, through black, sound only);
    • freeze frame, reverse, a speed ramp, turning by 90°;
    • split, cut with or without a gap, copy, paste, duplicate.
  • Clip sound: level loudness (EBU R128 loudnorm), reduce noise (afftdn), lift quiet speech (acompressor), duck the music under speech (sidechaincompress).
  • Right-click menus on every timeline item, on gaps, on the preview and on files. All edits are undoable.
  • Keys: J/K/L, , . for one frame, Home/End, T (text), F (fullscreen), E (export), Alt + wheel (timeline zoom).
  • The layout adapts to narrow windows.

Export (E) opens its own window:

  • presets: YouTube 1080p, Shorts / TikTok 9:16, Discord ≤ 10 MB, Telegram ≤ 50 MB, or custom;
  • format (H.264, HEVC, WebM, GIF), resolution, fps and quality;
  • an optional size limit: it becomes a bitrate, and the encode is retried at 92 % if the file came out over the limit;
  • each highlight as its own file.

The graphics card encodes (NVENC, QSV, AMF, VideoToolbox) when HardwareProbe finds one, with a software fallback.

How the clip is written. It is still one ordinary conversion: the progress shows in the toast, it can be cancelled, it follows the output rules and goes into the history. MediaEncoding.EditorGraphOf builds one graph:

  • each part is its own input (-ss/-t);
  • reverse runs in 2 s chunks; a speed ramp is 10 steps;
  • fps/format/tpad/trim per part, then settb=AVTB before xfade / acrossfade;
  • placement uses crop/scale/pad, or an overlay on the blurred copy; turned parts use rotate;
  • each sound gets atrim/volume/afade/adelay, then amix.

Texts and pictures are drawn by the same code as the preview (EditorDrawing) into transparent full-frame PNGs and overlaid with enable=between. The written clip therefore matches the preview with any font, and nothing depends on drawtext or fontconfig. A text without a drawn layer still falls back to drawtext.

Join videos

Drop several videos on the preset. A list opens where you can reorder them and pick how to fill the frame when the sizes differ. Videos of one format are joined with the concat demuxer and -c copy in seconds; any others go through the editor's graph. Open in editor opens them in the editor instead, to add transitions.

Structure

  • Core: ClipCutter (quick trim), ClipProject (editor operations with undo over ClipEdit snapshots), ClipCanvas (frame maths). Everything is unit-tested without a window.
  • Engines: MediaEncoding.Editor*, FfmpegConverter.Editor, ClipPreview.
  • App: the timeline and the preview are custom-drawn controls (EditorTimeline, EditorPreview) behind small host interfaces (IEditorTimelineHost, IEditorPreviewHost). The view model holds the state.

Keeping it light:

  • media bitmaps are released when the editor closes;
  • the probe cache is capped;
  • layer folders older than a day are removed from %TEMP%\Filee;
  • FFmpeg for previews runs below normal priority.

How was it tested?

  • dotnet format --verify-no-changes
  • dotnet test. New tests:
    • Core:
      • ClipToolTests (15) and ClipCutterTests (21);
      • ClipProjectTests (19): parts, gaps, transitions, freeze, reverse, ramps, texts, pictures, sounds in a row and on tracks, removing a file, music moved into sounds, placement and rotation, undo and redo, the schema 34 migration.
    • Engines:
      • ClipTests (32);
      • EditorClipTests (12): the graph's command lines, plus real FFmpeg runs when FFmpeg is installed — videos of different shapes into one 9:16 clip, turned and moved parts with picture layers and several sounds, join by copy, highlights as separate files under a size limit, GIF, and the editor's preview frames.
    • App:
      • ClipWindowTests (27);
      • ClipEditorTests (12): adding files, sound tracks, moving, sizing and turning, export layers, keys, properties, the export flow, Join videos into the editor, window zoom;
      • RenderTests: the quick trim, the editor (with a picture and a text), the export window, the narrow layout and the Join window in en, ru, ja, hi and ar, light and dark.
  • Tried in the app (Windows 11): a GPU export of a 9:16 clip from two videos, with texts, a picture and music under a 10 MB limit (NVENC: 21 s of clip encoded in 4.8 s, 9.3 MB); frames checked.
  • Linux (x64, arm64) and macOS (arm64, x64) packages built, with all tests run on those systems (the fork's "Linux and macOS packages" workflow).

Screenshots (UI changes)

tests/Filee.App.Tests/bin/<config>/net10.0/screenshots/: clip-*.png (quick trim), editor-*.png, editor-export-*.png, editor-narrow-*.png, join-*.png.

Checklist

  • New UI strings are in all src/Filee.App/Assets/i18n/*.json files, pt-BR included. Russian is written natively; please check the others.
  • No new third-party code or binaries. ffplay ships in the FFmpeg build Filee already downloads, and the icons are Material Design Icons paths, like the existing ones.
  • This is large. The quick trim, the editor and Join videos are separate layers, so they can go in as separate PRs if that is easier to review.

flexeykinDev and others added 2 commits October 21, 2026 06:45
… own

A new tool preset, "Cut a clip", first on the back of the video donut (settings
schema 33 adds it to existing libraries). Dropping videos on it opens a window
like the crop overlay: the frame at the active handle large, start / length /
end, a timeline of 16 pictures with two handles (drag a handle, drag the clip,
or press beside it), 15 / 30 / 60 s from the start, and keys (arrows move the
handle by 0.1 s, Shift by 1 s, S / E pick it, Enter saves, Esc closes).

Saving starts an ordinary conversion of that part (ClipTool.ConversionOf), so
the toast shows its progress and cancels it, the output rules name it
<name>_clip next to the video, and the history keeps it. The clip is written in
the video's own format when FFmpeg writes it, else MP4:
- Fast (default, remembered in the tool): -ss/-to before -i and -c copy, cut at
  the key frame before the start; a copy the container can't take is encoded.
- Exact: encoded with the preset's video options, sound included (copied sound
  would start with the packets before the seek point, a second early).

Tests: range clamping and time formatting, the conversion and the schema 33
migration (Core), FFmpeg command lines and real clips through the job queue
(Engines), the window's handles, keys, quick lengths, saving and several files,
and its screenshots in light, dark and right to left (App).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ades

The clip window plays the clip as it will be written, with its sound (Space):
the pictures come from FFmpeg as raw frames, the sound through ffplay, which
Filee's FFmpeg download has (without it the preview is silent).

Between the start and end handles the clip can now be cut into pieces:
- the blade (C) cuts at the playhead (a ruler over the timeline, a click in
  the clip, or P and the arrow keys);
- Delete cuts a piece out: with the magnet on (M) the rest closes up and
  handles snap to cuts and the playhead; off, a pause of black and silence
  stays. "Close gaps" closes the pauses, Delete again puts a piece back;
- each piece has its own volume (0-200 %) and speed (0.25x-4x, the sound keeps
  its pitch), shown on the timeline with the loudness of the sound;
- "Remove silence" cuts out what FFmpeg's silencedetect finds (one undo);
- fade in and out over a second, Ctrl+Z / Ctrl+Y undo and redo, Z zooms the
  timeline in on the clip.

ClipCutter (Core) does the editing without the window; ClipEdit is what the
conversion gets. One stretch as recorded still copies as before; anything else
is one FFmpeg filter graph (trim, setpts / atempo, volume, pauses, concat,
fades) encoded with the preset's options, reading the video once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@flexeykinDev flexeykinDev changed the title Cut a clip: a part of a video, chosen on a timeline, as a file of its own Cut a clip: a small video editor with sound, blade, volume, speed and fades Oct 21, 2026
flexeykinDev and others added 3 commits October 21, 2026 09:03
… took)

The preview's sound process got the clip's whole graph, pictures included; FFmpeg
refuses a graph with an output nothing maps, so the player got no sound. The
sound now has a graph of its own. Tests decode it for real and play it through
ffplay at volume 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	src/Filee.Engines/Media/MediaEncoding.cs
…g, music

The clip window now shows the clip as it plays, as in an editor, under the
overview of the whole video:
- V1 the pictures, A1 the video's own sound, A2 music from another file;
- Delete cuts a piece out and leaves a gap with a "Close gap" button on it
  (Shift+Delete closes up at once); Delete on a gap closes it;
- a piece's edge is dragged to trim it: outwards it takes back what was cut
  next to it, inwards it cuts that much out (one undo step per drag);
- A1: a volume line per piece to drag, Delete mutes the piece's sound while
  its picture plays (also a mute button);
- A2: "Music" puts the sound of any file under the clip, dragged along, with
  its own volume line, faded at its ends and mixed under the clip's sound
  (amix); playing and saving include it;
- the magnet only snaps now (playhead, edges, music to cuts and playhead).

The sequence takes its own pictures and loudness of the clip's stretch once
its ends rest. Cursors are made once, the sequence's layout is worked out once
per change, and FFmpeg for the window's pictures and sound runs below normal
priority, so the window stays smooth while they are taken.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@flexeykinDev flexeykinDev changed the title Cut a clip: a small video editor with sound, blade, volume, speed and fades Cut a clip: a small video editor (sequence with V1/A1/A2, sound preview, blade, music) Oct 21, 2026
… while starting

- Several pieces at once: drag across them in the sequence, Ctrl+click adds or
  takes one out, Shift+click selects a run, Ctrl+A all, Esc back to one. Delete,
  the volume, the speed and mute apply to every selected piece as one undo step
  (ClipCutter.Batch).
- Space and Enter are the window's own: its buttons don't keep the keyboard
  focus, and the keys' key-up is taken too, so Space no longer presses the
  button clicked last (maximize, a fade, the magnet).
- Playing shows "Preparing..." until the first picture, and the preview's clock
  starts with that picture: counted from before, FFmpeg's start-up made the
  first pictures late and skipped, so the start looked frozen.
- Finding silence and reading music say so the same way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KnifeLemon KnifeLemon added the feature New features label Oct 21, 2026
@KnifeLemon KnifeLemon self-assigned this Oct 21, 2026
@KnifeLemon

Copy link
Copy Markdown
Owner

Thank you @flexeykinDev, this is an impressive piece of work!

2.0.0 is being released right now, so we'll look at it after the release.
Because it's a big step for Filee (from converting files to editing a clip on a timeline), we'd like to agree on the scope first: which parts belong in Filee's first version of this (for example the trim with 15/30/60 s and the preview) and which could come later as follow-ups.

We'll come back to you with that soon.

…y system

Filee 2.0.0 brought pt-BR; it gets every string of the clip window. The music
tests used a Windows path, which Linux and macOS don't split into a file name.
'Close gaps' no longer mentions the magnet (Delete leaves the gaps now).
The clip window gets a second mode, an editor in Filee's style:
- Files (videos, sounds, pictures; dropped files fly in), the preview in the
  clip's frame (16:9, 9:16, 1:1, 4:5; bars, crop or a blurred fill), the
  player (J/K/L, frame steps, full screen), the selection's properties and
  right-click menus, tools and a T / I / V1 / A1 / A2... timeline.
- Parts from several videos in any order: blade, gaps, moving, copying,
  trimming by their edges, stills, playing backwards, smooth speed changes,
  transitions (crossfade, through black, sound only).
- The part's picture, texts (styles, fonts, see-through) and pictures over
  the video are moved, sized and turned with handles in the preview.
- Sounds from other files in a row or on several tracks; sound cleanup
  (loudness, ducking, noise, quiet speech).
- Export window: presets (YouTube, Shorts/TikTok, Discord, Telegram), size,
  format (H.264, H.265, WebM, GIF), fps, quality, size limit, the graphics
  card with a software fallback, each part as its own file.
FFmpeg writes an editor clip through one filter graph (texts and pictures
are drawn by the app as the preview draws them and laid over the video);
whole videos of one format are joined by copying.

Join videos on the video donut: an order window, then one conversion or
the editor. Ctrl + wheel / Ctrl +/- / Ctrl+0 make Filee's windows larger
or smaller. Settings schema 34 adds the Join tool. Strings in all ten
languages; model, FFmpeg and UI tests.
@flexeykinDev flexeykinDev changed the title Cut a clip: a small video editor (sequence with V1/A1/A2, sound preview, blade, music) Cut a clip: a video editor (quick trim + timeline editor), Join videos, window zoom Oct 21, 2026

@KnifeLemon KnifeLemon left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @flexeykinDev, this is a remarkable piece of work, and it is clearly built with care: Core holds the clip logic without any UI code, the clip is written as an ordinary conversion (toast, cancel, output rules, history all just work), FFmpeg gets its arguments through ArgumentList, texts reach drawtext only through textfile with expansion=none (or as drawn PNG layers), colours are validated, and every output and temp folder that gets deleted is one the code created itself. I built it locally (Release, dotnet format clean) and ran the Core, Engines (with real FFmpeg) and App clip tests: 97 + 60 + 96 passed. The translations are real in all ten languages.

As we said before the release, we’d like to agree on the scope before merging something this large (+21k lines), and you already offered to split it. Let’s do that:

  1. First PR: the quick trim “Cut a clip” (the clip window with the 15/30/60 s buttons, preview, blade, delete/close gap, per-piece volume/speed, fades, undo, the tool-clip preset and its migration). This is the part we’d like to ship first.
  2. Join videos needs a decision first: #349 adds “Merge videos” (merge-videos) on the same video donut back face. Both PRs fill that face to its 12 slices, so a new library can’t hold both, and two “join” presets would confuse users. We’ll come back with which one we keep (or how to combine them) before you open this part.
  3. The editor mode (timeline, texts, pictures, transitions, export window) as a follow-up PR on top of the quick trim.
  4. Window zoom (Ctrl + wheel / Ctrl ± / Ctrl+0) as its own small PR: it changes every window and has no visible setting to undo it, so we’d like to discuss it separately.

A few things for each part:

  • Settings schema: #349, #351 and #381 also use schema 33. Whichever merges first takes 33, so please number your migration after whatever main has when you open the split PR (we can renumber it ourselves when we merge, too). Small nit: the 34 comment should read // v34: like the others.
  • Docs: please add a section to docs/ARCHITECTURE.md next to “Crop overlay” (clip window, ClipTool.ConversionOf, how the graph is built), and note in docs/ENGINES.md that the preview plays sound through ffplay when it sits next to Filee’s FFmpeg.
  • EditorLayers.CleanUp stops at the first folder it can’t delete; a try/catch per folder would keep cleaning the rest.

Thanks again, this is great work and we’re looking forward to getting the quick trim in.

@KnifeLemon

Copy link
Copy Markdown
Owner

Following up on point 2 of the review, @flexeykinDev: we've decided to keep #349's "Merge videos" as the join tool, so please leave "Join videos" (tool-join, IsJoinTool) out of the split PRs. Sorry for the work that went into that part.

For the quick trim PR, the video back face will already be full (12 slices) once #349 is in, so please put tool-clip first and drop to-flac from the built-in video back face (and from the migration). It stays in the library, so anyone who wants it can add it back.

For the schema, number the migration after whatever main has when you open the PR. We'll confirm before merging. Looking forward to it!

@flexeykinDev flexeykinDev mentioned this pull request Oct 22, 2026
5 tasks done
@flexeykinDev

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Part 1, the quick trim, is in #439: tool-clip first on the video back face in place of to-flac (in the built-in face and the migration), schema 33, the docs sections, and the new fr / zh-TW strings. Join videos is left out. The editor follows as its own PR on top once #439 is in, with the EditorLayers.CleanUp fix (one try/catch per folder) and the // v34: nit. Window zoom will get its own small PR.

@KnifeLemon

Copy link
Copy Markdown
Owner

Closing this one, since it's now split into #439 (quick trim) and #440 (window zoom), and the join tool went with #349. Thanks again @flexeykinDev, the work continues in those two.

@KnifeLemon KnifeLemon closed this Oct 23, 2026
KnifeLemon added a commit that referenced this pull request Oct 23, 2026
Window zoom: Ctrl + wheel / Ctrl ± / Ctrl+0 (split from #326)
KnifeLemon added a commit that referenced this pull request Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants