A fast, pixel-art-first image browser for Linux/macOS/Windows, written in Rust with egui/eframe.
I wrote this to accompany my https://github.com/grymmjack/pixelmon so I could easily see my generated AI art and rate it fast. Needless to say, things got a little...
It decodes everything from PNG and Photoshop files to Commodore PETSCII and EGA
vector RIPscript, browses inside archives (.zip/.lha/.arj/…), and can mount
16colo.rs — the online ANSI archive — as a virtual folder.
Think Gwenview for pixel art and the BBS scene: crisp nearest-neighbor zoom, palette-preserving decoders, a virtualized thumbnail grid, and first-class support for ANSI / PETSCII / RIPscript and the rest of the demoscene / textmode art world — right down to baud-rate "watch it type" playback and CRT effects.
- Highlights
- Supported formats
- Install & build
- Quick start
- Feature tour
- Keyboard shortcuts
- Command-line options
- Menu reference
- Settings & where things are stored
- Bundled palettes
- Architecture
- Development
- Credits
- License
- 30+ image & scene-art formats, including palette-preserving PCX, Aseprite, PSD, GIMP XCF, SVG, and the full demoscene/textmode set (ANSI, XBin, PETSCII, RIPscript, and more).
- Pixel-perfect zoom — nearest-neighbor textures, snapped to whole device pixels so dithering never warps, even on fractionally-scaled (HiDPI) displays.
- Virtualized thumbnail grid that scrolls smoothly through folders of thousands of images, with independent Ctrl+wheel tile sizing and configurable captions.
- Recolor pane — a reorderable 15-stage adjustment + palette-rematch + dither pipeline (brightness/contrast/gamma/hue/vibrance/posterize/invert/… → palette snap → dithering), with live preview and export.
- A library of 55 bundled palettes (CGA, EGA, VGA, Game Boy, NES, C64, PICO-8,
DawnBringer, Endesga, …) plus
.GPLimport/export. - Star ratings stored as KDE Baloo xattrs (interoperate with Gwenview), with a cross-platform sidecar so even art inside a zip or on 16colo.rs is ratable.
- Recursive advanced search (name / type / dimensions / size / date / rating / SAUCE text) on a background thread, plus saveable "smart filters."
- Browse archives and the online ANSI scene as if they were folders.
- The BBS aesthetic, faithfully: SAUCE-aware textmode rendering, authentic IBM VGA & C64 fonts, baud-rate ANSImation/RIP playback, CRT scanlines, phosphor glow, 9-dot VGA cells, slideshow, an immersive fullscreen mode, and a random-pack screensaver.
Files are recognized by content (magic bytes) first, then extension — so a mislabeled file still opens if its header is known. A folder listing is filtered down to the extensions a decoder claims.
| Category | Formats | Notes |
|---|---|---|
| Raster (image crate) | PNG, GIF, BMP, JPEG, WebP, TGA, TIFF, PNM/PBM/PGM/PPM, QOI, ICO | |
| Palette-preserving | PCX | Original indices + palette kept, not flattened |
| Editor formats | Aseprite (.aseprite / .ase), Photoshop PSD, GIMP XCF |
Composited / flattened to frame 0 |
| Vector | SVG | Rasterized via resvg |
| Misc | .draw | PNG preview |
| ANSI / ASCII art | .ans .asc .nfo .diz .ice .cia |
CP437 + ANSI SGR/cursor, iCE colors, SAUCE-driven cell size |
| Binary scene art | XBin (.xb / .xbin), raw BIN (.bin), TundraDraw (.tnd, 24-bit), iCE Draw (.idf), Artworx (.adf) |
|
| Commodore | PETSCII (.seq / .pet), petmate (.petmate) |
Authentic C64 font + VIC-II palette |
| BBS vector | RIPscript (.rip) |
640×350 EGA, hand-rolled BGI rasterizer |
| Animation | Animated GIF | Plays in the viewer; hover-to-play in the grid |
| Archives (virtual folders) | .zip .lha .arj .arc .zoo .7z .rar … |
Browsed read-only; contents extracted on demand |
Scene-art formats are decoded with SAUCE metadata awareness (the standard trailer ANSI artists use to record title/author/group/dimensions), shown in the Details pane.
You need a Rust toolchain (stable).
git clone <this-repo>
cd pixelview
cargo run --release # build + launch (release is recommended: nearest-neighbor
# rendering wants the GPU/wgpu path)Or build the binary and run it directly:
cargo build --release
./target/release/pixelview --folder ~/Picturessudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
libxkbcommon-dev libssl-deveframe uses the wgpu backend by default — that's what gives the pixel-perfect nearest-neighbor textures, and it runs fine on KDE Plasma 6 / Wayland.
To register a real application icon and .desktop entry (so KDE/Wayland shows a
proper task-switcher icon), run:
./install-icon.shIt installs pixelview.desktop + the app icon into ~/.local/share. The entry's
StartupWMClass=pixelview matches the window's app-id so the icon maps correctly.
- Launch
pixelview(optionally with--folder PATH). - The thumbnail grid shows the current folder. Click a folder tile to descend,
or use the breadcrumbs / Go menu /
Backspaceto go up. - Click an image to open the single-image viewer.
←/→step through the folder;Escreturns to the grid. - Ctrl + mouse-wheel resizes thumbnails in the grid, or zooms the image in the
viewer. In the viewer, hold
Z+ a digit jumps to an exact zoom. - Press
/to filter the grid by filename, or Ctrl + F for full recursive search. - 1–5 rate the current image (
0clears), drag favorites into the toolbar, and open the Recolor pane (View menu) to remap palettes.
Everything you change — zoom, thumbnail size, theme, favorites, last folder, sort order, CRT toggles, baud rates — is remembered between runs.
- Breadcrumb path with clickable segments, plus a current-path bar.
- Drag-reorderable favorites in the top toolbar — drag to rearrange,
right-click to remove, or pin any folder via its grid context menu / the Go
menu.
🏠 Homeand⬆ Upare always available. - Left activity rail (VSCode-style) of icon toggles for the docks.
- Explorer dock — an expandable, lazy-loading folder tree with a filter box (collapsed nodes do no disk I/O).
- Details dock — a live fit thumbnail of the selection, its metadata, palette
swatches, and a
.GPLpalette export button. - Mouse back/forward buttons navigate folder history in the grid, or step images in the viewer.
- Virtualized — only the visible rows are ever built, so a folder with tens of thousands of files stays responsive.
- Background thumbnailer — N worker threads (one per core) decode + scale off the UI thread; the most-recently-scrolled-into-view tiles are prioritized.
- Independent tile sizing via Ctrl + wheel (separate from the UI zoom).
- Configurable captions — choose which fields show under each tile (filename, dimensions, size, …) and how many lines, with independent horizontal/vertical grid spacing (Preferences).
- Folder tiles render a montage of the images inside them, plus a count badge — recursively.
- Multi-select with Ctrl+click (toggle) and Shift+click (range);
Home/Endjump to the first/last item.
- Nearest-neighbor zoom with drag-to-pan, and a minimap/navigator on huge images.
- Two zoom modes: raster art keeps a logical
%zoom remembered across images; textmode/scene art uses device-pixel scale (N×) so it stays crisp on HiDPI. - Fit to window (
F) is sticky — toggle it on and every newly opened image auto-fits. Fit W re-fits to viewport width. Tile preview (T) fills the window with the tiled image for seamless-texture testing. - Huge images beyond the GPU texture limit are uploaded as a tile grid and shown at full resolution.
pixelview goes out of its way to keep pixel art exact:
- Source-resolution thumbnails and the viewer upload
NEARESTtextures so upscaling never smears. - On downscale, thumbnails are area-averaged (box filter) instead of point-sampled — single-sampling a 50% dither would alias it into fake noise.
- For pixel-perfect modes the blit is snapped to whole device pixels per source pixel and aligned to the device grid, because fractional desktop scaling (e.g. 1.3× HiDPI) would otherwise duplicate some source rows more than others and warp the dithering.
A non-destructive image pipeline (View → Recolor pane) whose stage order is fully user-controlled — drag the grip handle or use ⬆/⬇ to reorder:
- 12 adjustment ops: brightness, contrast, gamma, shadows, highlights, posterize, hue, saturation, vibrance (protects already-vivid colors), pixelate, sharpen, and invert (blend toward negative for partial solarize).
- Palette remap — snap the image to any bundled or loaded palette.
- Dithering — ordered/Bayer, an editable custom matrix, or error-diffusion (Floyd–Steinberg / Atkinson). Because dither is a separate stage, you can place it before posterize for dithered banding with no palette snap.
- Color balance — per-channel R/G/B offset from a picked color or hex value.
- Reduce — quantize the palette to N colors.
- Live preview, with the result applied to grid tiles too; Export the palette as
.GPLor Save the recolored image.
- 55 palettes bundled into the binary (no external files needed) — see the full list.
- Load your own
.GPLfiles from a configurable palette directory (they add to the bundled set). - Export any image's palette to
.GPLfrom the Details or Recolor pane. - Palette-based formats (PCX, etc.) preserve their original indices + palette, so recoloring and accurate re-export work on the real palette, not a guessed one.
- 1–5 sets a rating, 0 clears it.
- Stored as the KDE Baloo
user.baloo.ratingextended attribute — the same scheme Gwenview uses, so ratings made here show up there (and vice-versa). - A cross-platform
ratings.jsonsidecar mirrors them, which is what makes art inside a zip or on 16colo.rs — which has no real on-disk file — ratable at all. The rating survives re-extraction because it's keyed by the stable display path. - Sort or filter the grid by rating.
/— quick vim-style filename filter over the current folder.- Ctrl + F — advanced recursive search across the whole subtree, on a background thread (cancellable, results stream in live). Filter by any combination of: filename, extension list, width/height min-max, file size, modified-date range, minimum ★, and SAUCE text. Result tiles show where each hit lives.
- Smart filters — save a search as a reusable named filter (e.g.
*.ans · sauce:acid); they appear in the Places dock and re-run from the current folder on click. - Smart filter on… — right-click any file to seed a fresh search from one of its attributes (its type, a word from its name, ±20% of its size, its date, its rating, or its SAUCE group/artist).
Full file management, with undo:
- Copy / Cut / Paste, New folder, Rename, and Move to trash (via the system trash) — from the right-click context menu, the Edit menu, or shortcuts.
- Ctrl + Z undoes the last operation (trash restore, move-back, delete a created folder, or remove pasted copies).
- Archives as virtual folders — open a
.zip/.lha/.arj/.arc/.zoo/.7z/.rar/ … and browse inside it; contents are extracted on demand to a temp dir. - 16colo.rs as a virtual disk — a Places entry with a nav bar (Years / Latest / Groups / Artists, plus a server-side Search across artists + groups). Drill in to Packs, and pack art is auto-downloaded and shown like any local folder.
The textmode/BBS side is the heart of pixelview:
- Authentic fonts — the real IBM VGA CP437 ROM (8×16 and an 8×8 VGA50 variant) and a C64 character ROM, so block/shade/line-draw glyphs are exact.
- SAUCE-driven layout — cell size (8×8 VGA50 / EGA43 vs 8×16), iCE colors, and canvas width come from the file's SAUCE record.
- 9-dot VGA cell (toggle) — renders the 8-pixel glyph in a 9-wide cell the way real VGA text mode did (the 9th column repeats for line-draw chars so box rules join). This is why output matches ansilove / 16colo widths.
- Baud-rate playback — watch ANSI art and RIPscript draw themselves at an authentic modem speed (300 baud crawl → 115.2k). Pick a rate in the status bar; the view auto-scrolls BBS-style to follow the cursor. ANSI and RIP remember independent speeds.
- CRT aspect (toggle) — stretches textmode art ~1.2× vertically to match non-square VGA pixels (80×25 → 4:3), snapped to integer device pixels so it stays crisp.
- Phosphor glow + retro scanlines (with adjustable darkness and a "scale with zoom" option) + optional black background — composable CRT-monitor effects.
- Immersive mode (
F11) — OS fullscreen with every panel hidden; bars reveal when the mouse reaches a screen edge, and the cursor auto-hides after ~1.5s. - Slideshow — auto-advance through a folder (1/3/5/10s), waiting for any baud transmission to finish first.
- Random-pack screensaver —
🔀 Random pack(or R) jumps to a random 16colo.rs pack; with Shuffle on it chains endlessly. Pair withF11for a screensaver of real scene art.
Animated GIFs play in the viewer (autoplay + frame seek) and play on hover in the thumbnail grid.
The four navigation keys are rebindable in Preferences → Hotkeys (press
Rebind, then the new key; Esc cancels). Their defaults:
| Key | Action | Where |
|---|---|---|
← |
Previous image | Viewer |
→ |
Next image | Viewer |
Esc |
Back to grid | Viewer |
Backspace |
Parent folder | Anywhere |
The rest are fixed (this is the same list shown in Help → Keyboard shortcuts):
| Key | Action |
|---|---|
Ctrl + / Ctrl - |
Zoom the whole UI |
Ctrl + Wheel / pinch |
Resize thumbnails (grid) · zoom image (viewer) |
Wheel |
Viewer: previous / next image · Grid: scroll |
| Mouse Back / Fwd | Grid: folder history · Viewer: prev / next image |
Home / End |
Grid: select first / last |
/ |
Grid: filter by filename |
Ctrl + F |
Open advanced recursive search |
Drag |
Pan the image (viewer) |
F |
Fit to window + auto-fit new images (viewer) |
T |
Tile preview — fill window (viewer) |
F11 |
Immersive / fullscreen |
1 – 5 |
Set star rating |
0 |
Clear rating |
R |
Jump to a random 16colo.rs pack |
Click |
Open image / enter folder |
Ctrl + Click |
Toggle selection |
Shift + Click |
Range-select |
Right-click |
Grid: file-operations menu |
Ctrl + C / X / V |
Copy / Cut / Paste |
Ctrl + N |
New folder |
F2 |
Rename |
Delete |
Move to trash |
Ctrl + Z |
Undo last file operation |
Zoom chord (viewer): hold Z and press a digit to jump to an exact zoom —
1–9 = 100%–900%, 0 = 1000%. For textmode/scene art the digit means device
pixels per source pixel (e.g. Z+3 = 3×). Z + +/= and Z + - step the
zoom ladder. (Holding Z suppresses the 1–5 rating keys.)
pixelview — a pixel-art-first image viewer
USAGE:
pixelview [OPTIONS]
OPTIONS:
-f, --folder <PATH> Open this folder on launch
-t, --thumbnail-size <SIZE> Thumbnail tile size: a number (e.g. 160) or
WxH (e.g. 120x160 — tiles are square, so the
larger dimension is used)
-h, --help Print this help
--thumb-size is accepted as an alias of --thumbnail-size. Settings passed on
the command line override the persisted ones and are remembered afterward.
| Menu | Items |
|---|---|
| File | Open folder… · Quit |
| Edit | ↩ Undo · Copy · Cut · Paste · New folder · Rename… · Move to trash · Find images… (Ctrl+F) |
| View | Explorer pane · Details pane · Recolor pane · Reset thumbnail size · Preferences… |
| Sort | Name · Type · Modified · Created · Size · Rating · Colors · Descending · Directories first |
| Go | ⬆ Up · 🏠 Home · (your pinned favorites) |
| Help | Keyboard shortcuts |
Preferences covers theme (Dark/Light), grid spacing, caption fields, the default textmode zoom, the palette directory, and the rebindable Hotkeys.
- Settings persist via eframe's storage at
~/.local/share/pixelview/(Linux). Each setting (zoom, thumbnail size, favorites, last folder, sort/filter, dock visibility, grid spacing, captions, keymap, CRT/baud/look toggles, …) is its own key. - Ratings live in two places: the
user.baloo.ratingxattr on real files (for Gwenview interop) and a portableratings.jsonsidecar in the data dir (for virtual art and non-Linux platforms). - Palettes are embedded in the binary; an optional user palette directory adds
more
.GPLfiles on top.
55 .GPL palettes ship inside the binary (color count in parentheses):
1BIT (2) EGA (16) NES (55)
2BIT (4) ENDESGA-16 (16) PICO-8 (16)
6BIT (64) ENDESGA-32 (32) PICO-8-SECRET (32)
AMSTRADCPC (26) ENDESGA-36 (36) PINEAPPLE-32 (32)
ANSI32 (32) ENDESGA-64 (64) QUAKE (244)
APPLE2-HIRES (6) FAIRCHILD (8) SECAM (8)
APPLE2-LORES (16) FUNKYFUTURE (8) SEGA (64)
ATARI-8BIT (256) GAMEBOY (4) SHOVEL-KNIGHT-NES (59)
ATARI2600 (128) GAMEBOY-BGB (4) SODA-CAP (4)
BBCMICRO (16) HALLOWPUMPKIN (4) SYNTHEWAVE-CITY (8)
BLOODMOON21 (9) INK (5) TELETEXT (8)
C=64 (16) INK-CRIMSON (10) VGA (256)
CGA0/1/2-HIGH/LOW (4) INTELLIVISION (16) VINES-FLEXIBLE-LINEAR-RAMPS (38)
CGA32 (32) JUNGLE-8 (8) VIVIDMEMORY (8)
COLODORE (16) MS-WINDOWS (16) ZXSPECTRUM (16)
CYBERPUNK-NEONS (11) MSX (16)
DAWNBRINGER-16 (16)
DAWNBRINGER-32 (32)
DAWNBRINGERS-8-COLOR (8)
Drop a .GPL into assets/palettes/ (and add one include_str! line) to bundle a
new one, or point pixelview at a palette directory to load yours at runtime.
A single binary crate (pixelview). Three subsystems wired together at startup:
- Decoder registry (
src/decode/) — aVec<Box<dyn Decoder>>with two-tier dispatch: every decoder'ssniff()(magic bytes) is tried first, then file extension as a fallback. Adding a format is one new file + oneBox::new(...)line. - Threaded thumbnailer (
src/thumb.rs) — a worker pool (one thread per core) sharing a LIFO job stack so just-scrolled tiles decode first. Only CPU RGBA buffers cross back to the UI thread; texture upload happens there. - The UI (
src/app.rs) —PixelView, aneframe::App: a stack of panels (menubar, rail, favorites, breadcrumbs, search, docks, status/sort bars) around a central grid-or-viewer.
src/
main.rs eframe entry / window setup
app.rs PixelView: the whole UI, model, settings, sort/filter, ratings, CLI
image_types.rs PixImage (RGBA + optional indexed/palette)
thumb.rs worker pool: thumbnails + metadata
rating.rs star ratings via the user.baloo.rating xattr
ratings.rs cross-platform ratings.json sidecar
anim.rs animated-GIF frame decode
decode/ Decoder trait + every format decoder
palettes_builtin.rs the embedded .GPL library
For the deep internals — the recolor pipeline, the pixel-perfect blit math, the RIP
BGI rasterizer, the baud-playback engine, SAUCE handling, and the egui version
gotchas — see CLAUDE.md.
cargo run --release # build + launch
cargo check # fast type-check
cargo clippy # lint
cargo fmt # format
cargo test # 79 tests (unit + 3 headless egui_kittest GUI tests)
cargo test gui_tests # just the GUI testsPinned to eframe = "0.34" / image = "0.25" (with Cargo.lock committed). egui
renames symbols even between patch releases — if a build breaks on an egui symbol,
it almost certainly just moved; check the egui CHANGELOG for that version.
Note on UI glyphs: the bundled egui font lacks the Geometric Shapes block (
▲/▼/●render as tofu). Stick to the emoji arrows⬅/➡/⬆/⬇,⟲/⟳,…/×/›/★/📁/·, or ASCII — or paint the glyph yourself.
- egui / eframe — the immediate-mode GUI.
image— the raster decoders.- resvg — SVG rasterization.
- Mike Krüger's icy ecosystem (
icy_tools) —icy_parser_corepowers the PETSCII and RIPscript parsers (driven into pixelview's own renderers), andunarc-rshandles archive extraction. The RIP BGI primitives are ported pixel-for-pixel fromicy_engine's reference renderer. - The bundled CP437 VGA font derives from the IBM ROM (the canonical block/shade dithers); the C64 font is from the MEGA65 open-roms project (LGPL).
- The
.GPLpalette library draws on the work of DawnBringer, Endesga, PICO-8, and the broader pixel-art community. - Star ratings use the KDE Baloo
user.baloo.ratingscheme for Gwenview interoperability.
Released under the MIT License.
Note: the bundled fonts carry their own licenses — the C64 font is from the MEGA65 open-roms project (LGPL) and the CP437 VGA font derives from an IBM ROM. The MIT license covers pixelview's own source, not those embedded assets.