A high-performance, borderless image and video viewer for Windows, built with Rust, egui, and GStreamer.
This project is intentionally optimized for one job: opening media fast, navigating large folders fast, and keeping dense Long Strip / Masonry layouts responsive. It is not trying to be a DAM, editor, cataloger, or full video player. Think of it as a QuickLook-style viewer with unusually aggressive performance work under the hood.
floating.webm
masonry.webm
longstrip.webm
transition.webm
- Borderless floating window with custom title bar, auto-hide controls, and native-feeling fullscreen / maximize transitions on Windows.
- Fast single-file viewing plus fast folder navigation, including natural-sort media lists and optional single-instance reuse.
- Static images, animated GIF, animated WebP, and video playback in one app.
- Two fullscreen multi-item layouts: Long Strip and Masonry.
- Context-aware shortcut system where the same input can map to different actions in different modes.
- Persistent metadata and thumbnail caching, plus in-memory decode and texture caches.
- R-tree viewport virtualization, LOD bucketing, mipmapping, batch uploads, and bounded worker queues for dense layouts.
- Built-in FPS / diagnostics overlay and Criterion benchmarks for tracking regressions.
- Borderless floating mode for quick previewing.
- Fullscreen mode with configurable Windows-native maximize / restore transitions.
- Optional borderless fullscreen behavior for the custom maximize button and fullscreen shortcuts.
- Smart initial sizing: open at 100% when possible, otherwise fit to the screen.
- Drag and drop support.
- Single-instance mode that forwards file-open requests from secondary launches to the primary window.
- Title bar menu entry for
Edit Settings, which opens the activeconfig.iniin the default editor. - CJK filename support through lazy Windows font loading.
- Smooth cursor-follow zoom in floating and fullscreen modes.
- 90 degree rotation with
Up/Down. - Fine rotation in fullscreen with
Ctrl+Up/Ctrl+Downusing a configurable step size. - Double-click reset / fit behavior.
- Per-image fullscreen view memory for zoom, pan, and rotation, but only after explicit user interaction so automatic fit transitions do not create stale remembered states.
- Animated GIF playback with play / pause and scrubbing.
- Animated WebP support, including progressive frame streaming in the solo-view path.
- GStreamer-backed video playback with
playbin3fallback toplaybin. - Play / pause, seek, mute, volume, looping, and hover-driven controls.
- Adaptive seek policy support:
adaptive= keyframe while dragging, accurate on releaseaccurate= always frame-accurate seekskeyframe= fastest seeks, less precise
- Optional hardware-decoder preference on Windows, with a config switch to force software decode.
- In Long Strip / Masonry, videos use first-frame thumbnails until a focused live player is needed.
- Long Strip: continuous vertical reading layout for the current folder.
- Masonry: dense multi-column layout with configurable
masonry_items_per_row. - Bottom-right mode buttons for toggling
MasonryandLong Stripwhile fullscreen. - Inertial scrolling, drag panning, Ctrl+wheel zoom, and a configurable middle-click freehand autoscroll ball.
- Masonry freehand autoscroll keeps visible-item prioritization and visible-quality recovery aligned with the moving viewport.
- Video first-frame thumbnails and animated media support inside multi-item layouts.
- Hover-based autoplay in Masonry after a configurable settle delay.
- Solo fullscreen quick-open from Long Strip / Masonry with preserved return context and warm-cache reuse.
| Format | Extensions |
|---|---|
| JPEG | .jpg, .jpeg |
| PNG | .png |
| WebP | .webp |
| GIF | .gif |
| BMP | .bmp |
| PSD | .psd |
| ICO | .ico |
| TIFF | .tiff, .tif |
| Format | Extensions |
|---|---|
| MP4 | .mp4 |
| MKV | .mkv |
| WebM | .webm |
| AVI | .avi |
| QuickTime | .mov |
| WMV | .wmv |
| FLV | .flv |
| M4V | .m4v |
| 3GP | .3gp |
| OGV | .ogv |
Download the latest release from the Releases page.
The app is portable in the sense that you can place the executable folder anywhere. Use Windows Open with or file associations to launch media directly into it.
Because this project is built and distributed by a solo developer, the installer is not signed with an expensive enterprise code-signing certificate. As a result, Windows may treat the downloaded file as unfamiliar and flag it with a Mark of the Web (MotW), showing a "Windows protected your PC" or Smart App Control warning.
This is a safety mechanism in Windows for unsigned downloads, not proof that the app is malware. If you trust the source, you can unblock the installer manually:
- Download the installer.
- Right-click the downloaded file and select Properties.
- Go to the General tab.
- Look at the bottom for a Security warning and check the box that says Unblock.
- Click Apply and OK.
- Run the installer normally.
If you still see warnings after unblocking, Windows is simply being cautious about unsigned software. The unblock step tells Windows that you trust this file from this source.
Image viewing works without GStreamer, but video playback requires a GStreamer runtime install.
- Download GStreamer from https://gstreamer.freedesktop.org/download/
- Install the 64-bit MSVC runtime package.
- If you build from source, install the development package too.
- Make sure the GStreamer binaries and plugins are discoverable.
The app also tries to improve Windows-side discovery by refreshing PATH from the registry, probing common GStreamer install locations, and configuring plugin-scanner / registry paths automatically.
git clone https://github.com/cosmokud/rust-image-viewer.git
cd rust-image-viewer
# Fully optimized release build
cargo build --release
# Optional: release build with mimalloc as the global allocator
cargo build --release --features mimalloc-allocator
# Optional: faster-to-build release-like profile
cargo build --profile release-fastBuild requirements:
- Rust 1.76+
- Windows 10/11
- GStreamer MSVC runtime + development packages for video support
PKG_CONFIG_PATHpointing at GStreamer'spkgconfigdirectory if it is not auto-detected
$env:PKG_CONFIG_PATH = "C:\gstreamer\1.0\msvc_x86_64\lib\pkgconfig"The executable will be written to target/release/rust-image-viewer.exe for the standard release profile.
rust-image-viewer.exe path\to\file.jpg
rust-image-viewer.exe path\to\video.mp4When you open one file, the viewer builds the media list for its directory and enables previous / next navigation across the supported files in that folder.
- Floating / solo fullscreen mode is optimized for one current item at a time.
- Long Strip and Masonry are fullscreen-only multi-item layouts.
- Keyboard copy / cut actions prefer marked files first; without marks, Long Strip and Masonry target the hovered item.
- Right-click is contextual by design:
- floating / solo fullscreen side zones and black bars navigate previous / next
- right-click on the current media toggles fullscreen when bound to
goto_file - right-click on a strip or masonry item opens that item into solo fullscreen by default
- Middle-click is the freehand autoscroll trigger by default, not fullscreen.
- Center right-click can still act as play / pause for video or animated GIF when it is not consumed by navigation or fullscreen routing.
Bindings are action-first and context-aware. The same input can legally belong to multiple actions as long as those actions live in different modes.
| Action | Default |
|---|---|
| Toggle fullscreen | f, f11, f12, enter |
| Exit | ctrl+w, escape |
| Action | Default |
|---|---|
| Pan current view | mouse_left |
| Side-zone / black-bar previous-next navigation | mouse_right |
| Toggle fullscreen on current media | mouse_right |
| Freehand autoscroll | mouse_middle |
| Next item | right, pagedown, mouse5 |
| Previous item | left, pageup, mouse4 |
| Rotate clockwise | up |
| Rotate counterclockwise | down |
| Precise rotation clockwise | ctrl+up |
| Precise rotation counterclockwise | ctrl+down |
| Zoom in | scroll_up, ctrl+scroll_up |
| Zoom out | scroll_down, ctrl+scroll_down |
| Jump to first item | built-in fallback home |
| Jump to last item | built-in fallback end |
| Action | Default |
|---|---|
| Drag-pan strip | mouse_left |
| Open clicked item in solo fullscreen | mouse_right |
| Freehand autoscroll | mouse_middle |
| Continuous pan up | up |
| Continuous pan down | down |
| Fit-aware next page | right |
| Fit-aware previous page | left |
| Jump to next item | pagedown, mouse5 |
| Jump to previous item | pageup, mouse4 |
| Inertial wheel scroll up | scroll_up |
| Inertial wheel scroll down | scroll_down |
| Zoom in | ctrl+scroll_up |
| Zoom out | ctrl+scroll_down |
| Jump to start / end | built-in home, end |
| Action | Default |
|---|---|
| Drag-pan masonry | mouse_left |
| Open clicked item in solo fullscreen | mouse_right |
| Freehand autoscroll | mouse_middle |
| Pan up / down | up, down |
| Faster pan up / down | left, right |
| Fastest pan up / down | pageup, pagedown, mouse4, mouse5 |
| Inertial wheel scroll up / down | scroll_up, scroll_down |
| Zoom in / out | ctrl+scroll_up, ctrl+scroll_down |
| Action | Default |
|---|---|
| Play / pause | space |
| Mute | m |
- The canonical template is
assets/config.ini. - Your runtime config is normally created at
%APPDATA%\rust-image-viewer\config.ini. - Legacy
rust-image-viewer-config.iniandsetting.inifiles are migrated automatically. - Leaving a shortcut value empty disables the default binding for that action.
- Older fullscreen defaults that used middle-click are migrated to the newer
f,f11,f12,enterset. - Context priority is deliberate. For example, in strip mode the item-open binding outranks generic right-click logic, and in floating / solo fullscreen the side-zone navigation binding outranks center fullscreen toggling.
Example custom bindings:
[Shortcuts]
toggle_fullscreen = q, enter
video_play_pause = k, space
manga_goto_file = mouse_middle
masonry_goto_file = enterAvailable binding syntax:
| Type | Values |
|---|---|
| Mouse buttons | mouse_left, mouse_right, mouse_middle, mouse4, mouse5 |
| Scroll wheel | scroll_up, scroll_down |
| Modifiers | ctrl+<key>, shift+<key>, alt+<key> |
| Letters | a - z |
| Numbers | 0 - 9 |
| Function keys | f1 - f12 |
| Arrow keys | left, right, up, down |
| Special keys | escape, enter, space, tab, backspace, delete, insert, home, end, pageup, pagedown |
The config file is versioned. If the file is missing, stale, or missing its version header, the app regenerates the default template. The shipped template is also synchronized during the build so new keys stay discoverable.
Delete config.ini if you want to regenerate it from the current defaults.
| Key | Default | Meaning |
|---|---|---|
controls_hide_delay |
0.5 |
Delay before the top controls / title bar hide. |
bottom_overlay_hide_delay |
0.5 |
Delay before bottom overlays hide. Affects video controls, mode buttons, and zoom HUD. |
double_click_grace_period |
0.35 |
Double-click timing window in seconds. |
show_fps |
false |
Enables the top-right diagnostics overlay. |
resize_border_size |
6 |
Hit area for floating-window resize borders. |
startup_window_mode |
floating |
floating or fullscreen. |
single_instance |
true |
Reuse one window and forward file-open requests into it. |
vsync |
true |
Enable swapchain vsync to reduce tearing. |
metadata_cache_max_size_mb |
1024 |
Max on-disk size of metadata_cache.redb in MiB. 0 disables the size cap. |
background_rgb |
0, 0, 0 |
Background color as one RGB triplet. |
background_r |
0 |
Alternative per-channel background override. |
background_g |
0 |
Alternative per-channel background override. |
background_b |
0 |
Alternative per-channel background override. |
fullscreen_reset_fit_on_enter |
true |
Reset and fit media when entering fullscreen. |
fullscreen_native_window_transition |
true |
Use Windows maximize / restore animations during fullscreen transitions. |
maximize_to_borderless_fullscreen |
true |
Make the title-bar maximize action enter borderless fullscreen instead of a separate maximized floating state. |
zoom_animation_speed |
20 |
Speed of floating zoom animation. 0 disables the animation. |
precise_rotation_step_degrees |
2.0 |
Degrees added per Ctrl+Up / Ctrl+Down. |
zoom_step |
1.02 |
Scroll-wheel zoom multiplier. |
max_zoom_percent |
1000 |
Maximum zoom level, stored as percent. |
| Key | Default | Meaning |
|---|---|---|
manga_drag_pan_speed |
1.0 |
Drag-pan multiplier for multi-item layouts. |
manga_wheel_impulse_per_step |
2400.0 |
Velocity injected per wheel step. |
manga_wheel_decay_rate |
11.0 |
Exponential decay for free wheel momentum. |
manga_wheel_max_velocity |
9000.0 |
Cap on accumulated wheel velocity. |
manga_wheel_edge_spring_hz |
4.5 |
Edge return stiffness for overscroll. |
manga_inertial_friction |
0.33 |
Inertial target friction for keyboard / page / autoscroll movement. |
manga_arrow_scroll_speed |
140 |
Base arrow-key pan distance. |
masonry_items_per_row |
5 |
Number of columns in Masonry mode. |
manga_hover_autoplay_resume_delay_ms |
220 |
Delay before Masonry hover autoplay resumes after movement settles. |
manga_virtualization_backend |
rtree |
auto, linear, or rtree. Default is the R-tree path. |
manga_autoscroll_dead_zone_px |
14.0 |
Freehand autoscroll dead zone around the anchor. |
manga_autoscroll_base_speed_multiplier |
5.0 |
Base autoscroll multiplier relative to arrow-scroll speed. |
manga_autoscroll_min_speed_multiplier |
0.6 |
Lower speed multiplier bound. |
manga_autoscroll_max_speed_multiplier |
14.0 |
Upper speed multiplier bound. |
manga_autoscroll_curve_power |
2.0 |
Speed curve power from center to edge. |
manga_autoscroll_min_speed_px_per_sec |
80.0 |
Absolute minimum autoscroll speed. |
manga_autoscroll_max_speed_px_per_sec |
14000.0 |
Absolute maximum autoscroll speed. |
manga_autoscroll_horizontal_speed_multiplier |
1.0 |
Horizontal autoscroll multiplier. |
manga_autoscroll_vertical_speed_multiplier |
1.0 |
Vertical autoscroll multiplier. |
manga_autoscroll_circle_fill_alpha |
50 |
Fill alpha of the autoscroll anchor ring. |
manga_autoscroll_arrow_rgb |
140, 190, 255 |
Arrow color for the autoscroll indicator. |
manga_autoscroll_arrow_alpha |
50 |
Arrow alpha for the autoscroll indicator. |
| Key | Default | Meaning |
|---|---|---|
muted_by_default |
true |
Start videos muted. |
default_volume |
0.0 |
Initial video volume. |
loop |
true |
Restart videos automatically at end-of-stream. |
seek_policy |
adaptive |
adaptive, accurate, or keyframe. |
prefer_hardware_decode |
true |
Prefer D3D11 decoders when available on Windows. |
disable_hardware_decode |
false |
Disable hardware decoders completely. Overrides prefer_hardware_decode. |
| Key | Default | Meaning |
|---|---|---|
upscale_filter |
catmullrom |
CPU resize filter for enlarging images. |
downscale_filter |
lanczos3 |
CPU resize filter for shrinking images. |
gif_resize_filter |
triangle |
CPU resize filter for GIF frames. Uses a faster default for animation throughput. |
texture_filter_static |
linear |
GPU texture filtering for static images. |
texture_filter_animated |
linear |
GPU texture filtering for GIF / animated WebP textures. |
texture_filter_video |
linear |
GPU texture filtering for video textures and video thumbnails. |
manga_mipmap_static |
true |
Enable mipmaps for static textures in Long Strip / Masonry. |
manga_mipmap_video_thumbnails |
true |
Enable mipmaps for video first-frame thumbnails in Long Strip / Masonry. |
manga_mipmap_min_side |
128 |
Minimum texture side before mipmaps are generated. |
Supported filter values:
- Scaling filters:
nearest,triangle,catmullrom,gaussian,lanczos3 - Texture filters:
nearest,linear - Virtualization backends:
auto,linear,rtree - Startup window modes:
floating,fullscreen - Video seek policies:
adaptive,accurate,keyframe
Performance here comes from layering several smaller systems: metadata-first opening, persistent and in-memory caches, latest-only async coordinators, bounded worker queues, R-tree viewport queries, LOD-bucketed texture requests, selective mipmaps, and adaptive upload/caching policy for Long Strip and Masonry.
For the full startup flow, module-by-module design, cache hierarchy, optimization catalogue, and third-party crate map, see ARCHITECTURE.md.
Set show_fps = true to enable the top-right overlay.
Useful labels:
| Label | Meaning |
|---|---|
FPS |
Smoothed render FPS and last active-frame time. |
TTV p50/p95 |
Time to visible for multi-item media. |
U |
Current upload batch limit. |
L |
Pending load requests, plus peak. |
D |
Pending decoded images, plus peak. |
V |
Visible item count, plus peak. |
IDX H/M |
Directory-index cache hits / misses. |
DC H/M |
Decoded-image cache hits / misses. |
MC ... |
Metadata-cache hits, misses, expirations, and evictions. |
UP p95 |
Upload pass p95. |
QW p95 |
Decode queue-wait p95. |
DEC p95 |
Decode worker p95. |
RSZ p95 |
Resize p95. |
UTX p95 |
Texture-upload p95. |
LY p95 |
Masonry layout rebuild p95. |
SI p95 |
Spatial-index rebuild p95. |
VQ p95 |
Visible-query p95. |
VQ R/L |
R-tree vs linear visible-query counts. |
DQ |
Pending Masonry dimension updates. |
DM |
Decoded mailbox size. |
RR |
Retry requests enqueued / rejected. |
TS L/M/H |
Low / mid / high target-side distribution. |
The repository ships Criterion benchmarks for:
directory_scandirectory_index_cachegif_decode_120_framesrtree_strip_queryrtree_masonry_queryrtree_rebuild
Run them with:
cargo benchCriterion HTML reports are written under target/criterion/.
When comparing performance changes, keep the scenario fixed:
- Build a release binary.
- Enable
show_fps = true. - Open the same dense mixed-media folder for every run.
- Test the same
masonry_items_per_rowvalues, such as3,5, and10. - Repeat the same gestures: slow wheel scroll, fast wheel scroll, scrollbar drag, and zoom changes.
- Record
FPS,TTV,UP p95,QW p95,DEC p95,RSZ p95,UTX p95,VQ p95,RR, andTS L/M/H.
That keeps branch-to-branch comparisons honest.
Failed to create video pipelineusually means the GStreamer playback elements were not found. Install the runtime and verify plugin discovery.- If decode is unstable on your system, set
disable_hardware_decode = true. - If you want hardware decode but it is not being selected, keep
prefer_hardware_decode = trueand verify a compatible Windows decoder is available. - If the app was launched from an environment with a stale
PATH, restart it after installing GStreamer so the refreshed environment and plugin registry can be rebuilt.
- Delete
config.inito regenerate the latest default template. - If you are migrating from very old versions, legacy config file names are imported automatically.
- If a shortcut is interfering, set that action's value to an empty string to disable its default binding.
- If metadata or thumbnails seem stale, delete
%LOCALAPPDATA%\rust-image-viewer\metadata_cache.redb. - If you want to cap disk usage more aggressively, lower
metadata_cache_max_size_mb.
pkg-configerrors usually meanPKG_CONFIG_PATHis not pointing at GStreamer'spkgconfigdirectory.- Linker errors usually mean the GStreamer development package is missing.
MIT License. See LICENSE for details.