Skip to content

1ay1/neowall

Repository files navigation

NeoWall

Run GLSL shaders as your Linux wallpaper.

Build License Release

neowall_demo.mp4
neowall_mouse.mp4


Paste a Shadertoy shader into a file, point neowall at it, get an animated desktop. Wayland + X11, multi-monitor, single static binary, no daemon-in-Python anywhere.

neowall

It pauses itself the moment a window covers the wallpaper, so it isn't burning your battery while you actually use the computer.

Install

# Arch (AUR)
yay -S neowall-git

# Prebuilt binary
# https://github.com/1ay1/neowall/releases/latest
tar -xzf neowall-linux-x86_64-*.tar.gz
sudo install -m755 neowall /usr/local/bin/

# From source
git clone https://github.com/1ay1/neowall && cd neowall
meson setup build && ninja -C build
sudo ninja -C build install
Build dependencies
# Debian/Ubuntu
sudo apt install build-essential meson ninja-build libwayland-dev \
    libgles2-mesa-dev libpng-dev libjpeg-dev wayland-protocols \
    libx11-dev libxrandr-dev

# Arch
sudo pacman -S base-devel meson ninja wayland mesa libpng libjpeg-turbo \
    wayland-protocols libx11 libxrandr

# Fedora
sudo dnf install gcc meson ninja-build wayland-devel mesa-libGLES-devel \
    libpng-devel libjpeg-turbo-devel wayland-protocols-devel \
    libX11-devel libXrandr-devel

Config

~/.config/neowall/config.vibe

default {
  shader retro_wave.glsl
  shader_speed 0.8
}

Image slideshow:

default {
  path ~/Pictures/Wallpapers/
  duration 300
  transition glitch
}

Per-output:

output {
  DP-1     { shader matrix_rain.glsl }
  HDMI-A-1 { path ~/Pictures/ duration 600 }
}

Full reference: config/docs/CONFIG.md.

Commands

neowall          # start
neowall kill     # stop
neowall reload   # reload config
neowall next     # next wallpaper / shader
neowall pause    # pause cycling
neowall resume
neowall pause-shader   # freeze the shader animation in place
neowall resume-shader  # resume a frozen shader animation
neowall list     # show queue
neowall set 3    # jump to index
neowall current  # print what's playing

Shaders

30+ in the box. Bring your own — neowall accepts unmodified Shadertoy GLSL: drop a .glsl file into ~/.config/neowall/shaders/ and reference it from your config.

Vibe A few
Synthwave retro_wave · synthwave · neonwave_sunrise
Nature ocean_waves · aurora · sunrise
Cyber matrix_rain · matrix_real · glowing_triangles
Abstract fractal_land · plasma · mandelbrot
Space star_next · starship_reentry

Pair it with GLEditor for a live-preview shader workflow that one-clicks into neowall.

Reactive shaders — a living desktop

neowall is a superset of Shadertoy: on top of full compatibility it feeds shaders live data from your machine and ships a GLSL std-lib (noise, SDFs, palettes, tonemap) injected automatically — no #include. Shaders can react to system audio (FFT), CPU/RAM/network load, battery, the real time of day, and your mouse/keyboard. See docs/REACTIVE_SHADERS.md.

Shader Reacts to
audio_pulse · audio_bars system audio — spectrum, bass, beats
mouse_ripples water ripples from your cursor (click = splash)
plasma_touch plasma you push around with the mouse
fireflies a swarm that gathers at your pointer, flares on beat
starfield_warp warp speed scales with mouse motion + audio
system_monitor CPU heat, RAM tide, network pulses, battery
system_deck a command-deck HUD: CPU/RAM gauges, scrolling history graph, per-core meters, net traces, battery, clock
rain_window rain on glass — heavier with network, lightning on beat
circadian_sky a sky synced to your real clock: dawn → noon → dusk → stars

Drop a .neowall sidecar next to any shader for explicit channel bindings and custom reactive uniforms (e.g. uniform uGlow audio_bass). Audio capture uses parec (PipeWire/PulseAudio) and degrades to silence if it's not installed.

Changing what feeds iChannel0..3 (audio, noise, self-feedback, another buffer, a texture, a bitmap font atlas): a bare .glsl guesses via a heuristic; a .neowall sidecar lets you bind each channel explicitly — channel0 audio, channel1 self, channel2 font, etc. See docs/REACTIVE_SHADERS.md.

Terminal as wallpaper

Any terminal program can be the wallpaper. neowall ships its own in-tree, dependency-free VT/xterm-class terminal emulator (real PTY, spec-correct ANSI/DEC parser, cell grid with SGR truecolour, scroll regions, the alternate screen, mouse reporting and colour emoji) and renders its cell grid on the GPU — so btop, htop, cava, vim or a scrolling journalctl -f run live behind your windows.

default {
  terminal btop
  term_cols 0     # 0 = auto-fit the whole display
  term_rows 0
}
default {
  terminal "journalctl -f"
  term_font_size 16
  term_shader crt.glsl    # optional: pipe the terminal through a CRT/glow pass
}

It's a real terminal, not a screenshot: it answers the startup handshake (cursor-position report, Device Attributes) so probing TUIs enter their render loop and animate, forwards the pointer when the app enables mouse reporting, and auto-restarts the command if it exits. No libvterm, no external terminal — every byte of the parser and screen model is in-tree, in the same spirit as neowall's hand-rolled event loop and config parser.

Full key reference (term_font, term_font_size, term_fg/term_bg, term_cwd, term_env, term_shader, …) is in config/docs/CONFIG.md.

How it works

Single C binary. The event loop is built on timerfd + signalfd — there is no polling thread anywhere. Rendering goes through EGL → OpenGL 3.3 (desktop) with a GLES 2.0 fallback for older GPUs.

config.vibe → event loop ─┬─→ EGL / OpenGL 3.3
                          ├─→ Wayland (layer-shell)
                          └─→ X11 (root window + EWMH)

Smart pause is the main thing that separates neowall from the obvious one-evening hack:

  • Wayland: wl_surface.frame watchdog + wlr-foreign-toplevel state bits, plus a Hyprland-specific IPC path that handles the awkward "tiled mosaic of small windows covers the wallpaper" case
  • X11: EWMH _NET_WM_STATE_FULLSCREEN on every output

Result: while a fullscreen game, a maximized browser, or a wall of tiled terminals is covering the screen, neowall draws zero frames. The moment you switch workspaces, it picks back up.

Compared to

neowall swww mpvpaper hyprpaper
Animated GLSL shaders
Drop-in Shadertoy support
Terminal / TUI as wallpaper
Image slideshow
Video gifs only
Wayland
X11
Pauses when occluded

If you want video wallpapers, use mpvpaper — neowall is deliberately not that.

Caveats, honestly

  • KDE Plasma: native desktop icons may hide while neowall owns the background layer. Use a dock or plasma-desktop's widgets.
  • GNOME: works through the fallback path; Mutter doesn't expose layer-shell, so z-order behavior is less guaranteed than on wlroots compositors.
  • No video: by design.

Hacking

meson setup build --buildtype=debug
ninja -C build
./build/neowall -f -v

Architecture, threading model, and contribution conventions are documented in docs/ARCHITECTURE.md. Run the test suite (headless, no display server needed) with meson test -C build; for the memory-safety and concurrency gates use a sanitized build:

meson setup build-asan -Db_sanitize=address,undefined && meson test -C build-asan
meson setup build-tsan -Db_sanitize=thread && meson test -C build-tsan output_refcount

Shaders, bug reports, and compositor coverage PRs are all welcome. Issue tracker is the place.

License

MIT.


Issues · Discussions · ★ if it's your thing

Packages

 
 
 

Contributors

Languages