Skip to content
znp0Public

About

Copy and translate screen text on Wayland.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

xpeek

Copy and translate screen text on Linux/Wayland. Mainly developed for gaming dialogue and subtitles; other use cases have not been thoroughly tested. Select a region, then translate its text in a popup or copy it to your clipboard.

xpeek translating game dialogue into Vietnamese in a persistent popup

Install

Requires distro Python 3.10+, GTK4/PyGObject, grim, slurp, and wl-copy. Install gtk4-layer-shell for independent popup placement on niri and other layer-shell desktops.

# Arch / CachyOS
sudo pacman -S python python-pip python-gobject gtk4 gtk4-layer-shell grim slurp wl-clipboard
git clone https://github.com/znp0/xpeek.git
cd xpeek
python3 setup.py install

Setup asks which OCR engines to install: RapidOCR, PaddleOCR tiny, or PaddleOCR small. A new config defaults to tiny if selected, otherwise RapidOCR, then small. Paddle uses a separate managed Python 3.12 runtime on glibc Linux, x86_64. To skip the prompt:

python3 setup.py install --ocr-engines rapidocr,paddleocr-tiny
python3 setup.py install --ocr-engines all # Install all three engines

Press Enter to accept the displayed engine selection (tiny on a fresh install; previous engines on updates). Non-interactive installs require --ocr-engines; missing or empty selections fail.

The installer creates .venv, downloads selected models/dependencies, links ~/.local/bin/xpeek, and creates ~/.config/xpeek/config.json if missing, with a GitHub schema reference pinned to the installed version. Reinstalling updates only $schema in existing config; other settings, saved region, popup geometry, and history are preserved. Use distro Python; setup needs no sudo. Keep the checkout in place. If needed, add ~/.local/bin to your PATH:

export PATH="$HOME/.local/bin:$PATH"

Remove selected engines or uninstall from the same checkout:

python3 setup.py remove-engines paddleocr-small # Keep xpeek and the remaining engines
python3 setup.py uninstall                 # Keep configuration and state
python3 setup.py uninstall --remove-config # Also remove config, region, and popup state

Removing engines keeps config unchanged and requires at least one engine to remain; update ocr_engine if you remove its engine. Uninstall removes the managed environments, model downloads/caches, and command symlink. History and unrelated files are preserved; distro packages are managed separately. Clipboard notifications are optional and require notify-send plus a desktop notification daemon.

Update

Run from any directory:

xpeek update
xpeek update --tag vX.Y.Z # Optional: choose a published release tag

Update fetches and verifies the latest stable GitHub release, stops the popup and its OCR workers, checks out the release, and runs its installer without an engine prompt. There is no need to wait for model expiry; active translation work may be interrupted. It requires a clean git checkout and keeps installed engines unless --ocr-engines is supplied. Newer development versions are kept unless --tag explicitly selects an older release. Setup refreshes the version-specific schema reference while preserving other settings and state. From the checkout, python3 setup.py update performs the same update.

Verified models are reused; missing, changed, or corrupted model files are downloaded again. Dependency checks and the headless OpenCV repair step still run during installation.

Use

xpeek select                         # Save a screen region
xpeek --version                      # Show the installed version
xpeek translate                      # Translate the saved region
xpeek translate --persistent         # Append to one popup, keeping the latest 10
xpeek translate --ocr-engine paddleocr-small
xpeek translate --capture-backend gamescope # Capture native game pixels on niri
xpeek translate -p gemini -s auto -t vi
xpeek translate -p clipboard          # Copy text from the saved region
xpeek ocr                            # Select a temporary region and copy text
xpeek ocr -p google                   # Translate a temporary region
xpeek show-history -n 10              # Open recent translations
xpeek reset-size                      # Restore default popup sizes
xpeek history --watch                 # Watch history in a scrollable terminal view

Normal translation calls toggle the single popup. Persistent mode appends results and follows new entries while you're at the bottom. Clipboard calls run independently; ocr never changes the saved region. Flags override config only for that invocation. See xpeek --help, command-specific help, and the usage guide.

After closing a popup, loaded OCR models remain available for 60 idle seconds. Reopening reuses them; closing again resets the countdown. Configure ocr_keepalive_seconds to change this duration or use 0 to release models immediately after active work finishes. Open popups keep their models loaded.

Configure

Edit ~/.config/xpeek/config.json; see config.example.json, its JSON Schema, and the configuration guide. Translation starts with automatic source detection → English, using Google without an API key. Other providers are DeepL, OpenAI, Gemini, and Ollama.

Keep API keys in environment variables or the checkout's ignored .env:

cp -n .env.example .env
# Fill in DEEPL_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY as needed.

Exported variables take precedence. Use provider_options for non-secret settings such as models and hosts.

OCR engine Choose it for
paddleocr-tiny Best tested balance of speed and dialogue retention
rapidocr The existing lightweight ONNX engine
paddleocr-small Cleaner text, with slower processing

Set ocr_engine to your default engine; --ocr-engine overrides it for one command. Configure each engine separately in ocr_options:

Option Default Usage
capture_backend "desktop" "desktop" captures the displayed region; "gamescope" captures native game pixels on supported niri layouts, with desktop fallback.
threads 1 Integer 1–4. More threads can reduce processing time but increase CPU use; benchmark results favored one thread. This is not an OS CPU quota.
scale 1 Positive factor applied before OCR: 0.5 halves width and height, 1 keeps captured resolution. Downscaling uses area interpolation; enlarging uses cubic.
preprocess "none" Keep color with "none", or use "grayscale" after resizing. Grayscale can change word boundaries and meaning.

Merge these settings into your config for Tiny at native gamescope resolution and Small at half desktop resolution:

{
  "ocr_engine": "paddleocr-tiny",
  "ocr_options": {
    "paddleocr-tiny": {"capture_backend": "gamescope", "threads": 1, "scale": 1, "preprocess": "none"},
    "paddleocr-small": {"capture_backend": "desktop", "threads": 1, "scale": 0.5, "preprocess": "none"}
  }
}

Then use xpeek translate --ocr-engine paddleocr-small to switch capture and OCR settings together. Omitted engine settings use desktop capture, one thread, original resolution, and color. These example combinations follow the Wuthering Waves results; compare your own dialogue before adopting them.

Tested on an Intel Core i7-12700H using 25 Wuthering Waves captures with capture_backend: "desktop" (grim). The game rendered at 1280 × 800 and was upscaled to 2560 × 1600; the captured region was 2270 × 1060. Warm OCR medians exclude startup, capture, and translation:

Capture backend Settings (one thread, color) Time Dialogue result
desktop Tiny, scale: 1 1.142 s Preserved difficult clauses; safer Tiny starting point
desktop Tiny, scale: 0.5 0.425 s Lost an entire cinematic sentence
desktop Small, scale: 1 2.716 s Preserved all annotated clauses and choices
desktop Small, scale: 0.5 1.172 s Preserved all annotated clauses and choices; character error fell from 0.59% to 0.33%

Small at 0.5 gave the best tested accuracy/speed balance without manual cropping on those desktop images. Separate native gamescope experiments favored Tiny at 1 for speed and dialogue retention, using different scenes from the desktop set. Grayscale sometimes changed a direction or subject, so color remains the default. Testing covered only Wuthering Waves on one machine; other games are untested. Compare your own dialogue before adopting reduced resolution. See the OCR guide and full benchmark results.

Capture defaults to grim, including gamescope upscaling. Set capture_backend: "gamescope" inside an engine's ocr_options or use --capture-backend gamescope for native-resolution capture on supported niri layouts. The saved or temporary region is mapped into the native game frame; unavailable capture falls back to desktop with a terminal warning. Start with OCR scale: 1, since scaling applies after capture. See the capture guide for setup and limitations.

Contact

If you have any questions, you can ask me on Discord.

License

xpeek is licensed under the MIT License. Copyright (C) 2026 NguyenXuanVinh and xpeek contributors.

You can use, modify, and redistribute xpeek, including in commercial or closed-source software, provided you retain the copyright and permission notice in copies or substantial portions of the software. Third-party dependencies and assets retain their respective licenses.

About

Copy and translate screen text on Wayland.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages