shw
shw (show) is a very simple terminal viewer for images, videos and Markdown based on Rust. It renders with pixel precision through the kitty graphics protocol.
Features
- Images: PNG, JPEG, GIF, WebP, BMP, TIFF, ICO, QOI, TGA, DDS, HDR, PNM and SVG (rendered as vectors,
so they stay sharp at any zoom). HEIC, AVIF, JXL and RAW work through
ffmpegif it is installed.- Images are drawn 1:1 at native pixel resolution with Lanczos3 SIMD resampling and EXIF orientation.
- Zoom with the mouse wheel (anchored at the pointer) or
+/-. Pan by dragging or withhjkl.0fits the window,1shows actual pixels. Above 400 % pixels are drawn crisp (nearest neighbour). - Animated GIF, WebP and APNG playback. Neighbouring files are decoded in the background, so
n/pfeel instant.
- Videos (anything ffmpeg can decode). ffmpeg scales each frame to the exact pixel size of the terminal.
Frames are sent through shared memory locally, or zlib-compressed over ssh.
- Play/pause, seeking (arrow keys or a click on the progress bar), frame stepping, loop, mute, zoom and pan inside the video, and saving a frame as PNG.
- Audio via
ffplay; it is turned off automatically over ssh.
- Markdown, rendered close to the way github.com renders it:
- large semibold headings like GitHub's (H1 2×, H2 1.5×, H3 1.25×), typeset with a system font and drawn as images so they work in every kitty-graphics terminal; plus bold, italic and strikethrough
- syntax-highlighted code blocks, tables with alignment and zebra striping, task lists, footnotes, and
> [!NOTE]/[!TIP]/[!IMPORTANT]/[!WARNING]/[!CAUTION]alerts :emoji:shortcodes and clickable links (OSC 8)- inline images (local files, remote URLs, SVG badges from shields.io), HTML
<img width=…>and<p align="center"> - mermaid diagrams, if
mmdcis installed - search with
/,n,N; select text with the mouse to copy it (the terminal's native selection), and click links
- Code / text files with syntax highlighting and line numbers, and a hex view for binaries.
- Works everywhere kitty graphics work: kitty, Ghostty, WezTerm and Konsole, over ssh, and inside tmux (Unicode placeholders + passthrough).
- Scriptable:
-i/--inlineprints straight into the terminal, likeicat, which suits fzf previews, file managers and scripts. It reads from stdin and URLs, and opens GitHub links (shw https://github.com/user/reposhows the README).
Install
Prebuilt binaries (Linux x86_64/aarch64 static musl, macOS Intel/Apple Silicon) go into ~/.local/bin:
|
From crates.io:
From source:
&&
Optional runtime tools: ffmpeg/ffprobe for videos and HEIC/AVIF, ffplay for audio, mmdc for mermaid diagrams.
Dotfiles
Release assets follow the same naming as bat: shw-v<version>-<arch>-<target>.tar.gz, with
unknown-linux-musl or apple-darwin as the target. Each archive holds the binary and shell completions.
A dotfiles install script can therefore be a copy of install.sh or simply:
|
Usage
shw [OPTIONS] [FILE]...
-i, --inline print inline instead of opening the interactive viewer
-t, --type <TYPE> force the type: image, video, markdown, code, binary
-l, --language <LANG> syntax for code / stdin (rust, py, json, …)
-W, --width <COLS> inline width in cells (default: terminal or fzf preview)
-H, --height <ROWS> inline height in cells
--upscale enlarge small images to fill the inline area
--theme <THEME> auto | dark | light
--transfer <MODE> auto | direct | file | shm
--placeholders use kitty Unicode placeholders (automatic in tmux / fzf)
-s, --start <TIME> video start position (90, 1:30, 1:02:03)
-m, --mute play videos without sound
--loop loop videos
--offline do not download remote images in markdown
-f, --force skip terminal detection
--doctor print detected terminal capabilities
--completions <SH> print a completion script (bash, zsh, fish, elvish, powershell)
With no arguments, shw reads stdin if it is piped, otherwise opens README.md in the current directory.
Keys
| Image viewer | Video player | Markdown / code | |||
|---|---|---|---|---|---|
wheel, + - |
zoom | space |
play / pause | j k wheel |
scroll |
drag, hjkl |
pan | ← → |
∓ 5 s | space b |
page |
0 / f |
fit | ↓ ↑ |
∓ 30 s | d u |
half page |
1 |
100 % | click bar | seek | g G |
top / bottom |
r R |
rotate | wheel, + - 0 |
zoom | / n N |
search |
n p |
next / prev file | m l . s |
mute, loop, step, save frame | Tab |
next file |
t |
dark / bright theme | ||||
? |
help | ? |
help | ? |
help |
q or Esc quits everywhere. The bottom line of every viewer lists its keys.
Integrations
fzf file preview (fzf ≥ 0.44 supports kitty images):
# or as an alias
yazi: open files with shw (~/.config/yazi/yazi.toml):
[]
= [{ = 'shw "$@"', = true, = "shw" }]
[]
= [
{ = "image/*", = ["shw", "open"] },
{ = "video/*", = ["shw", "open"] },
{ = "*.md", = ["shw", "edit"] },
]
lf / ranger: use shw -i "$1" as the previewer, or map a key to shw "$f".
git: render the README of any repo with shw https://github.com/user/repo.
Shell completions:
Terminals, ssh and tmux
| Terminal | Status |
|---|---|
| kitty | ✅ full support, including text sizing for headings |
| Ghostty | ✅ |
| WezTerm | ✅ (no Unicode placeholders, so no tmux) |
| Konsole | ✅ basic |
| others | ❌ shw reports that the protocol is missing |
- ssh: works out of the box. Data is sent inline and zlib-compressed. Video frames are capped at 640×360 and 30 fps for smooth playback over a network, and the terminal scales them up.
- tmux: enable passthrough with
set -g allow-passthrough on. shw then uses Unicode placeholders automatically. - Run
shw --doctorto see what was detected.
How it works
On startup shw sends a handful of queries, terminated by a DA1 sentinel, so detection never hangs. They check for kitty graphics support, which transfer modes work (direct, temp file, shared memory), the background colour (for the light or dark theme), the cell size in pixels and text-sizing support. Every frame is resampled to the exact number of device pixels the terminal will show, so the terminal never rescales the image. Updates are wrapped in synchronized-output mode and swap between two image ids, so they don't flicker.
Security
shw is designed to be safe on untrusted files: no terminal escape injection, no script execution,
only safe links are clickable, and remote images only come from public hosts (--offline disables
downloads). Release archives ship with checksums and signed build provenance. See SECURITY.md.
Development
Startup timing: SHW_TRACE=1 shw README.md prints how long each phase took (terminal query,
fonts, images, layout, first frame) after you quit.
Releasing
- Bump
versioninCargo.tomland runcargo checkto updateCargo.lock. - Commit and tag:
git commit -am "release v0.2.0" && git tag v0.2.0 && git push --follow-tags. - The release workflow builds binaries for all targets, creates the GitHub release with
checksums and completions, and publishes to crates.io. It needs a
CARGO_REGISTRY_TOKENrepository secret.
License
Licensed under MIT