Floki is a fast, hardware-accelerated Rust GUI application tailored for Technical Directors, Compositors, and LookDev Artists who need to deeply inspect and compare multi-layered OpenEXR files.
Powered by egui, wgpu, and the pure-Rust exr crate, it allows you to instantly view dense pixel data, isolate color channels, explore unbounded floating-point histograms, and perform pixel-perfect A/B diffing — all rendered natively on your GPU — as well as play image sequences in real time.
- Vulkan/Metal/DX12 Backend: All image exposure scaling, gamma correction, sRGB mapping, and A/B difference matte compositing are executed via custom WGSL shaders on the GPU.
- GPU-Required Pipeline: All rendering runs on the GPU via
wgpu(Vulkan/Metal/DX12); a working GPU and driver are required to launch. (An internal CPU render path exists for contact-sheet thumbnails and headless tests — it is not a runtime fallback for a missing GPU.)
Open one frame of a numbered sequence (e.g. render.0101.exr) and play the whole shot — Floki is a review player, not just a still viewer.
- Transport & timeline: Play/pause, step, reverse, and stop-in-place, with a scrubber/timeline that highlights the trimmed region and marks any missing frames (holes). Editable target fps with a live measured-fps readout.
- Loop & pacing: Loop, Once, or Ping-Pong; choose Stutter (play every frame; fps drops under load) or Drop-frames (hold the wall-clock rate; skip frames) pacing.
- In/out trim: Set in/out points to review just a section — the cache and playback respect the trim.
- Smart cache: A byte-budgeted ring keeps decoded frames resident in RAM and pre-uploaded to the GPU within a live memory budget, so scrub-backs and loops are instant and playback degrades gracefully instead of crashing under memory pressure.
- Beauty-only fast decode: While playing, only the beauty/first layer is decoded for a much faster, lighter cache on heavy multi-part AOV EXRs; the paused frame re-decodes in full so the pixel readout and AOV switch stay accurate.
- Eager precache: Optionally cache the whole in/out range up front — a green fill bar under the scrubber shows what's resident — so the span plays and loops with the decoder idle.
- Live render-watch: Watch the sequence folder and pick up frames as a render writes them (new frames extend the range; re-rendered frames refresh), optionally parking the playhead on the newest frame.
Real-time sequence playback — the scrubber highlights the trimmed in/out region, the green bar shows the cached range, and target/measured fps read out live.
- Precision Pixel Sampling: Hover over any pixel to reveal exact floating-point values (R, G, B, A) regardless of bit-depth (F16, F32, U32).
- Persistent Swatches:
Shift + Clickon the image to drop a permanent color swatch into your toolbelt for cross-referencing. - Metadata Explorer: Cleanly displays embedded EXR attributes (like V-Ray/Arnold custom tags), layers, and bounding box data in collapsible panels for both Image A and Image B simultaneously.
- Dual Contact Sheets: Instantly view all AOVs (Arbitrary Output Variables) and layers as a scrollable grid of thumbnails. If a second image is loaded, view dual synchronized contact sheets side-by-side or seamlessly toggle between them.
Dual contact sheets — every AOV and layer as a thumbnail grid, kept in sync across Image A and Image B.
Load a Reference Image (Image B) to unlock advanced visual diffing:
- Wipe: Split-screen slider for boundary checks — with adjustable center, rotation angle, and divider-line opacity for wipes at any orientation.
- Side-by-Side: View Image A and Image B glued together in a continuous panorama. They share the same camera for synchronized panning and zooming.
- Diff Matte: Renders the magnitude of
A − Bas a false-colour heat map to spot fractional floating-point discrepancies in your render pipelines. Choose the colormap (black-body, grayscale, turbo, viridis, magma, inferno) or build a custom multi-stop gradient in the editor; select the magnitude metric (max channel, Rec.709 luminance, or per-channel RGB); set a noise-floor threshold to ignore sub-threshold noise; and read values off the on-screen legend. - Composite: Blend A over B directly in-viewport with selectable blend modes (Over, Under, Add, Multiply, Screen).
- Blink Mode: Press
Spacebarto strobe between Image A and Image B at an adjustable interval.
Comparison controls follow a two-tier toolbar: the everyday controls stay on a single row, while the active mode's parameters slide into a contextual second row only when needed.
Wipe compare mode — drag the divider at any angle to check Image A against Image B.
Side-by-side — Image A and Image B share one camera for synchronized panning and zooming.
Diff matte — the magnitude of A − B as a false-colour heat map, with the value legend on-screen.
- Dynamic Luminance Histogram: Real-time histogram mapped to Exposure Values (EV stops). Effortlessly spot floating-point highlights over
1.0using the Logarithmic view. - Dual Histogram Mode: When comparing two images, the histogram overlays a translucent Red graph (Image B) on top of the White graph (Image A) so you can visually align black levels.
- Channel Isolation: Quickly isolate
R,G,B,A, or viewRGBcomposite with single-key shortcuts.
Dual EV histogram — Image B (translucent red) overlaid on Image A (white) to align black levels and catch highlights over 1.0.
- OpenColorIO (built in): OCIO is compiled into every build — there is no non-OCIO build. Point Floki at a config and pick the display/view transform to see your footage in the right space; it auto-enables when a config loads and can be toggled on/off from Color Management. The transform runs on the GPU and can optionally be baked to a 3D LUT for smoother pan/zoom on weaker GPUs.
- 3D LUT Support: Load Adobe
.cube3D LUTs and apply them in real time on the GPU as a display transform, alongside the built-in Exposure/Gamma/sRGB controls.
Color Management — point Floki at an OCIO config and pick the display/view transform; the transform runs on the GPU.
- Background Modes: Replace the default transparency checkerboard with a checkerboard (custom cell colours and size), a solid colour, or a multi-stop gradient at any angle — set from View ▸ Viewport Background. Save named presets that persist across sessions. The background composites consistently across the GPU and OCIO display paths.
| Checkerboard | Solid | Gradient |
|---|---|---|
![]() |
![]() |
![]() |
- Snapshot to Clipboard: Copy exactly what's on screen to the system clipboard with
Cmd/Ctrl + Shift + S(or View ▸ Snapshot to Clipboard) — background, compare mode, OCIO, and annotations all included. Optionally also save a timestamped PNG to~/.floki/snapshots/. - Annotation Overlay: Mark up the view with arrows, boxes, a freehand pen, and text labels (adjustable colour and stroke width) before snapshotting. Annotations anchor to image pixels so they track pan/zoom, support undo/redo and clear-all, and are flattened into the snapshot automatically.
Annotation overlay — arrows, boxes, freehand pen, and text labels anchor to image pixels and flatten into the snapshot.
- EXR Header Converter: Bulk-rename channels across an entire directory to standard RGBA — available both as an in-app Tools window and a headless
convert_dirCLI, parallelized across CPU cores viarayonwith live progress and cancellation.
- Immediate-Mode UI: Built on
eguifor a responsive, minimal-overhead interface. - Light / Dark / System Themes: Switch the interface theme from the Theme menu; the
Systemoption tracks your OS light/dark setting live. Your choice persists across sessions. - Recent Files for A & B:
File ▸ Open Recent A/Open Recent Breload a recent EXR straight into the main or reference slot. - Drag & Drop Loading: Drop an EXR onto the window to load it — the left half loads it as Image A, the right half as the reference Image B, with a live overlay highlighting which side will receive the drop. Drop two files at once to fill A and B together.
- Persistent State: Remembers your UI layout, recent files list, theme, and preferences across sessions.
- Software Tone Mapping: Apply Exposure, Gamma, and sRGB transforms instantly without altering the underlying raw data.
- Resource Monitor: A discrete status-bar readout tracks floki's own memory footprint and system RAM, plus live GPU VRAM usage on macOS — handy when loading heavy EXRs or sequences. It samples about once a second and tucks into the bottom-right. (The VRAM figure is macOS/Metal only for now; Windows and Linux show RAM.)
| Shortcut | Action |
|---|---|
F |
Frame Image (Reset Zoom & Pan to fit screen) |
R |
Isolate Red Channel |
G |
Isolate Green Channel |
B |
Isolate Blue Channel |
A |
Isolate Alpha Channel |
C |
View Full RGB (Color) |
1 |
View Image A (when B is loaded) |
2 |
View Image B (when B is loaded) |
Space |
Play / pause the sequence — or, with no sequence loaded, toggle Blink Mode (requires a reference Image B) |
← / → |
Step one frame back / forward (sequence) |
I / O |
Set the in / out trim point to the playhead (sequence) |
Cmd/Ctrl + Shift + S |
Snapshot the current view to the clipboard |
Esc |
Cancel the active annotation tool (or exit fullscreen) |
Shift + Click |
Sample pixel and save to swatch palette |
Scroll Wheel |
Zoom in/out at cursor |
Click + Drag |
Pan Image |
Drag & Drop |
Load EXR — drop on left half → Image A, right half → Image B |
Make sure you have Rust and Cargo installed on your system.
# Clone the repository
git clone https://github.com/byvfx/floki.git
cd floki
# Build and run — needs no OpenColorIO installed (see the tiers below)
cargo run --release --no-default-featuresOn a clean machine, use
--no-default-features. The default build links an installed OpenColorIO and fails at build time if it can't find one. The flag selects the pure-Rust stub backend — no native dependencies, no C++ toolchain — which is also what CI builds and lints. Colour management is then limited to the built-in transforms; see the three tiers below to get full OCIO.
OCIO support is always compiled — it is mandatory, not an opt-in feature. What you choose
is the backend, and there are three tiers. A bare cargo run uses the system backend, which
is why it fails on a machine with no OCIO installed.
| Tier | Command | Needs | Gets you |
|---|---|---|---|
| Stub | cargo run --release --no-default-features |
nothing beyond Rust | Builds and runs anywhere. Built-in transforms only — no .ocio config support. This is what CI builds, lints and tests. |
| System (default) | cargo run --release |
an installed OCIO | Full OCIO, fast builds, no cmake |
| Vendored | cargo ocio-run |
C++ toolchain, cmake, ninja, python3 | Full OCIO, self-contained — what the release binaries ship |
Fast dev — link an installed OCIO (system, the default): a plain cargo run --release
links an OCIO found via OPENCOLORIO_ROOT (any OS) or Homebrew (macOS). Fast, no cmake.
cargo run --releaseRecommended for distribution — self-contained (vendored): statically builds OCIO 2.4.2 from the vendored submodule, so nothing needs to be installed system-wide. Works the same on Windows, Linux, and macOS. The first build is slow (minutes); then it's cached.
# One short command on any OS (cargo alias from .cargo/config.toml):
cargo ocio-run
# …or, to also init the submodule in one shot (requires `just`):
just ocioPrerequisites: a C++ toolchain (MSVC "Desktop development with C++" on Windows; clang/gcc
elsewhere), cmake ≥ 3.14, ninja, python3, and the OCIO submodule checked out
(git submodule update --init --recursive — done automatically by just ocio).
Once running, enable it in Color Management… (check Enable OCIO). With the config-path
field empty it uses the built-in ACES config, or $OCIO if that environment variable is set
(e.g. OCIO=ocio://studio-config-latest). See floki-ocio/README.md
for backend/build details.
Because OCIO (and its shaderc dependency) build native code, a Windows dev box needs
cmake + ninja + python + the MSVC toolchain on PATH, plus a prebuilt OpenColorIO to
link against for the default system-ocio backend. Those tools usually exist but aren't on
PATH (cmake/ninja ship inside Visual Studio 2022; python via Anaconda). The helper script
assembles that environment (imports vcvars64, prepends the bundled tools, points
system-ocio at a vcpkg OCIO) and then runs cargo:
scripts\run-windows.ps1 test # fmt --check, clippy -D warnings, cargo test
scripts\run-windows.ps1 # cargo run --release (default task)
scripts\run-windows.ps1 run -- "D:\shots\comp.exr"Paths default to a common layout and are overridable via FLOKI_VCPKG, FLOKI_ANACONDA,
and FLOKI_VSPATH. It's a local dev convenience only — CI does not use it.
The app initializes env_logger, so runtime logging is
controlled by the RUST_LOG environment variable. Launch the app from a terminal so
log output (written to stderr) is visible.
# PowerShell — watch the EXR Header Converter work through a batch
$env:RUST_LOG = "floki=debug"
cargo run --release# bash / zsh
RUST_LOG=floki=debug cargo run --releaseUseful levels (prefix the target with floki= to filter out noisy wgpu/eframe logs):
RUST_LOG value |
What you see |
|---|---|
floki=info |
Conversion start line, final summary (N of X files converted), and any errors |
floki=debug |
The above plus a line per converted file and any layer left unchanged by the rename guard |
info |
Everything at info level, including wgpu/eframe startup |
floki=info,wgpu=warn |
App info logs while silencing graphics-backend chatter |
Note: During batch conversion, files are processed in parallel across CPU cores, so per-file log lines appear interleaved/out of order. The count in the final summary is authoritative.
A birds-eye view of the workspace. The app ships as a single binary backed by a
library crate (so benches and integration tests can reach the internals), plus a
standalone floki-ocio crate that wraps OpenColorIO.
App shell
main.rs— entry point andeframe/wgpuinitialization.app.rs— the top-leveleframe::App: window and menus, async EXR + LUT loading, snapshot capture, persistence, and the panel layout that hosts the viewer.resource_monitor.rs— throttled RAM / GPU-VRAM sampler feeding the status-bar readout.
Image data
exr_loader.rs— threaded OpenEXR decode and logical-layer grouping via theexrcrate (the load hot path the benches exercise).
Viewer & rendering
viewer.rs— the heavy lifter: canvas pan/zoom, the six compare modes, pixel sampling, histograms, contact sheets, and the GPU render path (plus a CPU path used for contact-sheet thumbnails and headless tests, not as a missing-GPU fallback).gpu/— thewgpubackend:mod.rs(pipelines, uniforms, bind groups),shader.wgsl(the display / compare / diff / background fragment shader), andocio_pass.rs(the two-pass OCIO display transform and blit).render_math.rs— shared tone-mapping math (exposure / gamma / sRGB), unit-tested in one place.
Visualization & overlays
gradient.rs— reusable multi-stop gradients and the diff colormaps (shared by the heat map and the gradient background).background.rs— the customizable viewport background (checker / solid / gradient), sampled identically across every render path.annotation.rs— the transient arrow / box / pen / text overlay model.snapshot.rs— framebuffer-screenshot capture plus the clipboard / PNG helpers.
Color management
color/cube.rs— Adobe.cube3D-LUT parsing.floki-ocio/— a standalone crate wrapping OpenColorIO over FFI, with a GLSL→WGSL shader transpiler; always linked (thesystem-ocio/vendoredfeatures select the native backend).
Sequence playback
sequence.rs— numbered-sequence detection: parsing, numeric sort, and hole detection.playback.rs— the transport state machine (playhead, loop modes, in/out trim, pacing) and the pure frame-advance logic.scheduler.rs— the pure decode want-list / next-frame scheduler (priority order, prefetch window).cache.rs— the byte-budgeted T1 ring of decoded frames with directional-ring + LRU eviction.budget.rs— the RAM budget math sizing the T1 ring from a live memory sample.pixels.rs— pure pixel access over decoded EXR channels + thumbnail decimation.prefetch.rs— read-ahead file warmer; overlaps the next frame's file read with the current decode via the OS page cache.proxy_cache.rs— persistent on-disk proxy cache (~/.floki/proxy-cache), so a scrub proxy's first-touch decode is paid once ever.tex_upload.rs— off-thread comp-texture upload; the paint thread submits a frame and collects a finished GPU texture instead of interleaving and uploading inline.layer.rs— the pure comp layer-stack model backing A/B compare (the spine for N-way / locked-step).
Tooling & CLI
tools.rs— the multi-threaded EXR Header Converter (batch channel renaming viarayon) with progress reporting andRUST_LOGlogging.bin/— headless helpers:convert_dir(batch rename),inspect_exr, andcheck_types.
This project is licensed under the MIT License - see the LICENSE file for details.



