A Wayland desktop that feels like someone cared. Smooth animations, thoughtful gestures, and the kind of details you notice only when they're missing — built from scratch in Rust on Smithay, with a Skia renderer and the lay-rs scene graph.
Otto is a Wayland compositor and stacking window manager. Parts of the desktop are handed straight to hardware display planes instead of being composited into one buffer.
You can try it inside your current session in about a minute — jump to Try it.
Documentation: User Guide · Developer Guide
Testing phase. Many features are ready for daily use, but Otto is not finished and not yet fully stable. Playing with it, breaking it and telling us about it is genuinely the most useful thing you can do right now. Feedback and questions: Discord or Matrix
#otto-compositor:matrix.org.
Wallpaper, top bar, Dock, Files browsing poster thumbnails, the user guide in a browser window.
Exposé, with the workspace strip on top — the window previews are live, not screenshots.
The same compositor, configured differently — and a third-party wlr-layer-shell widget (eww) on the desktop layer, behind windows and above the wallpaper. See Desktop Widgets.
Otto's own surfaces follow the theme: the Dock down the right edge, the brightness indicator, and otto-settings editing the running compositor over D-Bus.
None of this is a theme engine: a look is an accent, an icon tint, which edge the Dock sits on and which side the window controls are — one config file. More of them in Customization.
Zero risk: Otto runs as a window inside the desktop you're using right now.
git clone https://github.com/nongio/otto
cd otto
cargo run --release # opens Otto in a window (winit backend)Then open something inside it (WAYLAND_DISPLAY=wayland-1 <your app>), minimize a window to the Dock, hit PageUp for Exposé, Ctrl+Tab for the app switcher.
For real: install a package and pick "Otto" in your login manager.
sudo dpkg -i otto_*.deb && sudo apt-get install -f # Debian / Ubuntu
sudo dnf install otto-*.rpm # Fedora / RHEL
curl -O https://raw.githubusercontent.com/nongio/otto/main/PKGBUILD && makepkg -si # ArchPackages come from the GitHub Releases page. See Installation for the details and post-install notes, and the Getting Started guide for a walkthrough.
-
A Dock that is a real task manager — pinned apps, running apps and minimized windows in one strip, along the bottom edge or down either side. Icons magnify on approach, bounce while an app is launching, auto-hide when you want the space back, and the whole thing resizes by dragging its handle.
-
Workspaces that animate — multiple workspaces per monitor, each monitor independent, drag windows between them, configurable backgrounds.
-
Exposé and an app switcher —
PageUp(or a three-finger swipe up) spreads every window out with live previews;Ctrl+Tabwalks apps, cycles windows within an app, and can close them. Both appear on the monitor under your pointer. -
Window management that stays out of the way — animated fullscreen/maximize, snap to halves, minimize to the Dock, and new windows placed where they overlap the least. Otto draws the title bar for clients that want a server-side one, on both
xdg-decorationand KDE'sorg_kde_kwin_server_decoration, so the controls keep working while an application is busy. -
A top bar and a dynamic island — clock, tray and application menus over DBusMenu; notifications, ongoing activities and permission dialogs in a floating panel; compositor-drawn volume and brightness indicators.
-
Multi-monitor that holds up — per-output rendering, hotplug, arrangement and modes from the config, virtual outputs created on demand.
-
Lock, login and power —
ext-session-lock-v1locking with a PAM-backed locker, lock on hotkey / power button / lid close / idle timeout (respectingidle-inhibit), a greetd login screen with password and fingerprint, and Otto-owned lid-suspend with clamshell awareness. -
Screen sharing — an XDG Desktop Portal backend over PipeWire: share a whole output or a single window with browsers, OBS and anything else that speaks the portal, and send an output to an AirPlay receiver. The portal also answers file-picker, screenshot and permission-dialog requests.
-
Remote desktop —
otto-rdpserves an output to any RDP client (Microsoft Remote Desktop on Windows, macOS, iOS and Android, or FreeRDP), with TLS, hardware H.264 through VA-API where the GPU offers it and a bitmap fallback where it doesn't. Remote pointer and keyboard input is injected back into the session, so it is a screen you can actually work on. -
Virtual outputs — monitors with no display behind them, declared in the config and rendered like any other screen, each published as a PipeWire node. They have their own workspaces, exposé and workspace selector, and you can drag windows onto them: a remote screen for RDP, a stage to record or cast from, or simply more desk than your hardware has.
-
X11 apps, including fullscreen games — keyboard focus for globally-active clients, output scale via XSETTINGS, direct scanout.
-
A file manager —
otto-files: list, icon and column views, thumbnails read from the shared cache other file managers write, drag and drop in and out of other apps, background copy/move/trash with progress and 32 levels of undo, and a quick-view panel onSpacethat previews pictures, text, PDFs and media details in a sandboxed process. It is also the desktop's file picker, so Open and Save dialogs in Firefox and Chrome are this window rather than a GTK one. -
A settings app —
otto-settingsedits the configuration live over D-Bus, so you don't have to hand-write TOML (you still can — the app writes to the same file, though it does not watch it for outside edits). Displays, Dock, input, sound, power, lock and login, and the shortcut list. -
A launcher —
otto-launcher:Ctrl+Spaceto start an application,Ctrl+Shift+Pto jump to a window, with fuzzy ranking and arithmetic in the query field. All three are first versions — they aim to be useful day to day, and each guide lists what is still missing rather than leaving you to find out. -
Rendering built for this — a Skia pipeline with KMS multi-plane scanout (Dock, app switcher, popups and topmost windows on their own hardware planes) and cross-plane backdrop blur.
-
Input and theming — natural and two-finger scrolling, keyboard remapping, fully configurable shortcuts, dark/light themes, accent colors, and night shift through
wlsunsetorgammastep, which drive the hardware gamma tables. -
Accessibility — the desktop's own chrome and bundled apps expose an AT-SPI tree over D-Bus through AccessKit, so a screen reader can walk the dock, the bar and the settings app, not just client windows. See Accessibility.
-
Translated — Otto's interface ships in German, English (GB and US), Spanish, French, Italian, Polish, Portuguese (Brazil), Russian and Ukrainian, selected with the
localessetting.
Note on KMS scanout: on the tty-udev backend, Otto puts parts of the desktop on their own hardware planes instead of compositing everything into one buffer, keeping the number of overlapping planes small to limit GPU work. This has mostly been tested on Intel GPUs. Other drivers are expected to fall back to full composition when the atomic test rejects a plane configuration, but that path is untested — if you see missing, misplaced or flickering elements on AMD or NVIDIA, this is the first thing to suspect, and a report is welcome. See docs/developer/drm_plane.md.
- Screen capture: a screenshot UI for picking a region or a window interactively, and per-window capture through
wlr-screencopy. Whole-output and region capture already work withgrim, the desktop portal answers screenshot requests from applications, and per-window capture is available through the screen-sharing portal. - Multi-monitor: display mirroring.
- Dock: favorite locations; moving Dock code out of the compositor core.
- Input: scroll acceleration.
- Scene graph protocol: a WIP protocol (otto-surface-style-unstable-v1) exposing the scene graph and its animations to clients — size, position, corner radius, blur and shadow driven by compositor-side springs, a Core Animation-like model. The top bar and the dynamic island are built on it.
Otto implements a comprehensive set of protocols — click to expand
- Core:
wl_compositor,wl_subcompositor,wl_shm,wl_seat,wl_data_device_manager - Shells:
xdg_wm_base(XDG shell),xdg_decoration_manager_v1,org_kde_kwin_server_decoration,wlr_layer_shell_v1(Layer shell 1.0),xwayland_shell_v1 - Output management:
wl_output,xdg_output,wp_presentation,wp_fractional_scale_v1,wp_viewporter - Rendering and DRM:
zwp_linux_dmabuf_v1,wp_linux_drm_syncobj_v1(explicit sync),wp_drm_lease_device_v1 - Input: pointer gestures, relative pointer, pointer constraints, tablet,
wp_cursor_shape_v1, keyboard shortcuts inhibit, text input, input method, virtual keyboard,zwlr_virtual_pointer_v1, XWayland keyboard grab - Selection: primary selection, data control (wlr-data-control)
- Session:
ext_session_lock_v1,zwp_idle_inhibit_manager_v1,xdg_activation_v1, security context - Window listing:
ext_foreign_toplevel_list_v1,zwlr_foreign_toplevel_management_v1 - Capture:
zwlr_screencopy_v1 - XDG foreign: cross-client surface identification
- Display control:
zwlr_gamma_control_v1(color temperature / night shift with hardware gamma tables) - Otto extensions:
otto-surface-style-unstable-v1,otto-dock-v1
For where each one is implemented and how to trace it through the code, see docs/developer/wayland.md.
Pre-built packages are on the GitHub Releases page.
# Download the .deb package from releases, then:
sudo dpkg -i otto_*.deb
sudo apt-get install -f # Install dependencies if needed# Download the .rpm package from releases, then:
sudo dnf install otto-*.rpm
# or
sudo rpm -i otto-*.rpm# Download PKGBUILD and let makepkg fetch the tarball automatically:
curl -O https://raw.githubusercontent.com/nongio/otto/main/PKGBUILD
makepkg -siIf you already downloaded the tarball from GitHub Releases, put the PKGBUILD in the same directory — makepkg will use it without re-downloading:
cd ~/Downloads # wherever your otto-*-x86_64.tar.gz is
curl -O https://raw.githubusercontent.com/nongio/otto/main/PKGBUILD
makepkg -siOtto appears in your login manager (GDM, SDDM, LightDM, …) as "Otto" in the session menu. Select it and log in.
- The packages install
/etc/otto/config.tomland never overwrite a modified one on upgrade. Edit it to configure the whole machine, or copy it to~/.config/otto/config.tomlfor just your user. On a HiDPI display setscreen_scale = 2.0. If that file is missing, Otto falls back to compiled-in defaults and you get an empty Dock with no pinned apps. - Screen sharing requires
xdg-desktop-portalon your system. - Using Otto as the login screen (
otto --loginwithotto-greeter) requiresgreetd. On Debian/Ubuntu, copy the shippedotto-lock.pamexample to/etc/pam.d/otto-lockbefore using the screen locker — the Arch and Fedora packages install it for you. - Otto handles the lid switch and the power button itself. Set
HandleLidSwitch=ignoreandHandlePowerKey=ignoreinlogind.conffor those to work.
Install these (package names vary by distribution). The Debian/Ubuntu names are
what CI installs, so that list is the authoritative one — see the "System
dependencies" step in .github/workflows/ci.yml.
- Wayland and input:
libwayland,libxkbcommon,libudev,libinput,libseat - Graphics:
libgbm,libdrm,libEGL/Mesa,libpixman,libdisplay-info - Text:
freetype,fontconfig - Session and IPC:
libdbus,libsystemd - Screen sharing and remote desktop:
pipewire,gstreamerandgstreamer-plugins-base(otto-rdp) - Authentication:
libpam(otto-lock,otto-greeter)
On Debian and Ubuntu:
sudo apt-get install -y libdrm-dev libudev-dev libgbm-dev libxkbcommon-dev \
libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev \
libseat-dev libpipewire-0.3-dev libfreetype-dev libfontconfig-dev \
libdisplay-info-dev libpixman-1-dev libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev libpam0g-devAdd xwayland if you want to run X11 applications inside Otto. Minimum supported Rust is 1.87.0 for the compositor; building the whole workspace needs 1.96.0 (otto-rdp pins it through GStreamer).
git clone https://github.com/nongio/otto
cd otto
# Run Otto (auto-detects backend)
cargo run --release
# Development features (scene debugger, profiler)
cargo run --features "dev"With no argument Otto looks at WAYLAND_DISPLAY:
- set (you are in a Wayland session) — it uses
--winitand runs as a window - unset — it uses
--tty-udevand drives the display directly
That check does not know about X11, so on an X11 session pass --winit
explicitly; otherwise Otto tries to take over the display from your running
desktop.
Force a backend by passing it as an argument:
--tty-udev: start Otto in a tty withudevsupport — the "traditional" launch of a Wayland compositor. May require root if your system has nologind.--winit: start Otto as a Winit application, inside another X11 or Wayland session. Best for development.--x11: start Otto as an X11 client. Quite basic and not really maintained, and not in the default feature set — build with--features x11to get it. For running inside an X11 session, use--winitinstead.
Otto reads TOML configuration files, in this order (later files override earlier ones):
- System:
/etc/otto/config.toml(installed by the packages, and marked as a config file so your edits survive an upgrade) - User:
$XDG_CONFIG_HOME/otto/config.toml(defaults to~/.config/otto/config.toml) - Local override:
./otto_config.toml(current directory, for development) - Backend-specific:
./otto_config.{backend}.toml(highest priority)
otto_config.example.toml is a complete, commented example:
mkdir -p ~/.config/otto
cp otto_config.example.toml ~/.config/otto/config.toml
$EDITOR ~/.config/otto/config.tomlOr skip the editor and use the otto-settings app, which changes settings live and writes them back to the same file.
Files named otto_config.{backend}.toml in the current directory — otto_config.winit.toml, otto_config.udev.toml — override everything else. Handy when, say, you want a different screen_scale in a window than on bare metal.
Every hotkey is configurable in the [keyboard_shortcuts] section:
[keyboard_shortcuts]
"Ctrl+Return" = { open_default = { role = "terminal", fallback = "foot" } }
"Ctrl+Space" = { run = { cmd = "otto-launcher", args = [] } }
"Logo+Space" = { open_default = "file_manager" }
"Logo+B" = { open_default = "browser" }
"Ctrl+1" = { builtin = "Workspace", index = 0 }
"Ctrl+Tab" = "ApplicationSwitchNext"
"Prior" = "ExposeShowAll"For everything else — window management, workspaces, gestures, the Dock and top bar, screen sharing, remote desktop, locking and login — see the configuration reference and the User Guide.
Otto is the compositor plus a set of components, each under components/ and buildable on its own with cargo build -p <name>:
| Component | Description |
|---|---|
otto |
Main compositor binary |
otto-bar |
Top bar: clock, tray and application menus |
otto-islands |
Dynamic island: notifications, activities and dialogs |
otto-lock |
PAM-backed screen locker (ext-session-lock-v1) |
otto-greeter |
Login screen client speaking greetd's IPC |
otto-auth-ui |
Authentication panel shared by the locker and the greeter |
otto-settings |
Settings app, driving the compositor over D-Bus |
otto-files |
File manager, and the desktop's file picker |
otto-quickview |
Sandboxed preview decoder behind Files' quick view |
otto-launcher |
Keyboard-driven launcher — type to filter apps and windows |
otto-rdp |
RDP bridge serving a virtual output to a remote client |
otto-kit |
UI toolkit the Otto clients are built on |
xdg-desktop-portal-otto |
XDG Desktop Portal backend: screen sharing, file picker, screenshots, settings, permission dialogs |
apps-manager |
Debug tool for ext_foreign_toplevel_list_v1 |
To exercise a component against a running compositor:
cargo run --release -- --winit &
WAYLAND_DISPLAY=wayland-1 cargo run -p otto-launcherThe Developer Guide covers architecture, the rendering pipeline, the render loop, the scene graph, layers, DRM planes, screen sharing and more. The same pages live in docs/developer/.
Otto can profile itself with puffin, through the profile feature (also enabled by dev):
- Run the compositor with profiling on — the puffin HTTP server starts on port 8585:
cargo run --features "profile" -- --winit - Install
puffin_viewer:cargo install puffin_viewer
- Connect it to
127.0.0.1:8585.
You get frame timing, render performance and other metrics for finding bottlenecks.
Note: your puffin_viewer version must match the puffin version Otto uses (0.19.x needs puffin_viewer 0.22.0 or later).
Otto and LayersEngine are both open to contributions — test the compositor, report bugs, implement features, bring ideas. Questions and bug reports go to the issue tracker, the Discord server or the Matrix room.
The repository ships AGENTS.md, automated code review instructions and developer documentation, for human contributors and coding agents alike.
MIT. See LICENSE.
- Icons used: Fluent Icon Theme
- Font used: Inter Font
- Background used: Zach Lieberman Soft Circle Study #6 2024 zach.li




