veil

Status: in progress Version: 0.1.0 Creator: viewerofall
"Your apps, your terminal."

Terminal GUI renderer. Capture Wayland applications and encode them as ASCII art with luma-based character selection, edge detection, and AT-SPI text overlay. Runs natively on Niri.

Quick Links

  1. Overview
  2. Quick Start
  3. Install
  4. Usage
  5. Architecture
  6. Roadmap
  7. Known Limitations

Overview

Veil renders graphical Wayland applications inside your terminal by:

  1. Launching GUI apps under Niri (Wayland compositor)
  2. Detecting window position via Niri IPC (niri msg --json windows)
  3. Capturing frames with grim (Wayland screenshot utility)
  4. Converting to luma-based ASCII with hysteresis and edge detection
  5. Overlaying actual text from accessibility APIs (AT-SPI)

Result: Your desktop GUI apps render as live ASCII art in the terminal. Works with any GTK4/Qt/native Wayland application.

Quick Start

Launch a TUI app:

veil run my-terminal-app

Launch a GUI app (renders to terminal):

veil run-gui nautilus      # File manager
veil run-gui zen-browser   # Web browser

Exit: Ctrl+C

Check terminal capabilities:

veil probe

Install

Requirements

Build from source

git clone https://github.com/viewerofall/veil
cd veil
cargo build --release
./target/release/veil run-gui nautilus

Install globally

cargo install --path .
# or with git directly:
cargo install --git https://github.com/viewerofall/veil

Usage

Basic Commands

Command Description
veil run <app> Launch a TUI/terminal application
veil run-gui <app> Launch a GUI application (renders to terminal)
veil probe Show terminal capabilities and active config

Overrides

Control rendering parameters on the fly:

veil run-gui --override fps=15,quality=ascii zen-browser
Parameter Description Default
fps Target frames per second (render loop) 30
quality Rendering quality (ascii_luma, ascii_edge) ascii_luma

Architecture

Crate Structure

veil/
├── veil-cli/          CLI interface, render loops
├── veil-compositor/   Window detection, capture pipeline
├── veil-render/       Character encoding (luma, edge detection)
├── veil-config/       Lua configuration
└── veil-capture/      Zig library (future GPU capture)

Rendering Pipeline

For GUI apps (run-gui):

Niri window detection (IPC)
    ↓ Extract window geometry & PID
    ↓ grim fullscreen capture (PNG)
    ↓ Decode to RGBA
    ↓ Compute luma (luminance) per cell
    ↓ Apply hysteresis (noise rejection)
    ↓ Edge detection (neighboring cell luma deltas)
    ↓ Map luma to ASCII characters (sparse to dense)
    ↓ AT-SPI text overlay (actual widget text)
    ↓ Dirty-row optimization (only redraw changed rows)
    ↓ Terminal output

Components

veil-cli

Command-line interface and main render loops. Two paths:

veil-compositor

Window detection and frame capture:

veil-render

Terminal encoding:

veil-capture

Zig library for future GPU rendering:

Roadmap

Current (April 2026)

May 1st (GPU Rendering Path)

Mid-May (Beta)

Mid-June (v1)

Known Limitations

Current

Why These Exist

Niri coordinates: Niri is a tiling compositor. Windows don't have fixed screen coordinates — they exist in a layout tree. Full Wayland coordinate calculation requires knowing tile grid dimensions, output scaling, and workspace offsets. Fullscreen capture + downscaling is pragmatic for now; proper solution requires Wayland screencopy protocol (in progress for May 1st).

GPU rendering: Rendering 1920×1080 to 80×24 luma computation on every frame is expensive on weak hardware. GPU path will push capture and initial downscaling to VRAM, freeing CPU for encoding.

Workarounds

Performance Notes

CPU Budget

Default 30 FPS target assumes ~33ms budget per frame. Adjust --override fps=N for your hardware.

Memory Usage

Minimal footprint suitable for embedded systems and remote SSH sessions.

Contributing

GitHub: viewerofall/veil

Areas for contribution:

License

MIT

Created by viewerofall. GitHub: viewerofall/veil