GPU-accelerated minimalist image viewer for creative professionals and advanced users who treat images as assets and graphical resources. Built on SDL3 and Skia.
C#
25
7 commits
updated Oct 3, 2026

Lyra is a high-performance, minimalist image viewer designed for speed, fluid navigation, and precision. It handles modern and professional image formats without the overhead of full editing suites or Electron-based tools. Built for anyone who relies on images as a core resource in their workflow:
Lyra is designed for capable, modern hardware - a dedicated GPU and SSD storage will get the best out of it. Not every limitation is Lyra's to solve: network shares over SMB are constrained to a single stream by the protocol itself and cannot be parallelised, so performance over a NAS or remote share will always be bounded by that ceiling.
.icns / .ico, the pages of a TIFFLyra is built on .NET 9 with SDL3 for windowing and input, and SkiaSharp for hardware-accelerated rendering via OpenGL or Metal. It is not an Electron app - there is no embedded browser, no web runtime, and no hidden resource overhead (and definitely no AI client). Decoding is split between Lyra.ManagedCodecs, a pure-managed codec library, and lightweight native interop wrappers for EXR, JPEG 2000, JPEG XL and TIFF.
See Technical Documentation for the full detail:
| Format | Description | Extensions | Notes |
|---|---|---|---|
| PNG | Lossless raster image format with optional alpha | .png | |
| JPEG / JFIF | Lossy raster image format (JPEG family) | .jpg .jpeg .jif .jfif | |
| TIFF | High-precision raster image container | .tif .tiff | See Technical Details. |
| Targa | Raster image format with optional alpha | .tga | |
| BMP | Uncompressed bitmap image format | .bmp |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| AVIF | High-efficiency image format based on AV1 | .avif | |
| HEIF / HEIC | High-efficiency image container format (HEVC-based) | .heif .heic | |
| JPEG XL | JPEG XL Image Coding System | .jxl | Lyra displays static JPEG XL images. Animated JXL is decoded to its first frame only (same policy as JPEG 2000). HDR (floating-point) JXL gets the full HDR / EDR path. |
| WebP | Compressed raster image format with optional alpha | .webp |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| SVG | Scalable Vector Graphics | .svg | |
| Photoshop | Adobe Photoshop document | .psd .psb | See PSD / PSB Decoding Model |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| OpenEXR | High-dynamic range, multi-channel raster format | .exr | |
| Radiance HDR | High-dynamic range RGBE format | .hdr | See HDR / EDR. |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| DDS | DirectDraw Surface | .dds | See DDS & KTX Texture Decoding Model |
| KTX | Khronos GPU texture container | .ktx .ktx2 | KTX 1.x and KTX 2.0; see the texture decoding model |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| ICO | Icon container format | .ico | Every entry in the container is decoded and selectable from the sidebar's VARIANTS section. Reads PNG and BMP (DIB) entries with their masks. |
| ICNS | Apple icon container format | .icns | Every size in the container is decoded and selectable from the sidebar's VARIANTS section. Reads PNG, JPEG 2000, ARGB and the legacy RLE24 plates with their masks. |
| JPEG 2000 | Wavelet-based image format | .jp2 .jpg2.j2k .j2c .jpc | Lyra supports single-image JPEG 2000 files. Multi-image, animated, or compound JPEG 2000 formats (JPX, JPM, MJ2, JPIP) are intentionally NOT supported. |
| Key | Action |
|---|---|
← → | Previous / Next image |
Home End | First / Last image |
+ - | Zoom in / Zoom out |
Mouse Wheel | Zoom at cursor position |
Middle Mouse Button | Customizable (see app-settings.toml) |
0 | Toggle Fit to Screen / Original Size |
S | Toggle sampling mode |
F | Toggle fullscreen |
B | Toggle background mode |
I | Toggle image information overlay |
H | Toggle help overlay |
U | Toggle sidebar |
Return | Reveal image or directory in native file explorer |
Esc | Cancel an operation, or exit application |
| Key | Action |
|---|---|
⌘ ← ⌘ → | First / Last image |
⌥ ← ⌥ → | First / Last image within the directory |
| Key | Action |
|---|---|
Ctrl ← Ctrl → | First / Last image within the directory |
| Context | How Lyra interprets it | Make a collection from files around | Recursion |
|---|---|---|---|
| Single file | Anchor (Open / Open With / Double-click) | Yes | No |
| Multiple files (same directory) | Selection | No | No |
| Single directory | Directory collection | No | Yes |
| Multiple directories | Multi-directory selection | No | Yes |
| Mixed files from different directories | Multi-directory selection | No | No |
Recursion applies only when directories are explicitly dropped. Opening or dropping files never implicitly expands into subdirectories.
Developer note: Lyra intentionally favors context-aware navigation. Opening a single image always implies “show me this image in relation to its neighbors”, not isolation.
| Library | Purpose | License | Repository |
|---|---|---|---|
| SDL3-CS | Core graphics, input, and windowing | zlib | github |
| SkiaSharp | Hardware-accelerated 2D rendering | BSD-3-Clause | github |
| Svg.Skia | SVG parsing and rendering | MIT | github |
| LibHeifSharp | HEIF / HEIC image decoding | LGPL-3.0 | github |
| OpenEXR | High-dynamic-range OpenEXR (.exr) decoding | BSD-3-Clause | github |
| OpenJPEG | JPEG 2000 still-image decoding | BSD-2-Clause | github |
| libjxl | JPEG XL decoding (native wrapper) | BSD-3-Clause | github |
| libtiff | TIFF decoding | BSD-like | gitlab |
| Basis Universal | KTX2 ETC1S / UASTC transcoding (native wrapper) | Apache-2.0 | github |
| ZstdSharp.Port | Zstandard decompression for KTX2 supercompression | MIT | github |
| Unicolour | Color space conversions & perceptual color math (transitive, via the in-house PSD decoder) | MIT | github |
| MetadataExtractor | EXIF metadata extraction | Apache-2.0 | github |
| Tomlyn | TOML parsing for configuration files | BSD-2-Clause | github |
| System.IO.Hashing | Fast non-cryptographic hashing (duplicate detection) | MIT | github |
A handful of formats are decoded through native libraries (libheif, OpenJPEG, libjxl, OpenEXR, libtiff, plus the Basis Universal transcoder). How those libraries are delivered depends on the platform:
.deb, except for libjxl, which is vendored inside the
package for now. This is a temporary measure until JPEG XL support is more widely available across Ubuntu releases; it
will be dropped in favor of the system package once that lands.Lyra Viewer is distributed via Homebrew on macOS, an APT repository (or a
direct .deb) on Debian/Ubuntu, a Flatpak repository for any Linux distribution, and Scoop on Windows.
brew tap lyra-viewer/lyra
brew trust --cask lyra-viewer/lyra/lyra-viewer
brew install --cask lyra-viewer
scoop bucket add lyra-viewer https://github.com/lyra-viewer/scoop-lyra
scoop install lyra-viewer
Updates then arrive through scoop update lyra-viewer.
Add the signed repository once, then install and receive updates through apt:
# 1. Trust the repository signing key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://lyra-viewer.github.io/apt-lyra/lyra-archive-keyring.asc \
| sudo gpg --dearmor -o /etc/apt/keyrings/lyra.gpg
# 2. Add the repository
echo "deb [signed-by=/etc/apt/keyrings/lyra.gpg] https://lyra-viewer.github.io/apt-lyra stable main" \
| sudo tee /etc/apt/sources.list.d/lyra.list
# 3. Install
sudo apt update
sudo apt install lyra-viewer
Updates then arrive through the usual sudo apt update && sudo apt upgrade.
To remove the repository:
sudo rm /etc/apt/sources.list.d/lyra.list /etc/apt/keyrings/lyra.gpg
sudo apt update
Prefer not to add a repository? Download lyra-viewer_<version>_amd64.deb from the
latest release and install it
directly (apt resolves the system dependencies):
sudo apt install ./lyra-viewer_0.6.0_amd64.deb
Works on any distribution with Flatpak. One command adds the signed repository (and Flathub, for the runtime) and installs Lyra:
flatpak install --user https://lyra-viewer.github.io/flatpak-lyra/lyra-viewer.flatpakref
Updates then arrive through flatpak update. A standalone LyraViewer-linux-x86_64.flatpak is also attached to each
release; installing it subscribes to the same repository for
updates:
flatpak install --user ./LyraViewer-linux-x86_64.flatpak
The Flatpak has read-only access to your files, so it can browse folders and find duplicates, but never modifies them.
To uninstall:
flatpak uninstall --user com.nineveh.LyraViewer
flatpak remote-delete --user lyra # if you installed the bundle, `flatpak remotes` shows its remote's name
Note: Linux builds (
.deband Flatpak) are amd64 (x86-64) only for now.
Where Lyra keeps its files depends on how it was installed:
| Channel | Configuration | Data | Cache |
|---|---|---|---|
| macOS (Homebrew) | ~/.config/lyra-viewer/ | ~/.local/share/lyra-viewer/ | ~/.cache/lyra-viewer/ |
Linux (APT / .deb) | ~/.config/lyra-viewer/ | ~/.local/share/lyra-viewer/ | ~/.cache/lyra-viewer/ |
| Linux (Flatpak) | ~/.var/app/com.nineveh.LyraViewer/config/lyra-viewer/ | ~/.var/app/com.nineveh.LyraViewer/data/lyra-viewer/ | ~/.var/app/com.nineveh.LyraViewer/cache/lyra-viewer/ |
| Windows (Scoop) | %LOCALAPPDATA%\lyra-viewer\ | %LOCALAPPDATA%\lyra-viewer\ | %LOCALAPPDATA%\lyra-viewer\cache\ |
On macOS and Linux these follow the XDG base directories, so XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_CACHE_HOME are
honored when set. The Flatpak's files are separate from a .deb install's: switching between the two starts with default
settings, unless you copy the lyra-viewer/ folders across.
| File | Description |
|---|---|
app-settings.toml | Application settings: renderer, window state, middle mouse button function, text sizes... |
ui-settings.toml | UI state - saved automatically on exit |
themes/ | Color themes, one .toml per theme, selected by theme in app-settings.toml |
| File | Description |
|---|---|
log.txt | Application log output |
log.previous.txt | Log of the previous run |
load-time-data.toml | Recorded decode times per format, used to estimate loading progress |
| Path | Description |
|---|---|
scratch/ | Temporary local copies of very large files read from slow or network storage. Can briefly hold multi-GB files; each is deleted after decoding, and leftovers from a crashed run are removed on next start. |
If any configuration file is missing or malformed, Lyra falls back to built-in defaults and recreates the file on next save. Deleting everything under these folders is always safe - Lyra will start fresh with default settings.
C#
94.5%
C++
4.5%
GPU-accelerated minimalist image viewer for creative professionals and advanced users who treat images as assets and graphical resources. Built on SDL3 and Skia.
C#
25
7 commits
updated Oct 3, 2026

Lyra is a high-performance, minimalist image viewer designed for speed, fluid navigation, and precision. It handles modern and professional image formats without the overhead of full editing suites or Electron-based tools. Built for anyone who relies on images as a core resource in their workflow:
Lyra is designed for capable, modern hardware - a dedicated GPU and SSD storage will get the best out of it. Not every limitation is Lyra's to solve: network shares over SMB are constrained to a single stream by the protocol itself and cannot be parallelised, so performance over a NAS or remote share will always be bounded by that ceiling.
.icns / .ico, the pages of a TIFFLyra is built on .NET 9 with SDL3 for windowing and input, and SkiaSharp for hardware-accelerated rendering via OpenGL or Metal. It is not an Electron app - there is no embedded browser, no web runtime, and no hidden resource overhead (and definitely no AI client). Decoding is split between Lyra.ManagedCodecs, a pure-managed codec library, and lightweight native interop wrappers for EXR, JPEG 2000, JPEG XL and TIFF.
See Technical Documentation for the full detail:
| Format | Description | Extensions | Notes |
|---|---|---|---|
| PNG | Lossless raster image format with optional alpha | .png | |
| JPEG / JFIF | Lossy raster image format (JPEG family) | .jpg .jpeg .jif .jfif | |
| TIFF | High-precision raster image container | .tif .tiff | See Technical Details. |
| Targa | Raster image format with optional alpha | .tga | |
| BMP | Uncompressed bitmap image format | .bmp |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| AVIF | High-efficiency image format based on AV1 | .avif | |
| HEIF / HEIC | High-efficiency image container format (HEVC-based) | .heif .heic | |
| JPEG XL | JPEG XL Image Coding System | .jxl | Lyra displays static JPEG XL images. Animated JXL is decoded to its first frame only (same policy as JPEG 2000). HDR (floating-point) JXL gets the full HDR / EDR path. |
| WebP | Compressed raster image format with optional alpha | .webp |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| SVG | Scalable Vector Graphics | .svg | |
| Photoshop | Adobe Photoshop document | .psd .psb | See PSD / PSB Decoding Model |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| OpenEXR | High-dynamic range, multi-channel raster format | .exr | |
| Radiance HDR | High-dynamic range RGBE format | .hdr | See HDR / EDR. |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| DDS | DirectDraw Surface | .dds | See DDS & KTX Texture Decoding Model |
| KTX | Khronos GPU texture container | .ktx .ktx2 | KTX 1.x and KTX 2.0; see the texture decoding model |
| Format | Description | Extensions | Notes |
|---|---|---|---|
| ICO | Icon container format | .ico | Every entry in the container is decoded and selectable from the sidebar's VARIANTS section. Reads PNG and BMP (DIB) entries with their masks. |
| ICNS | Apple icon container format | .icns | Every size in the container is decoded and selectable from the sidebar's VARIANTS section. Reads PNG, JPEG 2000, ARGB and the legacy RLE24 plates with their masks. |
| JPEG 2000 | Wavelet-based image format | .jp2 .jpg2.j2k .j2c .jpc | Lyra supports single-image JPEG 2000 files. Multi-image, animated, or compound JPEG 2000 formats (JPX, JPM, MJ2, JPIP) are intentionally NOT supported. |
| Key | Action |
|---|---|
← → | Previous / Next image |
Home End | First / Last image |
+ - | Zoom in / Zoom out |
Mouse Wheel | Zoom at cursor position |
Middle Mouse Button | Customizable (see app-settings.toml) |
0 | Toggle Fit to Screen / Original Size |
S | Toggle sampling mode |
F | Toggle fullscreen |
B | Toggle background mode |
I | Toggle image information overlay |
H | Toggle help overlay |
U | Toggle sidebar |
Return | Reveal image or directory in native file explorer |
Esc | Cancel an operation, or exit application |
| Key | Action |
|---|---|
⌘ ← ⌘ → | First / Last image |
⌥ ← ⌥ → | First / Last image within the directory |
| Key | Action |
|---|---|
Ctrl ← Ctrl → | First / Last image within the directory |
| Context | How Lyra interprets it | Make a collection from files around | Recursion |
|---|---|---|---|
| Single file | Anchor (Open / Open With / Double-click) | Yes | No |
| Multiple files (same directory) | Selection | No | No |
| Single directory | Directory collection | No | Yes |
| Multiple directories | Multi-directory selection | No | Yes |
| Mixed files from different directories | Multi-directory selection | No | No |
Recursion applies only when directories are explicitly dropped. Opening or dropping files never implicitly expands into subdirectories.
Developer note: Lyra intentionally favors context-aware navigation. Opening a single image always implies “show me this image in relation to its neighbors”, not isolation.
| Library | Purpose | License | Repository |
|---|---|---|---|
| SDL3-CS | Core graphics, input, and windowing | zlib | github |
| SkiaSharp | Hardware-accelerated 2D rendering | BSD-3-Clause | github |
| Svg.Skia | SVG parsing and rendering | MIT | github |
| LibHeifSharp | HEIF / HEIC image decoding | LGPL-3.0 | github |
| OpenEXR | High-dynamic-range OpenEXR (.exr) decoding | BSD-3-Clause | github |
| OpenJPEG | JPEG 2000 still-image decoding | BSD-2-Clause | github |
| libjxl | JPEG XL decoding (native wrapper) | BSD-3-Clause | github |
| libtiff | TIFF decoding | BSD-like | gitlab |
| Basis Universal | KTX2 ETC1S / UASTC transcoding (native wrapper) | Apache-2.0 | github |
| ZstdSharp.Port | Zstandard decompression for KTX2 supercompression | MIT | github |
| Unicolour | Color space conversions & perceptual color math (transitive, via the in-house PSD decoder) | MIT | github |
| MetadataExtractor | EXIF metadata extraction | Apache-2.0 | github |
| Tomlyn | TOML parsing for configuration files | BSD-2-Clause | github |
| System.IO.Hashing | Fast non-cryptographic hashing (duplicate detection) | MIT | github |
A handful of formats are decoded through native libraries (libheif, OpenJPEG, libjxl, OpenEXR, libtiff, plus the Basis Universal transcoder). How those libraries are delivered depends on the platform:
.deb, except for libjxl, which is vendored inside the
package for now. This is a temporary measure until JPEG XL support is more widely available across Ubuntu releases; it
will be dropped in favor of the system package once that lands.Lyra Viewer is distributed via Homebrew on macOS, an APT repository (or a
direct .deb) on Debian/Ubuntu, a Flatpak repository for any Linux distribution, and Scoop on Windows.
brew tap lyra-viewer/lyra
brew trust --cask lyra-viewer/lyra/lyra-viewer
brew install --cask lyra-viewer
scoop bucket add lyra-viewer https://github.com/lyra-viewer/scoop-lyra
scoop install lyra-viewer
Updates then arrive through scoop update lyra-viewer.
Add the signed repository once, then install and receive updates through apt:
# 1. Trust the repository signing key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://lyra-viewer.github.io/apt-lyra/lyra-archive-keyring.asc \
| sudo gpg --dearmor -o /etc/apt/keyrings/lyra.gpg
# 2. Add the repository
echo "deb [signed-by=/etc/apt/keyrings/lyra.gpg] https://lyra-viewer.github.io/apt-lyra stable main" \
| sudo tee /etc/apt/sources.list.d/lyra.list
# 3. Install
sudo apt update
sudo apt install lyra-viewer
Updates then arrive through the usual sudo apt update && sudo apt upgrade.
To remove the repository:
sudo rm /etc/apt/sources.list.d/lyra.list /etc/apt/keyrings/lyra.gpg
sudo apt update
Prefer not to add a repository? Download lyra-viewer_<version>_amd64.deb from the
latest release and install it
directly (apt resolves the system dependencies):
sudo apt install ./lyra-viewer_0.6.0_amd64.deb
Works on any distribution with Flatpak. One command adds the signed repository (and Flathub, for the runtime) and installs Lyra:
flatpak install --user https://lyra-viewer.github.io/flatpak-lyra/lyra-viewer.flatpakref
Updates then arrive through flatpak update. A standalone LyraViewer-linux-x86_64.flatpak is also attached to each
release; installing it subscribes to the same repository for
updates:
flatpak install --user ./LyraViewer-linux-x86_64.flatpak
The Flatpak has read-only access to your files, so it can browse folders and find duplicates, but never modifies them.
To uninstall:
flatpak uninstall --user com.nineveh.LyraViewer
flatpak remote-delete --user lyra # if you installed the bundle, `flatpak remotes` shows its remote's name
Note: Linux builds (
.deband Flatpak) are amd64 (x86-64) only for now.
Where Lyra keeps its files depends on how it was installed:
| Channel | Configuration | Data | Cache |
|---|---|---|---|
| macOS (Homebrew) | ~/.config/lyra-viewer/ | ~/.local/share/lyra-viewer/ | ~/.cache/lyra-viewer/ |
Linux (APT / .deb) | ~/.config/lyra-viewer/ | ~/.local/share/lyra-viewer/ | ~/.cache/lyra-viewer/ |
| Linux (Flatpak) | ~/.var/app/com.nineveh.LyraViewer/config/lyra-viewer/ | ~/.var/app/com.nineveh.LyraViewer/data/lyra-viewer/ | ~/.var/app/com.nineveh.LyraViewer/cache/lyra-viewer/ |
| Windows (Scoop) | %LOCALAPPDATA%\lyra-viewer\ | %LOCALAPPDATA%\lyra-viewer\ | %LOCALAPPDATA%\lyra-viewer\cache\ |
On macOS and Linux these follow the XDG base directories, so XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_CACHE_HOME are
honored when set. The Flatpak's files are separate from a .deb install's: switching between the two starts with default
settings, unless you copy the lyra-viewer/ folders across.
| File | Description |
|---|---|
app-settings.toml | Application settings: renderer, window state, middle mouse button function, text sizes... |
ui-settings.toml | UI state - saved automatically on exit |
themes/ | Color themes, one .toml per theme, selected by theme in app-settings.toml |
| File | Description |
|---|---|
log.txt | Application log output |
log.previous.txt | Log of the previous run |
load-time-data.toml | Recorded decode times per format, used to estimate loading progress |
| Path | Description |
|---|---|
scratch/ | Temporary local copies of very large files read from slow or network storage. Can briefly hold multi-GB files; each is deleted after decoding, and leftovers from a crashed run are removed on next start. |
If any configuration file is missing or malformed, Lyra falls back to built-in defaults and recreates the file on next save. Deleting everything under these folders is always safe - Lyra will start fresh with default settings.
C#
94.5%
C++
4.5%