A local, keyboard-first desktop PDF reader inspired by Zathura. It uses a minimal interface so that opening, reading, navigating, and switching documents can be done almost entirely from the keyboard.
The application is currently developed and verified on Windows 11 x64. Linux and macOS can be built through Tauri, but their native behavior has not yet been verified by this project.
- Open up to 32 PDFs at once with the native file picker.
- Render PDFs completely offline with a bundled PDF.js worker and assets.
- Read documents in a continuous vertical view with mouse, trackpad, or Vim-style keyboard navigation.
- Select and copy text from PDFs that contain a text layer.
- Zoom in and out, reset to 100%, fit the current page, or fit page width.
- Keep multiple documents open without a permanent tab bar; use the document switcher or keyboard shortcuts to move between them.
- Browse nested PDF outlines and follow internal document destinations.
- Open password-protected PDFs with retry and cancellation support.
- Recover cleanly from invalid, corrupt, or unsupported files.
- Follow the operating-system theme or persist a manual light/dark override.
- Remember status-bar visibility and each document's last page and zoom level. Document history is keyed by file content rather than its path.
- Run without a network connection, accounts, telemetry, or remote assets.
Current limitations:
- There is no text search, OCR, printing, annotation editing, Save As, or recent files list.
- External links in PDFs are disabled; internal PDF links are supported.
- Image-only PDFs can be viewed but are not converted to searchable text.
- Files are loaded into memory and are limited to 128 MiB each.
- Installers and signed release packages are not configured yet. The build instructions below produce a standalone executable for the current OS.
On macOS, use Cmd instead of Ctrl for the global shortcuts marked
Ctrl/Cmd. Reader scrolling shortcuts continue to use Ctrl.
| Keys | Action |
|---|---|
Ctrl/Cmd+O |
Open one or more PDFs |
Ctrl/Cmd+L |
List open documents |
Ctrl/Cmd+R |
Toggle and remember light/dark theme |
Ctrl/Cmd+N |
Toggle and remember the status bar |
F11 |
Toggle fullscreen |
Tab |
Toggle the PDF outline sidebar |
: |
Open command mode |
Escape |
Clear a pending key sequence or close the active dialog |
| Keys | Action |
|---|---|
j / k |
Scroll down / up |
h / l |
Scroll left / right |
Ctrl+D / Ctrl+U |
Scroll half a viewport down / up |
Ctrl+F / Ctrl+B |
Scroll one viewport down / up |
gg |
Go to the first page |
G |
Go to the last page |
[number]G |
Go to a physical page, for example 42G |
+ / - |
Zoom in / out |
= |
Reset zoom to 100% |
a |
Fit the page |
s |
Fit page width |
gt / gT |
Switch to the next / previous document |
| Keys | Action |
|---|---|
j / Down |
Select the next document |
k / Up |
Select the previous document |
Enter |
Open the selected document |
Escape |
Close the switcher |
Press :, type a command, and press Enter.
| Command | Action |
|---|---|
:q |
Close the current document |
:clear-history |
Clear saved reading state and return to the OS theme |
:waifu |
Toggle the dancing corner overlay |
| Layer | Technology |
|---|---|
| Desktop shell | Tauri 2 |
| Native backend | Rust 1.93 |
| Frontend | TypeScript 5.9, HTML, and CSS |
| Build tooling | Vite 7 and pnpm 10 |
| PDF rendering | PDF.js 6.3 |
| Native file picker | rfd |
| Windows webview | Microsoft Edge WebView2 |
| Linux webview | WebKitGTK 4.1 |
| macOS webview | WKWebView |
The frontend receives opaque document handles instead of filesystem paths. The native backend validates and reads selected files, while PDF parsing and rendering happen locally in the bundled PDF.js viewer. Tauri capabilities, remote navigation, and external PDF links are disabled.
Build on the operating system you want to target. Tauri uses native webviews and native compiler toolchains, so a Windows build should run on Windows, a macOS build on macOS, and a Linux build on Linux. Cross-compilation is not part of the project's supported workflow.
All platforms require:
- Node.js 24
- pnpm 10
- Rust through rustup;
rust-toolchain.tomlautomatically selects Rust 1.93 - Git
After installing the OS-specific prerequisites below, run these commands from the repository root:
pnpm install --frozen-lockfile
pnpm tauri build --no-bundleThe command runs the TypeScript typecheck and Vite production build before
compiling the native release executable. Installer bundling is currently
disabled, so --no-bundle intentionally creates only the application binary.
Supported and verified target: Windows 11 x64.
Install:
- Visual Studio Build Tools with Desktop development with C++, the MSVC x64 build tools, and a Windows SDK
- Microsoft Edge WebView2 Runtime, which is normally included with Windows 11
- Rust's
x86_64-pc-windows-msvctoolchain
For a repeatable release build, run the checked-in script from native PowerShell:
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-windows.ps1The default output is %USERPROFILE%\Downloads\Zathura.exe. The script:
- stages the current worktree in a fresh directory on the native Windows filesystem, so it also works when the repository is inside WSL;
- requires the exact pnpm version from
package.jsonand the Node.js range frompackage.json; - installs JavaScript dependencies with
--frozen-lockfileand compiles Rust with--lockedusing the toolchain pinned inrust-toolchain.toml; - builds a release executable without an installer, runs the native shell smoke test, gracefully closes an existing destination executable, and replaces it;
- verifies the copied file by SHA-256 and prints its path, size, and hash.
Use another destination or relaunch the application after replacement with:
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-windows.ps1 `
-Destination "C:\path\to\Zathura.exe" -LaunchFrom WSL, invoke the same script through Windows PowerShell. It copies source
files but never shares WSL node_modules or Rust build artifacts with Windows:
powershell.exe -NoProfile -ExecutionPolicy Bypass \
-File "$(wslpath -w scripts/build-windows.ps1)" -LaunchPass -SkipSmoke only when the Windows UI automation smoke test cannot run.
The resulting executable is unsigned, so Windows SmartScreen may warn when it
is first opened. Locked inputs and a clean build make the procedure repeatable;
they do not promise byte-for-byte reproducible PE files across different Windows
SDK, MSVC, or operating-system versions.
For a manual build from a native Windows checkout, run:
pnpm install --frozen-lockfile
node node_modules/@tauri-apps/cli/tauri.js build --no-bundle -- --lockedManual-build output:
src-tauri\target\release\local-pdf-reader.exe
To run the native Windows shell smoke test after building:
powershell -NoProfile -ExecutionPolicy Bypass -File tests/windows-shell-smoke.ps1Linux builds require Tauri's WebKitGTK and native development libraries. On Debian, Ubuntu, or WSL, install them with:
sudo apt update
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file \
libxdo-dev libssl-dev librsvg2-dev libayatana-appindicator3-devThen build:
pnpm install --frozen-lockfile
pnpm tauri build --no-bundleOutput:
src-tauri/target/release/local-pdf-reader
The executable still depends on compatible system runtime libraries, including WebKitGTK. Native Linux behavior and distribution compatibility have not yet been verified by this project. See the official Tauri Linux prerequisites for packages used by other distributions.
Install Xcode Command Line Tools:
xcode-select --installThen build on the Mac architecture you want to target:
pnpm install --frozen-lockfile
pnpm tauri build --no-bundleOutput:
src-tauri/target/release/local-pdf-reader
This produces an unsigned standalone Mach-O executable, not a .app, DMG, or
notarized release. Native macOS behavior and minimum OS compatibility have not
yet been verified by this project.
Install dependencies and run the checks:
pnpm install --frozen-lockfile
pnpm typecheck
pnpm buildThe complete test suite also validates deterministic PDF fixtures. Set up its
development-only Python environment and FIXTURE_PYTHON as described in
fixtures/README.md, then run:
pnpm testRun the native development application after installing the prerequisites for your OS:
pnpm tauri devRun the Rust checks directly:
cargo check --locked --manifest-path src-tauri/Cargo.toml
cargo test --locked --manifest-path src-tauri/Cargo.tomlAdditional architecture, design, acceptance criteria, and verification details
are available in docs/.