Documentation · Version 1.0.0

Embedding VeloFrame

Everything you need to bring screenshots and clips into your app.

Windows macOS in progress Linux in progress

Overview

VeloFrame was written specifically for ClipHub, the clipping app by LiGLP Studios, and is open source: github.com/LiGLP-Studios/VeloFrame. Business use, or use in apps that are not open source, requires a license from LiGLP Studios.

VeloFrame has no user interface. The host application (e.g. ClipHub) decides when to capture, by hotkey, button or automation, and what happens with the result. VeloFrame does the capturing.

  • Engine only. Hotkeys, settings and display belong to the host application. VeloFrame receives finished requests and returns results with measurements.
  • Two ways to embed. As a Rust library (veloframe::Engine) or as a separate process (veloframe.exe, JSON lines over stdin/stdout). The process route protects the host from crashes and works with any language.
  • Stay warm. warm_up() opens capture up front and buffers are reused, so even the first screenshot is fast.
  • Everything is measured. Every answer contains per-step timings and which source delivered the image.

Not yet: audio in clips, mouse cursor in video, Windows Graphics Capture (phase 2), and macOS and Linux. The Mac and Linux versions are being worked on.

Build, test, measure

VeloFrame is a Rust workspace. The release build ends up in target/release/veloframe.exe.

cargo build --release
cargo test --workspace

# Benchmarks
cargo run --release -p veloframe-bench -- encode "Screenshot.png"   # compare encoders
cargo run --release -p veloframe-bench -- capture 20                 # measure real screenshots
cargo run --release -p veloframe-bench -- memory                     # memory after each step
cargo run --release -p veloframe-bench -- clip performance 30        # measure and verify the clip buffer
cargo run --release -p veloframe-bench -- clip long 60

As a Rust library

The direct route for Rust apps. warm_up() opens capture up front so even the first screenshot is fast.

use veloframe::{Engine, ScreenshotRequest, ImageFormat, Area, Rect};

let mut engine = Engine::new()?;
engine.warm_up()?;                         // open capture up front
let shot = engine.screenshot(&ScreenshotRequest {
    format: ImageFormat::Jpeg,
    quality: 90,
    cursor: false,
    area: Area::Window,                    // foreground window, otherwise the screen
    screen: Rect::new(0, 0, 2560, 1440),   // physical pixels
    folder: "C:\\Users\\Name\\Pictures\\Screenshots".into(),
    clipboard: true,                       // copied to the clipboard while encoding
})?;
println!("{} in {:.1} ms", shot.path, shot.total_ms);

As a separate process

For Electron, Node, Python, C# and everything else: start veloframe.exe and send one JSON message per line on stdin. Answers arrive line by line on stdout. If the engine crashes, the host application keeps running.

→ {"id":1,"cmd":"screenshot","args":{"format":"png","area":"screen",
     "screen":{"x":0,"y":0,"width":1920,"height":1080},"folder":"C:\\Pictures"}}

← {"id":1,"ok":true,"result":{"path":"C:\\Pictures\\Screenshot 2026-11-05 163141.png",
     "width":1920,"height":1080,"captureMs":4.0,"encodeMs":25.0,"totalMs":29.0,"warm":true}}
  1. Start the process. VeloFrame announces itself with a ready event and pre-warms capture on all screens.
  2. Send requests with a unique id, one per line.
  3. Match answers by id. ok tells you whether it worked.

The protocol is compatible with the previous ClipHub capture helper. ClipHub can start veloframe.exe instead of cliphub-capture.exe without changing its Electron code.

Commands

CommandArgumentsResult
ping–"pong"
version–Engine, version, active capture source
system-check–GPUs, monitors, HDR, encoders, available capture paths
warm-up–Open capture on all screens up front (veloframe.exe does this on start)
screenshotformat (png/jpeg), quality, cursor, area (screen/window), screen, folder, clipboardPath, size, bytes, source, per-step timings
copypathCopy the last screenshot to the clipboard again, otherwise error not-cached
buffer-startmode (performance/long), seconds, fps, quality (low…ultra), resolution (native, 1440p, 1080p, 720p), screen, optional codec (h264/hevc), storage (file/ram)Plan, encoder, accepted settings
buffer-status–Seconds and bytes in the buffer, encoded and dropped frames (by reason), encoder effort
save-clipfolder, optional secondsPath, size, duration, frames, codec, save time
buffer-stop–Stop the buffer, release memory and encoder

Timings in every answer

Screenshot answers contain captureMs, encodeMs, writeMs, totalMs and clipboardMs, so you can always see where time is lost.

Errors

Every error has a fixed code for your app and a message you can show your users directly. React to code in your code, not to the text.

{"id":1,"ok":false,"error":"Message for the user","code":"no-screen"}
CodeMeaning
invalid-requestRequest incomplete or malformed
no-screenNo matching screen found
capture-lostCapture lost (resolution change, UAC, fullscreen switch). VeloFrame reopens once and tries again
capture-failedCapture failed
save-failedFile could not be saved
clipboard-failedClipboard not available
not-cachedNo screenshot in memory for copy
unsupportedNot possible on this system

Screenshots

The flow of a screenshot request, from the call to the file:

Request (Rust API or JSON line)
  └─ ScreenshotPipeline::take                      core/pipeline.rs
       ├─ Target: screen or foreground window
       ├─ ScreenSource::capture -> RgbImage        Win/duplication.rs
       │    └─ screen with the largest share of the target, D3D device on its GPU,
       │       BGRA -> RGB (4 pixels per step), rotation handled
       ├─ draw mouse cursor (optional)             Win/desktop.rs
       ├─ in parallel: clipboard (own thread)      Win/clipboard.rs
       │               encode PNG/JPEG in memory   core/codec (all cores)
       │               then write in one go        core/screenshot.rs
       └─ result with measurements; image stays in memory for `copy`

Custom encoders

Both split the image into horizontal strips, one per CPU core, and join the parts into an ordinary file.

  • PNG: All five PNG filters are computed per row (with AVX2 when the CPU supports it), the best one wins. Then a custom DEFLATE encoder with its own Huffman code per strip. Verified lossless.
  • JPEG: Each strip is encoded separately (SIMD) and joined with restart markers. The file decodes pixel for pixel exactly like a single pass.
  • The game comes first: The helper threads run below normal priority and only use CPU time that is currently free.

Clip engine

The clip buffer continuously captures a screen, encodes in hardware and keeps the last seconds ready. On request they are saved as MP4, without re-encoding.

Modes

PerformanceLong
Length5–60 s5–300 s
CodecHEVC (if the GPU supports it), otherwise H.264H.264 (plays everywhere)
Bitrate 1080p60 “high”mean 6.2 / cap 10.4 Mbit/s, follows the contentmean 13.6 / cap 16 Mbit/s
Keyframeevery 2 severy second
Encoder effort85, lowered when needed70, lowered when needed
GPU prioritybehind the gamenormal
Buffertemporary filetemporary file

Codec and buffer location can be overridden per request (codec, storage).

Per-frame flow (60 fps = every 16.7 ms)

Desktop Duplication ─► GPU texture (only when something changed)
        │
GPU video processor: BGRA → NV12, BT.709, scaling ─► frame from the encoder pool
        │
Queue (up to 4 frames) ─► hardware encoder (NVENC / AMF / QuickSync)
        │
Packets ─► replay buffer (fixed ring, always a keyframe at the front)
        │
save-clip ─► MP4 (index at the front, packets unchanged)

What VeloFrame does itself

  • Queue in front of the encoder: Short delays no longer cost a frame. Dropped frames under load: from 8–11 % down to 0.4–1.6 %.
  • Encoder effort controller: If more than 1 % of frames are lost, VeloFrame lowers the effort while running and raises it again once there is headroom. Smooth video comes before the last percent of compression.
  • Buffer in a temporary file: Windows keeps it in the cache where possible and can give the memory back to the game at any time. It is deleted on exit, even after a crash.
  • Saving without a copy: The index is copied under the lock, the data is read afterwards while recording continues.
  • One capture for both: While the buffer runs, screenshots of that screen come from the live image (17 ms total).
  • Clean teardown: The encoder is drained before shutdown. 40 out of 40 runs end cleanly.

Known limitations

  • No audio and no mouse cursor in the video yet.
  • One screen per buffer; rotated screens not yet supported.
  • A clip starts at the last keyframe before the requested start (Performance: up to 2 s earlier). Frame-accurate start is still to do.
  • Windows 10 only plays HEVC with the “HEVC Video Extensions” from the Microsoft Store. Browsers (Chrome, Edge, Electron) play HEVC with hardware support. For maximum compatibility use codec: "h264".
  • The NVIDIA HEVC encoder does not accept B-frames.

Architecture

The pipeline lives platform-independently in core. The platform crates only implement two interfaces:

  • ScreenSource delivers an image of a desktop region (Desktop Duplication, later Windows Graphics Capture, ScreenCaptureKit, PipeWire).
  • Desktop delivers foreground window, mouse cursor, clipboard and timestamp.
FolderCrateContents
coreveloframe-coreImage types, interfaces, screenshot pipeline, custom encoders, clip modes, replay buffer, MP4 writer, protocol, errors
engineveloframeThe engine API (Engine) and the veloframe.exe program
Winveloframe-winDesktop Duplication, mouse cursor, clipboard, system check, clip buffer (GPU capture, NV12, hardware encoder)
Macveloframe-macScreenCaptureKit, VideoToolbox (in progress)
Linuxveloframe-linuxPipeWire, xdg-desktop-portal, X11, VAAPI (in progress)
benchveloframe-benchBenchmark tool: compare encoders, measure screenshots, memory and the clip buffer

Benchmarks

Release build, Intel Core i5-6400 (4 cores), RTX 3050, Windows 10, two monitors on two GPUs. Measured under load: other programs were already using 60–70 % of the CPU.

Screenshot engine memory

StateTask ManagerTotal working setCommitted
After start + warm-up23.5 MB45.5 MB57.5 MB
After screenshots29.9 MB52.1 MB64.1 MB
After a screenshot with clipboard37.9 MB60.1 MB72.0 MB
  • Task Manager shows the private working set: memory used only by VeloFrame.
  • Total working set additionally includes the GPU driver files (about 22 MB), shared by all programs on the same GPU, including the game.
  • CPU when idle: 0.00 %, no background polling. 20 more screenshots change usage by less than 1 MB, so no memory leak.

Platforms

PlatformStatusTechnology
Windows 10 / 11AvailableDesktop Duplication, Media Foundation, D3D11
macOSIn progressScreenCaptureKit, VideoToolbox
LinuxIn progressPipeWire, xdg-desktop-portal, X11, VAAPI

The Mac and Linux versions are still being worked on. The interfaces are the same as on Windows, so your integration won't need to change for them later.

Windows roadmap

PhaseContentsStatus
0 · FoundationTypes, IPC protocol compatible with ClipHubDone
1 · Desktop DuplicationEverything the ClipHub helper can do: monitors, rotation, DPI, active window, PNG/JPEG, clipboardDone
Intermediate · SpeedPre-warming, custom encoders on all cores, benchmark toolDone
2 · Windows Graphics CaptureCapture single windows, even when something lies on topPlanned
3 · GPU processingCrop and HDR → SDR via shadersPlanned
4 · OutputWebP and metadata (time, game name, monitor)Partly
5 · Automatic selectionBest capture path with fallback, no screenshot fails without reasonPlanned
6 · Benchmark & polishMeasure FPS loss in the game, compare with the old helperPlanned

Targets

MetricTarget
Key press to finished file, 1440p, JPEGunder 50 ms
Key press to finished file, 1440p, PNGunder 150 ms
FPS loss in the gamenot measurable (under 1 %)
RAM when idleunder 30 MB
CPU when idleclose to 0 %

Open source and license

VeloFrame is open source. The complete source code is on GitHub: github.com/LiGLP-Studios/VeloFrame.

UseWhat you need
Open-source projectsFree to use, no license from LiGLP Studios needed
Business useLicense from LiGLP Studios
Apps that are not open sourceLicense from LiGLP Studios

Request a license: for business use or closed-source apps, write to business@liglp.de or get in touch via .