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 is built on a clear two-layer architecture: a Rust backend powered by Tauri v2 handles all the heavy, Windows-native work — screen capture, hardware encoding, audio capture, and file I/O — while a SvelteKit/Svelte 5 frontend provides the user interface for the clip library, settings, and non-destructive editor. The two layers communicate exclusively through Tauri’s typed invoke() command channel; no shared memory or native bridges cross the boundary.

Technology Stack

Tauri v2 + Rust

Backend runtime. Owns capture pipelines, Media Foundation encoders, WASAPI audio tracks, the overlay window, and all file operations.

SvelteKit + Svelte 5

Frontend shell. Reactive state via $state runes. Four routes: library (/), settings (/settings), favorites (/favoritos), and games (/juegos).

Windows Graphics Capture

Frame acquisition API. Zero-copy GPU path: WGC delivers BGRA textures directly into a D3D11 device shared with the encoder.

Windows Media Foundation

Encoding and muxing. IMFSinkWriter writes MP4 containers; hardware MFTs (NVENC, AMF, Quick Sync) or a software fallback handle H.264.

WASAPI

Audio capture. Loopback on the default render device for system audio; per-device capture for microphone input.

Direct2D / DirectWrite

Overlay rendering. The out-of-focus card (blurred last frame + logo + text) is composited entirely on the GPU using the same D3D11 device as capture.

Module Overview

Every Rust module has a single, narrow responsibility. lib.rs is the only file that exposes Tauri commands; all other modules are plain Rust with no Tauri types in their public interfaces.
ModuleResponsibility
lib.rsTauri command registration and application setup
capture.rsWGC session, D3D11 device, hardware encoder selection, Instant Replay ring buffer, manual recording IMFSinkWriter
audio.rsWASAPI loopback and microphone capture, float→PCM16 conversion, downmix, AAC encoding via IMFTransform
overlay.rsOut-of-focus card: Direct2D Gaussian blur + logo + DirectWrite text composited on GPU
editor.rsNon-destructive edit model, IMFSourceReader/IMFSinkWriter export, waveform peak extraction
edits.rsPersistent edit index (edits.json in app-data, keyed by clip path)
library.rsClip list scan, rename, delete, embedded source metadata
config.rssettings.json read/write, directory management, asset protocol scopes
detect.rsForeground window enumeration, Steam AppID lookup, game detection
thumbnail.rsJPEG thumbnail generation and frame capture to PNG
artwork.rsGame hero and icon fetch (Steam CDN + local cache)

Communication Model

The frontend never calls Windows APIs directly. Every action is a Tauri invoke() call that names a command registered in lib.rs. The backend performs the operation synchronously or on a spawned thread, then returns a serialized result (or an error string) to the frontend.
// Frontend (TypeScript/Svelte)
const path = await invoke<string>("save_replay", { source: gameTitle });

// Backend (lib.rs) — thin wrapper delegates to capture module
#[tauri::command]
fn save_replay(source: String) -> Option<String> {
    capture::save_replay(&source)
}
Long-running operations (export, thumbnail generation, audio preparation) are dispatched to tokio::task::spawn_blocking so the command channel is never blocked. Progress updates during export are pushed back to the frontend via app.emit("export-progress", progress_f32).

Window Setup

Flashback creates two windows at startup, configured in tauri.conf.json and refined in the setup closure in lib.rs.

main

1200 × 675 logical pixels, frameless, not resizable below that minimum. Closing the window hides it to the system tray rather than quitting; the replay pipeline continues running in Rust threads regardless of window visibility.

overlay

480 × 64 logical pixels, fully transparent background, always-on-top. Rendered as a click-through, non-focusable floating window. Repositioned to the top-right corner of the primary monitor on every toast command call. Hidden between toasts.
// lib.rs — overlay setup
if let Some(o) = app.get_webview_window("overlay") {
    let _ = o.set_ignore_cursor_events(true);
    let _ = o.set_focusable(false); // never steals focus from the game
}
The overlay window is repositioned programmatically before each toast so it stays anchored to the right edge even after resolution or DPI changes:
let x = mpos.x + msize.width as i32 - size.width as i32;
let y = mpos.y + margin;
let _ = w.set_position(tauri::PhysicalPosition { x, y });

System Tray and Single-Instance Behavior

A system tray icon is built during setup with a two-item menu (“Open Flashback” / “Quit”). Double-clicking the tray icon or selecting “Open Flashback” calls show_main, which un-hides, un-minimizes, and focuses the main window. Selecting “Quit” calls app.exit(0), the only way to fully terminate the process. Single-instance enforcement uses tauri-plugin-single-instance. When a second Flashback process is launched (for example, from the Start Menu while the app is already running), the plugin intercepts it, forwards the launch arguments to the existing process, and calls show_main on it before the new process exits:
builder = builder.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
    show_main(app);
}));
Closing the main window via the title-bar X button hides it — it does not terminate the process. The Instant Replay pipeline continues buffering in the background. Use the tray menu “Quit” to fully exit.

Data Flow: Capture to Library to Editor

The full lifecycle of a clip looks like this:
Game / Monitor

      │  Windows Graphics Capture (WGC)

D3D11 Texture (BGRA)

      │  Video Processor MFT (BGRA → NV12, GPU)

H.264 Encoder MFT (NVENC / AMF / QSV / Software)
      │                      ▲
      │                      │ WASAPI loopback
      │              AAC Encoder MFT
      │              (system + mic tracks)

      ├── [Instant Replay]  ring buffer (pre-encoded packets)
      │       └── save_replay() → IMFSinkWriter → MP4 file

      └── [Manual Recording] IMFSinkWriter (real-time) → MP4 file


                          Videos\Flashback\Clips\

                               library::list_clips()


                              Clip Library UI (/)

                               editor::ClipEdit

                               export_clip() ──► Videos\Flashback\Clips-Edit\
Settings (encoder preference, clips directory, seen games, disabled games) are stored in %APPDATA%\Flashback\settings.json. Non-destructive edits are stored in %APPDATA%\Flashback\edits.json, keyed by the absolute path of each source clip, so the original MP4 is never modified.

Frontend State Management

The frontend uses Svelte 5 $state runes for all reactive state. There is no external state management library. Capture status is polled via periodic invoke("capture_status") calls; the overlay uses Tauri events (show-toast) emitted from the Rust side.
Because the replay pipeline lives entirely in Rust threads, the frontend can be closed, hidden, or even crashed without affecting an in-progress Instant Replay session. The buffer will continue filling until stop_replay() is called.

Capture Pipeline

WGC frame acquisition, D3D11 texture path, hardware encoder selection, and Instant Replay ring buffer mechanics.

Audio Pipeline

WASAPI loopback and microphone capture, PCM conversion, downmix matrix, and AAC encoding with IMFTransform.

Commands: Capture

Full reference for all capture and replay Tauri commands.

Commands: Editor

Full reference for editor, export, and timeline commands.

Build docs developers (and LLMs) love