Expand description
egui UI. Dockable layout (ui/layout.rs) of panes: Library, Preview, Inspector, Effects, Transitions, Subtitles, Timeline, Curves, Planner, Auto-cut, Tracking — DaVinci-like by default, bare Windows-forms styling. Windows (Settings, Retime, Export) never block the editor.
Modules§
- app
- The application: owns the project, undo stack, settings, player, dockable layout and wires the panels
together. Non-blocking windows (Settings, Retime, Export, Save Template, Save Profile, export/convert
progress) are plain
egui::Windows — the editor stays usable while they are open. Also executes MCP tool calls against the live project (one undo step per mutating call). - autocut_
ui - Auto-cut pane (non-blocking; the timeline stays usable while it is open). Works on the selected audio
clips (a selected video clip uses its linked audio). Controls: threshold (dBFS slider -80..0),
min silence, min speech, padding (DragValues), “Keep: loud parts / quiet parts” toggle, “Ripple (close
gaps)” checkbox. It shows the detected segments live (count + total kept seconds) and publishes them to
overlay(timeline time ranges to KEEP, per selected clip) so the timeline can shade them; buttons: “Split only” (cuts at the boundaries, removes nothing), “Apply” (Project::auto_cut with the cuts and the quiet ranges; linked video follows), “Clear”. Peaks come from WaveformCache (None while computing → “analysing…”); detection uses engine::autocut. Undo once per Apply/Split. Returns what changed. - capture_
ui - Screen recording + voiceover windows (both non-modal, both keep the editor usable).
- curves
- Curve (graph) editor for the FIRST selected clip: x = clip-local time over [0, duration], y = value.
Left: a list of the clip’s keyframeable properties (
Clip::props_mutnames + “Volume”/“Pan”/“Speed” + “: ” for effect params) with a colour swatch and a checkbox to show/hide each curve (auto-scaled per property; the selected property’s scale drives the y axis labels). Right: the graph — curves drawn with the eased segments (sample Animated::atevery ~2 px), keys as diamonds (accent when selected), playhead line (click on the ruler strip seeks →seeked), constant (unkeyed) properties shown as a flat dashed line. Interaction: drag a key horizontally/vertically (time clamped to the clip, vertical changes the value; undo once at drag start) — the whole selection moves with it, click a key to select it, Ctrl+click adds/removes one, dragging empty graph space rubber-bands a group (like the timeline’s clip band), Delete removes the selection and Ctrl+C / Ctrl+V copy it and paste it at the playhead keeping the relative times, double-click on empty graph area adds a key for the active property at that (t, v), right-click a key → easing menu (Ease::ALL) + Delete; Ctrl+Scroll zooms the time axis, Shift+Scroll pans, plain Scroll zooms the value axis around the pointer and “Fit” frames every key. Bezier velocity handles: a Bezier segment (or any segment whose left key is selected) shows its two handles; dragging one converts the segment toEase::Bezier. - effects_
ui - Effects panel. Top: the CATALOGUE as a thumbnail grid — one ~96x54 card per
EffectKindshowing the effect applied to a stock image with its name underneath, grouped byEffectKind::category()under collapsible headers, with a search box. Thumbnails arrive throughset_thumbnail(kind, id, size), which the app calls after rendering them on the GPU; without a GL context a card still shows its name on a neutral tile (never blank) — an effect withEffectKind::applies_to_audio()instead gets a solid green tile with a music-note glyph, since it has no picture to render. The catalogue is filtered to what the first selected clip can use (audio clip -> audio effects only, and vice versa); with nothing selected it shows everything. Clicking a card adds the effect to every eligible selected clip, right-clicking opens its quick actions (selected clips / every clip on the track), and only a deliberate press-and-move makes it aDragPayload::Effectdrag source (ui::drag_source). Below: the FIRST selected clip’s effect stack, in order: for each effect a header row (enabled checkbox, name, mask button, “Edit shader…” for a custom shader, copy/paste params, painted reorder and remove buttons) and its parameters fromeffect.specs(): a “From … for …” row giving the effect a window inside the clip (0 length = to the end of it, so an effect covers the whole clip until the user says otherwise), then label + DragValue (range from ParamSpec, speed ≈ (max-min)/200) — or a CHECKBOX whenEffectKind::is_bool_param— + a diamond keyframe toggle at clip-local playhead time (Animated::toggle_key / set_at, highlighted when a key exists) + a button to clear them. Tint shows a colour button bound to R/G/B as well. An effect with a mask gets the inspector’s mask grid inline (shape / position / radius / feather / invert …) plus a delete button. A clip that renders from a REAL node graph (Clip::uses_graph) greys the stack out — the graph is what the renderer evaluates, so stack edits would be invisible — and offers “Unlink” to get back to the list. Every change → undo once per gesture (sameedit_startrule as the inspector). - export_
ui - Export window (non-blocking egui::Window “Export”): resolution (Project / 720p / 1080p / 1440p / 4K /
Custom W×H, keeping the project aspect unless unlocked), scaler for up/downscaling (Nearest, Bilinear,
Bicubic, Lanczos, Area, Spline → ffmpeg flags), encoder (auto + detected), quality CRF, preset, an
“audio only” hint by extension, and the Fast Lossless Cut option when
export::lossless_segmentsapplies (with the keyframe-accuracy note). “Export…” opens the save dialog and returns the options; the window stays usable while an export runs (progress + cancel are shown by the app). Settings remember the last scaler/resolution. Returns Some(options) when the user confirmed an export this frame. - frame_
ui - “Export Frame” window: save the frame at the playhead as an image.
Options: resolution (Project / 2x / 4x / Custom W x H), upscaling mode (
Scalerfor the render plus the ffmpeg flag for the final resize), format (PNG / JPG / WebP with a quality slider for the lossy ones), and “Render with effects” vs “Source frame only” (the decoded frame of the top-most clip under the playhead, no compositing). Non-modal; returns the chosen options when the user confirms. - import_
ui - Import report window: after
engine::import::import_file, show what came through and what did not — a summary line (clips / tracks / missing media), then a scrollable table ofIssues grouped by level (Ok / Warning / Skipped) with the subject and detail. Buttons: “Use this project” (replaces the current one, with the usual unsaved-changes prompt), “Copy report” (markdown) and Close. Non-modal. - inspector
- Inspector panel. Nothing selected → Project panel (name, width, height, fps, duration, Save / Export / Export Frame buttons, export settings summary). One clip selected → clip name, enabled, colour label, timing (start / duration / source in), retime readout (Ctrl+R), and:
- layout
- Dockable editor layout (egui_tiles): panes can be rearranged by dragging their tabs, split, tabbed,
hidden/shown, popped out into their own OS windows (egui immediate viewports) and saved/loaded as
profiles (JSON — also written to / read from
.sedit-layoutfiles so profiles can be shared). - library
- Left panel: the project browser — Premiere’s project panel, in two sub-tabs.
- markers_
ui - Markers pane: every marker in timeline order (project markers and clip markers together, via
Project::markers_in_timeline). Rows: colour label dot (menu), time (editable DragValue, seconds), duration for ranges, name, note (multiline when the row is selected), “Go” (seek) and X (delete). Toolbar: “Add at playhead” (M), “Add on selected clip”, filter by label, and “Copy as list” (markdown, handy for the AI tools). Undo once per gesture; returns what changed. - mixer_
ui - Mixer pane: the routing list (which track feeds which bus) on top, one channel strip per bus below (Main last). Everything in a strip scrolls vertically, so a long filter chain stays reachable.
- nodes
- Node editor: the selected clip’s effect chain as a graph you can wire up.
- paste_
ui - “Paste Attributes” window (Ctrl+Alt+V): a checkbox per
AttrSetfield, All / None buttons, a line saying what is on the clipboard (“from ‘clip.mp4’”) and how many clips will change. Non-modal, like every other window. Returns Some(set) when the user confirms; the app then callsProject::paste_attributes(one undo step). - planner
- Planner pane: tabs “Plan” and “Notes”.
Plan = a nested to-do tree (Project.plan): each row = checkbox (done), editable title, colour label dot
(click → LABEL_COLORS menu), a collapse triangle, “+” add sub-task, delete, reorder among siblings,
indent/outdent; a selected item shows its notes (multiline) and its moodboard: the asset ids in
assetsas rows (name, kind tag, thumbnail via ThumbCache if available, per-asset note inasset_notes, “Add to timeline”, delete); assets are added by dropping library items (DragPayload::Asset) onto the item or onto the moodboard area. Progress bar “done/total” at the top; “Add task” at the top level; “Clear completed”. Notes tab = Project.notes as a large multiline TextEdit (“describe your process, ideas, style while you edit — the style summary / AI tools read this”). Undo once per gesture. Returns what changed. - presets_
ui - Presets pane: everything reusable that lives on the machine instead of in the project — saved effect chains, node graphs, adjustment layers and clip templates. All of it is in settings.json, so it survives a new project. Clicking a row applies it to the selection (templates place at the playhead); its context menu renames and deletes. “Save from selection” captures the selected clip’s node graph or effect stack, and falls back to a clip template for adjustment layers and multi-clip selections.
- preview
- Preview panel: the rendered frame (letterboxed, black bars), a selection outline for the selected
visual clip (drag to move = edits clip.x / clip.y at the playhead time via
Animated::set_at, callingundoonce at drag start), and the transport bar, centred under the video: go-start, prev cut, step back, play/pause, stop, step forward, next cut, go-end (all painted glyphs, NLE order) plus timecode / duration, In/Out buttons and the in/out times, a preview-quality selector (100 / 75 / 50 / 25 %) and a Movie mode toggle. Infullscreenmode only the video is drawn (no transport, no overlay): Esc / F11 leave it (app). - retime
- Retime window (Ctrl+R): speed / reverse / freeze for the selected clips (linked clips follow).
egui::Window “Speed / Retime”: speed as a percent DragValue (1..10000 %, 100 = normal) + preset buttons
(25 % 50 % 100 % 200 % 400 %), “Reverse” checkbox, “Freeze frame at playhead” button
(Project::freeze_at(playhead, selection)) and “Unfreeze” (clear
freeze), “Apply” → Project::set_speed (shows a note when the new length collides with a neighbour and nothing changed). Shows the resulting duration live. Undo once per applied change. Returns true when the project changed. - settings_
ui - Settings window (egui::Window, closable). Tabs:
- shader_
ui - “Shader Editor” window for
EffectKind::Shader: the GLSL body in a monospace editor, an Apply button, and the driver’s compile log verbatim (selectable, so it can be pasted somewhere) when the source was rejected. Non-modal — the timeline stays usable while it is open. The window only edits text: the app writes the source back onto the effect, pushes undo and asksGpuRenderer::check_shaderfor the log, then hands it here througherror. - subtitles_
ui - Subtitles panel. Toolbar: “Add at playhead” (cue [playhead, playhead+2 s) with the text “Subtitle”,
selected + text field focused), “Import…” (rfd: srt/vtt → engine::subtitles::parse → replace or append
after a yes/no), “Export SRT…” / “Export VTT…” (engine::subtitles::to_srt/to_vtt), “Burn in” checkbox
(project.show_subtitles), and a “Style” collapsing section (font combo from
fonts, size, colour, outline width/colour, background box colour, margin from bottom = project.subtitle_margin). Below: the cue list (egui::Grid / ScrollArea): start and end as editable timecode-ish DragValues in seconds (3 decimals, end ≥ start + 0.1, keep the list sorted via Project::sort_cues), a multiline text field, a play button (seek to the cue and play →seeked+play), a select checkbox and a delete one; the cue containing the playhead is highlighted; a “Split at playhead” button on the highlighted cue. A second toolbar row: “To text clips” (Project::cues_to_text_clips — editable Text clips on a “Subtitles” track), “Delete selected”, “Delete in range” (the In/Out range) and “Clear all”. “Open folder” →open_folder: the app writes the .srt sidecar and opens the folder. Undo once per gesture (same edit_start rule as the inspector); returns what changed. - timeline
- Timeline widget (custom painted). Header column (track name, M/S buttons, height drag handle at the bottom edge), ruler (ticks, in/out markers, click/drag scrubs), track lanes (video tracks top→bottom = Vn..V1, then A1..An), clips (name, waveform for audio via WaveformCache, keyframe diamonds, disabled = dimmed, selected = accent outline), playhead (drag by ruler or line).
- tools
- Tool bar: a thin, movable strip that sits between the viewport and the timeline (its own dockable
pane, so it can also be popped out). One row of icon buttons:
Select (V) · Text (T) · Rectangle · Ellipse · Triangle · Polygon · Star · Line · Arrow · Draw (D) ·
Mask (rect/ellipse/polygon/path) · Zoom
plus a magnet button that lights up while snapping is on (S, or Settings.snap’s own
Nshortcut), then, for shape tools, fill and stroke colour buttons and a stroke-width DragValue; for Draw, a play/record button, the brush colour/width, the playback speed (0.5x / 1x / 2x) and a page toggle. - tracking_
ui - Tracking pane (non-blocking): follow a point or a rectangular area through a clip and keep the result as a reusable project path.
- transitions_
ui - Transitions panel. Catalogue: one CARD per
TransitionKind(same size and frame as an effect card), previewing the transition half-way over the stock picture the effect thumbnails are rendered from — the app hands it over withset_stock, and without it a card falls back to a neutral named tile. A card selects the kind, right-clicking it applies the transition straight away (start / end of the selection, or every cut on its track), and a press-and-move dragsDragPayload::Transition. Next to the grid the default duration DragValue (0.1..5 s), a colour button for FadeToColor and a direction selector for Push/Wipe. “Add at start” / “Add at end” apply it to EVERY selected clip throughadd_transitions, which is also what the menu, the hotkeys and MCP call — it records the choice inTransitionsState, so Ctrl+T (Action::AddLastTransition) repeats whatever was applied last, whichever path applied it. A clip with no neighbour on that side gets an EDGE transition (blend from/to nothing) instead of a cut transition, so lone clips can fade in/out too. Below: the transitions touching the first selected clip (Project::transitions_of): kind combo, position combo (Start / End / Last / Next — re-anchors the transition relative to the clip), duration, colour/direction/ease editors, remove. Returns true when the project changed (callundoonce per gesture first).
Structs§
- Gesture 🔒
- Accumulates widget responses over one frame:
start→ push undo once,changed→ write back. Shared by every panel so the gesture rule lives in one place.
Enums§
- Drag
Payload - Drag-and-drop payload from the library / recent / planner panels to the timeline (egui dnd API).
Constants§
- DRAG_
SLOP 🔒 - How far the pointer must travel while held before a click turns into a drag.
- ENCODER_
PRESETS - x264-style speed presets offered by the settings and export windows.
Functions§
- combo
- ComboBox over (value, label) pairs writing into a String setting. Returns true if the value changed.
- drag_
intent 🔒 - “The user really means to drag this”: the primary button is down and the pointer has moved past
DRAG_SLOP. egui also promotes a stationary long press to a drag (is_decidedly_dragging), and itsSense::dragwidgets start dragging on the press of ANY button — which is how a right-click used to pluck a card out of a panel instead of opening its menu. - drag_
source 🔒 - An item that is clickable and right-clickable first and a drag-and-drop source second: the payload
is only handed to egui once
drag_intentholds, and the body is lifted under the cursor from that moment (the one thingUi::dnd_drag_sourceis good for). Use this instead ofdnd_drag_source, which senses drag only — grab cursor on hover, and a drag on any press. - duration_
text - Short duration text “1:23.4”.
- edit_
start 🔒 - True on the first frame of an edit gesture (drag start, or a non-drag change such as typing/clicking).
- encoder_
options - Encoder names worth offering: the h264 / hevc / vp9 / av1 families (software + nvenc/qsv/amf).
- key_
buttons 🔒 - Diamond keyframe toggle at the clip-local playhead + a “keys” clear button once it is animated.
- label_
color - Colour of a clip/asset/recent label index (0 or out of range = “no label” dim).
- label_
name - Name of a label index (“None” for 0 / out of range).
- mask_
grid 🔒 - Mask parameter grid, shared by the Inspector (the clip mask) and the Effects panel (a per-effect mask): shape, enabled, invert, position/size/rotation, feather, expand, opacity — each keyframable.
- once 🔒
- Push undo at most once per frame.
- seed_
mask_ 🔒points - A Polygon/Path mask is drawn from
points; with fewer than 3 vertices the rasteriser reports “outside everywhere” and the masked clip disappears with no way back. Seed the vertices from the mask’s own rect so every shape switch leaves something visible and editable. - timecode
- HH:MM:SS:FF timecode.