A trackpad-first infinite canvas Wayland compositor.
demo.mp4
Traditional window managers arrange windows to fit your screen. driftwm flips this: windows float on an infinite 2D canvas and you move the viewport around them. Designed with laptops in mind — trackpad support keeps getting better while display size stays limited, so treating your screen as a camera onto a larger canvas makes sense. Pan, zoom, and navigate with trackpad gestures. No workspaces, no tiling — just drift.
Built on smithay. Inspired by vxwm, hevel, and niri.
WARNING: This is experimental software. Primarily built with AI. Use at your own risk.
Think Figma or Google Maps, but for your desktop. Your screen is a viewport onto an infinite canvas where windows live. Pan around to find what you need, zoom out to see everything at once, zoom back in to focus.
Zoom is cursor-anchored — the point under your cursor stays fixed as you zoom in or out, just like pinch-to-zoom on a map. Multiple monitors are just multiple viewports on the same canvas.
pan_zoom.mp4
Infinite 2D canvas with viewport panning, zoom, and scroll momentum. A quick flick carries the viewport smoothly until friction stops it.
| Input | Action | Context |
|---|---|---|
| 3-finger swipe | Pan viewport | anywhere |
| Trackpad scroll | Pan viewport | on-canvas |
Mod + LMB drag |
Pan viewport | anywhere |
Mod+Ctrl + arrow |
Pan viewport | — |
| 2-finger pinch | Zoom | on-canvas |
| 3-finger pinch | Zoom | anywhere |
Mod + scroll |
Zoom at cursor | anywhere |
Mod+= / Mod+- |
Zoom in / out | — |
Mod+0 / Mod+Z |
Reset zoom to 1.0 | — |
navigation.mp4
Jump to the nearest window in any direction via cone search. MRU cycling
(Alt-Tab) with hold-to-commit. Zoom-to-fit shows all windows at once.
Configurable anchors act as navigation targets for directional jumps even
with no window there — useful for areas with pinned widgets.
| Input | Action |
|---|---|
| 4-finger swipe | Jump to nearest window (natural direction) |
Mod+Ctrl + LMB drag |
Jump to nearest window (natural direction) |
Mod + arrow |
Jump to nearest window in direction |
Alt-Tab / Alt-Shift-Tab |
Cycle windows (MRU) |
4-finger pinch in / Mod+W |
Zoom-to-fit (overview) |
4-finger pinch out / Mod+A |
Home toggle (origin and back) |
4-finger hold / Mod+C |
Center focused window |
Mod+1-4 |
Jump to bookmarked canvas position |
All 4-finger navigation gestures also work as Mod + 3-finger for smaller
trackpads.
movement.mp4
Move windows by doubletap-swiping on them. Resize with Alt + 3-finger swipe.
Windows snap to nearby edges magnetically during drag. Drag to the viewport
edge and the canvas auto-pans — handy for rearranging windows just beyond the
visible area.
Tip: while dragging a window, keyboard shortcuts still work. Use Mod+1-4
to jump to a bookmark or Mod+A to go home — your held window comes with you.
Fit-window (Mod+M) is the maximize analogue — centers the viewport, resets
zoom to 1.0, and resizes the window to fill the screen. Toggle again to
restore. Fullscreen (Mod+F) is a viewport mode, not a window state — any canvas
action (launching an app, navigating) naturally exits it.
| Input | Action |
|---|---|
| 3-finger doubletap-swipe | Move window |
Alt + LMB drag |
Move window |
Alt + 3-finger swipe |
Resize window |
Alt + RMB drag |
Resize window |
Alt + MMB click / Mod+M |
Fit window (maximize/restore) |
Alt + 2-finger pinch-in/out |
Fit window |
Alt + 3-finger pinch-in/out |
Toggle fullscreen |
Mod + MMB click / Mod+F |
Toggle fullscreen |
Mod+Shift + arrow |
Nudge window 20px |
canvas.mp4
The background is part of the canvas — it scrolls and zooms with the viewport, not stuck to the screen. This gives spatial awareness when panning.
Two modes: GLSL shaders (default: dot grid, or write your own — see docs/shaders.md) and tiled images (any PNG/JPG, tiled infinitely across the canvas). Both are infinite by nature.
[background]
shader_path = "~/.config/driftwm/bg.glsl" # custom shader
# tile_path = "~/.config/driftwm/tile.png" # or tiled imagewindow_rules.mp4
Match windows by app_id and/or title (glob patterns) and control
everything: position, size, decoration mode, blur, opacity, and widget
behavior. All fields are independent and combine freely.
Widgets: set widget = true to pin a window in place — immovable, below
normal windows, excluded from Alt-Tab. Works for both regular windows and
layer-shell surfaces (e.g. waybar). Use this for clocks, system stats, trays, or
anything you want fixed on the canvas.
# Frosted-glass terminal
[[window_rules]]
app_id = "Alacritty"
opacity = 0.85
blur = true
# Desktop widget — pinned, borderless
[[window_rules]]
app_id = "my-clock"
position = [50, 50]
widget = true
decoration = "none"Tip: to find a window's
app_id, check$XDG_RUNTIME_DIR/driftwm/state— thewindowsfield lists all open windows by their app ID.
Consistent rounded corners and drop shadows across all CSD and SSD windows. SSD fallback for X11/XWayland apps — minimal title bar, close button, double-tap to maximize.
Multiple monitors are independent viewports on the same canvas. An outline on each monitor shows where the other monitors' viewports are. Cursor crosses between monitors freely; dragged windows teleport to the target viewport's canvas position.
| Input | Action |
|---|---|
Mod+Alt + arrow |
Send window to adjacent output |
docks.mp4
Layer shell surfaces (waybar, fuzzel, mako) work as expected. Foreign toplevel
management means your dock/taskbar shows all windows — click one and the
viewport pans to it and centers it. See extras/ for a fuzzel
window-search script that lets you search and jump to any open window.
- XWayland for X11 apps (Steam, Wine, JetBrains, etc.)
- Session lock (swaylock), idle notify (swayidle/hypridle)
- Screencasting (OBS, Firefox, Discord — requires
xdg-desktop-portal+xdg-desktop-portal-wlr) - Screenshots (grim + slurp)
- Click-to-focus (default) or focus-follows-mouse (sloppy focus)
- All bindings (keyboard, mouse, gesture) fully configurable via TOML
- 30 Wayland protocols
curl -fsSL https://raw.githubusercontent.com/malbiruk/driftwm/main/install.sh | sudo shInstalls the binary, session wrapper, desktop entry, and shader wallpapers.
Checks for required runtime libraries and tells you what to install if
anything is missing. To uninstall, run with sudo sh -s uninstall.
yay -S driftwmA flake.nix is included. To build:
nix buildFor development (provides native deps, uses your system Rust):
nix develop
cargo build
cargo runTo add driftwm as a session in your NixOS config:
let
driftwm-flake = builtins.getFlake "github:malbiruk/driftwm";
driftwm = driftwm-flake.packages.x86_64-linux.default;
in
{
services.displayManager.sessionPackages = [ driftwm ];
environment.systemPackages = [ driftwm ];
}Requires Rust 1.85+ (edition 2024).
Fedora:
sudo dnf install libseat-devel libdisplay-info-devel libinput-devel mesa-libgbm-devel libxkbcommon-develUbuntu/Debian:
sudo apt install libseat-dev libdisplay-info-dev libinput-dev libudev-dev libgbm-dev libxkbcommon-dev libwayland-devArch Linux:
sudo pacman -S libdisplay-info libinput seatd mesa libxkbcommonNote: Ubuntu 24.04 ships Rust 1.75 which is too old. Install via rustup instead of
apt install rustc.
git clone https://github.com/malbiruk/driftwm.git
cd driftwm
cargo build --release
sudo make installdriftwm auto-detects whether it's running nested (inside an existing Wayland
session) or on real hardware (from a TTY). Just run driftwm. For display
manager integration, select "driftwm" from the session menu.
mod is Super by default. Terminal and launcher are auto-detected
(foot/alacritty/kitty, fuzzel/wofi/bemenu), can be overridden in config.
| Shortcut | Action |
|---|---|
mod+return |
Open terminal |
mod+d |
Open launcher |
mod+q |
Close window |
mod+m |
Fit window (maximize/restore) |
mod+f |
Toggle fullscreen |
mod+c |
Center focused window |
mod+x |
Center window under cursor |
mod+arrow |
Jump to nearest window |
mod+a |
Home toggle |
mod+w |
Zoom-to-fit (overview) |
mod+= / mod+- |
Zoom in / out |
mod+scroll |
Zoom at cursor |
alt+tab |
Cycle windows |
mod+l |
Lock screen |
mod+ctrl+shift+q |
Quit |
All keybindings are configurable — see config.example.toml.
Config file: ~/.config/driftwm/config.toml (respects XDG_CONFIG_HOME).
mkdir -p ~/.config/driftwm
cp /etc/driftwm/config.toml ~/.config/driftwm/config.tomlMissing file uses built-in defaults. Partial configs merge with defaults —
only specify what you want to change. Use "none" to unbind a default binding.
Validate without starting: driftwm --check-config.
# Launch programs at startup
autostart = ["waybar", "swaync", "swayosd-server"]See config.example.toml for all options: input
settings, scroll/momentum tuning, snap behavior, decorations, effects,
per-output config, gesture bindings, mouse bindings, and window rules.
See docs/DESIGN.md for the full compositor design specification.
driftwm is just a compositor — everything else is standard Wayland tooling. Here are some tools that work well with it:
| Tool | Purpose |
|---|---|
| waybar | Status bar / taskbar |
| crystal-dock | macOS-style dock |
| fuzzel / wofi | App launcher |
| mako / swaync | Notifications |
| swaylock | Lock screen |
| swayidle / hypridle | Idle timeout (lock, suspend) |
| swayosd | Volume/brightness OSD |
| grim + slurp | Screenshots |
| wlr-randr / wdisplays | Output configuration |
| COSMIC Settings | Wi-Fi, Bluetooth, sound (or nm-applet + blueman + pavucontrol) |
The extras/ directory contains a complete setup — driftwm config,
GLSL shader wallpapers, Python widgets (clock, calendar, system stats, power
menu), waybar with taskbar/tray, fuzzel window-search script, and window rules
tying it all together. Use it as a starting point or steal pieces.
GPL-3.0-or-later
