Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/CaramelHQ/Flashback/llms.txt

Use this file to discover all available pages before exploring further.

Flashback’s non-destructive clip editor is backed by a set of Tauri commands that handle the heavy lifting on the Rust side — demuxing, waveform extraction, frame-level seeking, re-encoding, and progress reporting — while the SvelteKit frontend (src/lib/editor.svelte.ts) drives the interaction model. Every original clip is left untouched; exported clips are written to a separate Clips-Edit directory. This page documents all editor commands, the shared type definitions they use, and working TypeScript examples drawn from the real frontend code.
All editor commands that call into Media Foundation are Windows-only. On other platforms they return an error string. load_clip_edit / save_clip_edit and edit_dest are platform-independent.

Shared Types

The following types are used across multiple editor commands. They are defined in src-tauri/src/editor.rs and serialised as JSON.

ClipEdit

The complete state of a non-destructive edit. Persisted to an edits.json index in the app-data directory (never as a sidecar next to the clip) so it survives file renames.
ClipEdit
object

Segment

A single kept range of source video.
Segment
object

MixerState

Per-track volume and mute settings applied during export. Defaults to sys_vol: 1.0, sys_muted: false, mic_vol: 1.0, mic_muted: false.
MixerState
object

Audio Preparation

prepare_clip_audio

Extracts audio tracks from an MP4 clip and writes them as WAV files to the app-data audio/ directory. Also computes reduced-resolution peak arrays for waveform display in the editor timeline. Extraction is cached: if WAV files already exist for the clip they are reused, making subsequent opens instantaneous. Clips recorded with a microphone contain two AAC audio streams (system loopback on stream 1, microphone on stream 0). Single-stream clips return null path fields and only populate mix_peaks.
path
string
required
Absolute path to the source MP4 clip.
Returns Result<ClipAudio, string>
ClipAudio
object
import { invoke, convertFileSrc } from '@tauri-apps/api/core';

const audio = await invoke<ClipAudio>('prepare_clip_audio', { path: clip.path });

// Wire WAV files into <audio> elements for the timeline scrubber
const sysAudioSrc = audio.system ? convertFileSrc(audio.system) : null;
const micAudioSrc = audio.mic    ? convertFileSrc(audio.mic)    : null;

Edit Persistence

load_clip_edit

Loads the persisted ClipEdit for a clip from the app-data edit index. If no edit exists for this path a default is returned (empty segments, default mixer). Transparently migrates legacy per-clip .edit.json sidecar files to the central index on first access.
path
string
required
Absolute path to the source MP4 clip.
Returns Result<ClipEdit, string>
const edit = await invoke<ClipEdit>('load_clip_edit', { path: clip.path });
console.log('Segments:', edit.segments.length);
console.log('System volume:', edit.mixer.sys_vol);

save_clip_edit

Persists a ClipEdit for a clip to the central edit index. The original MP4 is never modified. Flashback calls this automatically after a short debounce whenever the user makes a change in the editor.
path
string
required
Absolute path to the source MP4 clip — used as the index key.
edit
ClipEdit
required
The complete current edit state to persist.
Returns Result<void, string>
await invoke<void>('save_clip_edit', {
  path: clip.path,
  edit: {
    segments: [
      { start_ms: 0, end_ms: 15000, pos_ms: 0,
        bound_start_ms: 0, bound_end_ms: 15000, disabled: false }
    ],
    mixer: { sys_vol: 1.0, sys_muted: false, mic_vol: 0.8, mic_muted: false }
  }
});

Frame & Timing Information

keyframe_times

Returns the presentation timestamp of every H.264 IDR (keyframe) in the clip, in milliseconds, in ascending order. Use this list to snap the trim handle to the nearest keyframe, which allows exact cuts without re-encoding in seek-based workflows.
Flashback’s exporter re-encodes the entire clip through a single hardware encoder pass, so you do not need to snap to keyframes to avoid quality loss. keyframe_times is primarily useful for the UI: positioning seek handles near an IDR avoids the black-frame artefact that occurs when the decoder starts from a P-frame.
path
string
required
Absolute path to the source MP4 clip.
Returns Result<number[], string> — array of keyframe timestamps in milliseconds.
const keyframes = await invoke<number[]>('keyframe_times', { path: clip.path });
// Snap to the closest keyframe at or before a given time
const snap = (t: number) => [...keyframes].reverse().find(k => k <= t) ?? 0;

frame_times

Returns the presentation timestamp of every video frame in the clip, in milliseconds. Because Flashback uses WGC (which delivers frames only when screen content changes), clips are variable frame rate. This list lets the editor advance or rewind exactly one frame at a time regardless of the actual cadence.
path
string
required
Absolute path to the source MP4 clip.
Returns Result<number[], string> — array of all frame timestamps in milliseconds, sorted ascending.
const frames = await invoke<number[]>('frame_times', { path: clip.path });
// Step one frame forward from current position
const nextFrame = (t: number) => frames.find(f => f > t) ?? t;

clip_fps

Returns the nominal frame rate of the clip as stored in its Media Foundation media type. This is the rate declared at capture time (e.g. 60), not the actual delivered rate (which is variable with WGC).
path
string
required
Absolute path to the source MP4 clip.
Returns Result<number, string> — detected frame rate as an integer.
const fps = await invoke<number>('clip_fps', { path: clip.path });

Thumbnails & Frames

clip_thumbnail

Returns the path to a cached JPEG thumbnail for the clip (generated from frame 0). The thumbnail is written to the app-data thumbs/ directory the first time it is requested; subsequent calls return instantly from cache.
path
string
required
Absolute path to the source MP4 clip.
Returns Result<string, string> — absolute path to the cached JPEG file.
import { invoke, convertFileSrc } from '@tauri-apps/api/core';

const thumbPath = await invoke<string>('clip_thumbnail', { path: clip.path });
imgEl.src = convertFileSrc(thumbPath);
Use convertFileSrc from @tauri-apps/api/core to convert the returned filesystem path to an asset-protocol URL that the WebView can load. Direct file:// URLs are blocked by Tauri’s asset scope.

capture_frame

Extracts a single video frame at a specific timestamp and saves it as a PNG to the Screenshots directory (Videos\Flashback\Screenshots). The filename encodes the clip stem and timestamp (e.g. myclip_4200.png).
path
string
required
Absolute path to the source MP4 clip.
time_ms
number
required
Timestamp of the frame to extract, in milliseconds.
Returns Result<string, string> — absolute path of the saved PNG file.
const framePath = await invoke<string>('capture_frame', {
  path: clip.path,
  time_ms: 4200.0
});
console.log('Frame saved to:', framePath);

Export

edit_dest

Computes the destination path for an exported clip without writing anything. Exported clips always go to the dedicated Clips-Edit subdirectory (Videos\Flashback\Clips-Edit) so they are kept separate from originals but still appear in the library. The output filename is <stem>_edit.mp4.
src
string
required
Absolute path to the source MP4 clip.
Returns string — the absolute destination path.
const dst = await invoke<string>('edit_dest', { src: clip.path });
console.log('Will export to:', dst);

export_clip

Re-encodes the clip according to the provided ClipEdit, writing the result to dst. Each enabled segment is decoded, re-timed, and written through a single H.264 hardware encoder pass (software fallback if no GPU encoder is available). Audio is either remixed (system + mic with mixer volumes) or passed through with gain applied. This is an async command that runs on a blocking thread. While running it emits export-progress events on the Tauri event bus so the UI can show a progress bar.
src
string
required
Absolute path to the source MP4 clip.
dst
string
required
Absolute path for the output file. Use edit_dest to compute the canonical destination.
edit
ClipEdit
required
The edit to apply. Disabled segments are automatically excluded.
Returns Result<void, string> — resolves when the export is complete and the MP4 has been finalised.

export-progress event

While export_clip is running the backend emits progress updates via the Tauri event bus.
FieldTypeDescription
payloadnumberExport progress from 0.0 to 1.0. The final 1.0 event is emitted after Finalize() completes.
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';

// Listen for progress updates
const unlisten = await listen<number>('export-progress', (event) => {
  progressBar.value = event.payload; // 0.0 – 1.0
});

try {
  const dst = await invoke<string>('edit_dest', { src: clip.path });
  await invoke<void>('export_clip', {
    src: clip.path,
    dst,
    edit: {
      segments: [
        { start_ms: 5000, end_ms: 45000,
          pos_ms: 0, bound_start_ms: 5000, bound_end_ms: 45000,
          disabled: false }
      ],
      mixer: { sys_vol: 1.0, sys_muted: false, mic_vol: 0.8, mic_muted: false }
    }
  });
  console.log('Export complete:', dst);
} finally {
  unlisten();
}

Clip Editor

User-facing guide to the non-destructive clip editor.

Audio Pipeline

How system loopback and mic tracks are structured in the MP4.

Capture Pipeline

How clips are produced by the capture engine.

Library Commands

Commands for listing and managing clips.

Capture Commands

Commands for starting and stopping recordings.

Architecture

High-level overview of the Flashback Tauri architecture.

Build docs developers (and LLMs) love