Reel is the video non-linear editor (NLE) of the Prism creative suite —
the Premiere Pro analog, and Prism app #4 (after Pigment, Contour, and Pulse).
It is built in Rust on eframe / egui (glow backend), sharing the suite's
prism-core and prism-io foundation crates.
This is an initial, working scaffold: a multitrack timeline you can edit, a program preview, and a media bin. Real video decode is not implemented yet (see Future work); every clip is treated as a single still over its duration.
- Timeline (bottom, the core)
- A seconds ruler with one-second ticks and labels.
- N stacked track lanes (
V1,V2, …), highest track drawn on top. - Each clip is a draggable block (label + colored body):
- drag the body horizontally to move its
start(and vertically to change track; a track change that would overlap another clip is rejected), - drag the left / right edge to trim —
source_in/durationstay consistent, and with Ripple on (transport toggle) the trim shifts every downstream clip on the track, - Alt+drag a clip body to slide it (eat into neighbours, no gap), or Alt+drag an edge to roll the shared cut with the adjacent clip (total length preserved).
- drag the body horizontally to move its
- A draggable playhead (grab the top handle), and click / drag the ruler or empty lane space to scrub.
- Snap-to-other-clip-edges and to the playhead while dragging.
- Transport: Play / Pause advancing time by real
dt, looping at the project duration, requesting repaints while playing. Space toggles play/pause; jump-to-start / jump-to-end buttons; live timecode + frame number. - Preview (central panel): at the playhead, finds the topmost clip active on
the highest track and renders it into an aspect-fit comp frame —
Colorsources fill the frame,Imagesources are drawn aspect-fit (letterboxed) from a cached, decoded texture. An empty frame is black. When a transition is active at the playhead, the frame is the blend of its two clips: a cross-dissolve stacks the incoming clip over the outgoing one by progress, and a dip to color (black / white) shows one clip with a flat color dipped over it (peaking at the midpoint). - Media bin (left panel): lists imported media; File → Import media…
(
rfd) adds an image, and Add color adds a color clip. The+button on a bin item drops it onto the top track at the playhead. - Editing tools (the daily-driver edit surface, modeled as unit-tested pure
operations on the project): razor / split at the playhead (
Cor the scissors button — splits every straddling clip, source-continuous across the cut), lift (delete, keep gap —Del), ripple delete (delete + close gap —⇧Del), close gap after, plus ripple / roll / slip / slide trims. Slip the selected clip's source window one frame with[/]. The transport shows the (primary) selected clip's source in→out points. - Multi-select & marquee: Ctrl/Cmd-click or Shift-click toggles
clips in/out of the selection; a drag on empty lane space marquee-selects
every clip it covers; Cmd/Ctrl+A selects all, Esc clears. Dragging the
body of a multi-selected clip moves the whole group together, and Lift /
Ripple delete act on every selected clip at once (modeled as pure
move_clips/lift_clips/ripple_delete_clipsover aSelection). - Transitions (computed in the preview compositor, no FFmpeg): Edit → Add
transition drops a cross dissolve or a dip to black / white at the
cut nearest the playhead on the selected clip's track (clamped so it can't
overrun either clip). Each transition shows as a translucent band with
crossing diagonals on the timeline, persists in the
.reelfile, and is cleaned up automatically when a referenced clip is removed. - Captions / subtitles (sequence-level timed text, no FFmpeg): a
Captionstrack of[start, end)cues with a shared style (size / color / box / Top · Middle · Bottom position), burned into the program monitor at the playhead. Captions menu adds a cue at the playhead (⇧C), navigates cues, and imports / exports SRT / VTT (one tolerant parser for both); the inspector edits the cue text / timing and the style; a timeline strip shows each cue. - Menus: File (New, Import media…, Save
.reel→serde_jsonviarfd), Edit (Razor; Lift; Ripple delete; Close gap after; Add transition — and the Delete / Backspace /⇧Del keys), Captions (add / nav / import / export). - Prism dark theme (warm amber accent to distinguish the NLE) and Phosphor icons (clapperboard / film-strip / scissors motif), reimplemented locally.
// A clip references a source + a *window into it* (source_in + duration),
// decoupled from its timeline placement (start, track). Edit ops are pure,
// unit-tested methods on Project (split/lift/ripple_delete/close_gap_after/
// roll/slip/slide/ripple_trim_*); the UI is a thin caller. 28 unit tests.
struct Clip { name, source: ClipSource, track, start, duration, source_in }
enum ClipSource { Image(PathBuf), Color([f32; 4]) }
struct Project { width, height, fps, duration, tracks, clips, bin }Reel path-depends on the suite's shared crates (it does not copy or modify them):
prism-core—prism_core::Sizefor image dimensions andprism_core::color(srgb_to_linear/linear_to_srgb) at the color boundary into egui.prism-io—prism_io::load_imagedecodes still images to 8-bit sRGB RGBA (cached into egui textures keyed by path), andprism_io::SUPPORTED_EXTENSIONSpopulates the import dialog filter.
The theme and icon modules are reimplemented locally (adapted from Pigment / Pulse, not symlinked) so Reel's look can drift independently.
From prism/reel:
cargo run # debug build + launch
cargo build # build only
cargo fmt # format
cargo clippy # lintThe binary crate is reel-app and produces a binary named reel.
- Video decode (FFmpeg) — the headline gap.
ClipSourcewill gain aVideo(PathBuf)variant; an FFmpeg-backed decoder will seek and decode frames at the playhead and feed the same texture-upload path the still preview uses. - Audio tracks and waveform display.
- More transitions (wipes, push/slide/zoom) and per-clip effects, plus a real render/export pipeline (cross-dissolve and dip-to-color land in v0).
- Project load (the save path already writes
.reelJSON).