Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Halley

Named after Halley's comet — periodic, precise, returning.

Website

Sponsor License Status Wayland Build Rust


Windows as nodes. Windows as clusters. Windows as your command center.

Halley is a Wayland compositor built from the ground up for multi-monitor setups. Each display gets its own independent infinite canvas. Windows live as nodes on those canvases, group into clusters you build intentionally, and decay gracefully when they drift out of focus. Inspired by the comet it's named after — periodic, precise, and always returning — Halley makes multi-monitor work feel deliberate rather than chaotic.


Support the Next Leap

Halley will continue receiving updates, fixes, protocol work, and polish. The project is active, and the core direction is not being paused or held hostage.

The larger leap is different. A full Wayland desktop ecosystem can only be taken so far as a solo project. Sponsorship helps fund the boring-but-important work that makes Halley more durable, approachable, and useful over time — documentation, testing, packaging, compatibility, triage, tooling, and release work — alongside larger technical improvements.

Sponsorship does not buy roadmap control. Halley remains maintainer-directed. Support helps create the time and stability needed to execute on that direction responsibly.

Sponsorship Stretch Goals

  • A real Halley website, beyond a basic GitHub Pages presence.
  • A major Rune-CFG upgrade so it can become a larger foundation for future Halley UI and app work, not only a config language.
  • A much stronger halley-api for plugins, integrations, ecosystem tooling, and external developers.
  • A system for creating full Halley ecosystem apps using Rune-CFG plus light Rust, mostly through halley-api.
  • Documentation, onboarding, examples, migration notes, troubleshooting, and developer guides.
  • Packaging, testing, CI, compatibility, hardware/device testing, crash/debug tooling, and other infrastructure work.
  • Funding or compensating a community maintainer for triage, Discord/community support, docs cleanup, bug reproduction, and release coordination.
  • Better outreach: demos, release posts, videos, dev logs, showcases, and broader Linux desktop visibility.

Demo

Halley demo Halley demo


Concepts

A quick orientation before diving in.

Term What it is
Field An infinite 2D canvas, one per monitor. Everything lives here. Zoomable and pannable.
Node A window on the Field — open, collapsed, or a cluster core.
Focus Ring An invisible eye-shaped region defining your active area. Windows outside it are candidates for decay.
Decay Nodes that drift outside the focus ring dim or collapse over time. Optional and configurable.
Cluster Halley's answer to workspaces — a contained layout you build intentionally from a set of windows.
Core The collapsed form of a cluster on the Field. Expands into a petal arrangement of window previews.
Trail History-aware navigation — step backward and forward through recent focus changes.
Bearings A lightweight directional overlay for orienting movement and navigation around the current view.
Jump Move a grabbed window across monitors, traversing between Fields, with a single keybind.

The Field

Multi-monitor is a first-class concept in Halley — not an afterthought. Each monitor gets its own infinite canvas, completely independent from every other display. The Field is zoomable, pannable, and isolated per monitor.

  • Per-monitor — displays don't share state; each Field is its own world
  • Max windows — configurable cap on open nodes per Field
  • Decay — opt-in clutter management based on focus ring position; a small overlap tolerance prevents edge-case false positives
  • Jump — grab a window and send it to another monitor's Field with one keybind; Super+Shift+LeftMouse for a pointer-driven field jump

The Focus Ring is the heart of the Field. It's an invisible eye-shaped region centered on your view — windows that fall significantly outside it over time become candidates for decay. You can make it briefly visible via config; it fades out after a moment. Size and shape are fully configurable.


Clusters

Clusters are Halley's answer to workspaces — but you build them yourself, intentionally, rather than having them auto-generated.

Building a cluster

Enter cluster mode, then click or mark the windows you want to group. Press Enter to form the cluster, or Esc to cancel and return to the Field. Once formed, the cluster collapses into a core node on the Field — a single handle representing the whole group.

The core

Clicking a core within the focus ring enters the cluster. Expanding it fans the windows out in a petal arrangement — clockwise or counter-clockwise — as icon-sized previews around the core. From there you can:

  • Pull windows out into the Field
  • Bring Field windows in
  • Collapse it back into the core

Inside a cluster

Once inside, you leave the Field entirely. The cluster is its own contained space with one of two layout modes:

Tiling — Weighted tiling. Windows are arranged by assigned weight and recency.

Stacking — Windows layered in a navigable stack, similar to a mobile app switcher. Navigate with keybinds, reorder the stack as needed.


Systems

System Description
Field Per-monitor infinite canvases with zoom and pan
Clusters Core nodes, cluster entry/exit, tiling, stacking, drag reordering
Focus Ring Configurable active region with optional preview
Decay Optional clutter reduction outside the focus ring
Trail Recent-focus navigation — back and forward
Bearings Directional overlays and navigation cues
Jump / Field Jump Fast cross-monitor grabbed-window movement
IPC Unix socket control at $XDG_RUNTIME_DIR/halley/halley.sock
Xwayland On-demand support via xwayland-satellite

Requirements

Halley targets a native Linux Wayland session and expects:

  • A DRM/KMS-capable graphics stack with GBM/EGL/OpenGL support
  • A seat/session backend through libseat such as seatd or logind
  • libinput and udev access on a real TTY for the native backend
  • Rust and Cargo if you are building from source

Optional but commonly needed:

  • xwayland-satellite for X11 app support
  • Halley's native xdg-desktop-portal-halley backend for portal-driven screen/window sharing, plus xdg-desktop-portal-gtk for common file/dialog portals
  • fuzzel plus a Wayland terminal such as ghostty, kitty, foot, wezterm, alacritty, rio, or contour if you use the default launch bindings

Install

Void Linux (xbps package — this fork)

This fork ships an xbps-src template that builds the compositor as a real Void package. Anyone can build it on Void with no local files to copy.

git clone https://github.com/void-linux/void-packages.git
cd void-packages

# Drop only the template into srcpkgs/halley. The template itself
# downloads the source via distfiles (the GitHub tarball of this fork), so
# there's nothing else to copy.
mkdir -p srcpkgs/halley
curl -L -o srcpkgs/halley/template https://raw.githubusercontent.com/mikuri12/halley/main/void/template

./xbps-src pkg halley
sudo xbps-install --repository hostdir/binpkgs halley

After install, log out and pick Halley from the Noctalia/ly/SDDM menu. The .desktop points to /usr/bin/halley-session, which already carries the dbus-run-session guard for Void runit (no session D-Bus by default — without that guard the monitor hangs with "no signal" when logging in).

Build-time dependencies (clang18-devel, wayland-devel, ..., see void/template). Runtime dependencies (xwayland-satellite, dbus, seatd) are pulled in automatically via depends=.

NixOS / Home Manager (flake)

This fork also exposes a flake under nix/ with:

  • packages.${system}.halley — the Rust derivation (callable from any other flake as an input).
  • packages.${system}.default — alias of halley.
  • homeConfigurations.mikuri — a ready-to-use Home Manager configuration that installs the package and exposes the Wayland session + portal metadata.

Use it from your existing flake

inputs.halley.url = "github:mikuri12/halley";
# ...
environment.systemPackages = [ inputs.halley.packages.${system}.halley ];
# or, on Home Manager:
home.packages = [ inputs.halley.packages.${system}.halley ];

The halley derivation ships passthru.providedSessions = [ "halley" ], so on NixOS you can also register it with the display manager:

services.displayManager.sessionPackages = [ inputs.halley.packages.${system}.halley ];
xdg.portal.extraPortals = [ inputs.halley.packages.${system}.halley ];

Or apply the ready-made HM configuration

On a non-NixOS distro (Void, Arch, …) with Home Manager standalone:

home-manager switch --flake github:mikuri12/halley#mikuri

This installs halley, halleyctl, xdg-desktop-portal-halley into the mikuri user profile and writes the Wayland .desktop + portal metadata into ~/.local/share/. The halley-session wrapper shipped with the Nix package already contains the dbus-run-session guard (same as the Void one).

Note: home.username is hardcoded to mikuri in the example config. Fork the repo or override the module with your own username. home.stateVersion = "25.05".

AUR (upstream only)

yay -S halley

or

paru -S halley

Or for the latest commit:

yay -S halley-dev

or

paru -S halley-dev

From Source

git clone https://github.com/mikuri12/halley
cd halley
cd src
cargo build --release

The compositor, control CLI, and portal backend binaries will be available at:

src/target/release/halley
src/target/release/halleyctl
src/target/release/xdg-desktop-portal-halley

For local testing without system-wide binaries, install them into ~/.local/bin:

install -Dm755 src/target/release/halley ~/.local/bin/halley
install -Dm755 src/target/release/halleyctl ~/.local/bin/halleyctl
install -Dm755 src/target/release/xdg-desktop-portal-halley ~/.local/bin/xdg-desktop-portal-halley

Display Manager Session

Halley's native session needs to start the tty backend rather than the nested winit backend. This repo ships the assets needed for display managers such as SDDM and LightDM directly in the src/ tree:

  • src/packaging/wayland-sessions/halley-session
  • src/packaging/wayland-sessions/halley.desktop

Install them to the standard system locations alongside the compositor binary:

sudo install -Dm755 src/target/release/halley /usr/bin/halley
sudo install -Dm755 src/packaging/wayland-sessions/halley-session /usr/bin/halley-session
sudo install -Dm644 src/packaging/wayland-sessions/halley.desktop /usr/share/wayland-sessions/halley.desktop
sudo install -Dm644 src/packaging/systemd-user/halley.service /usr/lib/systemd/user/halley.service
sudo install -Dm644 src/packaging/systemd-user/halley-shutdown.target /usr/lib/systemd/user/halley-shutdown.target

halley-session is the recommended public launcher for a full Halley desktop session. It will start halley.service when a user systemd instance is available, which makes graphical-session.target, xdg-desktop-autostart.target, and related user-session units behave correctly under display managers like SDDM. If those units are not installed, the launcher falls back to executing halley directly.

On Void (runit, no systemd) the launcher needs the dbus-run-session guard so Halley gets a session bus — otherwise it hangs in dbus-update-activation-environment. Use the void/halley-session wrapper shipped in this repo instead of the upstream one.

The compositor also accepts halley --session for session wrappers, packagers, and service files. Normal users should prefer halley-session.

After that, Halley should appear in Wayland-capable display managers.


Default Keybinds

Defaults follow Halley's shipped fresh-config template.

Category Keybind Action
Basic Super+Shift+r Reload config
Basic Super+n Toggle state
Basic Super+q Close focused window
Quit Super+Shift+e Quit Halley
Zoom Super+MouseWheelUp Zoom in
Zoom Super+MouseWheelDown Zoom out
Zoom Super+MiddleMouse Reset zoom
Move Super+Left Move node left
Move Super+Right Move node right
Move Super+Up Move node up
Move Super+Down Move node down
Monitor Super+Shift+Left Focus monitor left
Monitor Super+Shift+Right Focus monitor right
Monitor Super+Shift+Up Focus monitor up
Monitor Super+Shift+Down Focus monitor down
Clusters Super+Shift+c Enter cluster mode
Clusters Super+l Cycle cluster layout
Bearings Super+z Show bearings
Bearings Super+Shift+z Toggle bearings
Trail Super+, Trail previous
Trail Super+. Trail next
Launch Super+Return Open terminal
Launch Super+d Launch fuzzel
Pointer Super+LeftMouse Move window
Pointer Super+RightMouse Resize window
Pointer Super+Shift+LeftMouse Field jump
Screenshot Super+Shift+s Open capture menu
Tile Super+Left/Right/Up/Down Focus tile in that direction
Tile Super+Ctrl+Left/Right/Up/Down Swap tile in that direction
Stacking Super+Left Cycle stack forward
Stacking Super+Right Cycle stack backward
Media XF86AudioRaiseVolume Raise volume
Media XF86AudioLowerVolume Lower volume
Media XF86AudioMute Toggle mute

Configuration

On first launch Halley bootstraps ~/.config/halley/halley.rune for you from an internal fully documented template, inserting detected tty monitors into the viewport section. Normal config precedence is --config/-c, then HALLEY_WL_CONFIG, then ~/.config/halley/halley.rune, then /etc/halley/halley.rune, then generated user config/internal defaults. Use halley --config /path/to/halley.rune or halley -c /path/to/halley.rune to force a specific file.

Handled by crates/halley-config. Covers input settings like repeat/focus mode, keybinds, focus ring shape and size, decay threshold, max windows per Field, viewports, autostart programs and much more.

Community / Support

Halley has a Discord for practical support, bug triage, release updates, packaging discussion, and focused contributor coordination.

Halley remains maintainer-directed. Discord is not a roadmap vote or public steering committee. Please read the rules and start in #intake so you can be routed to support, config help, bugs, packaging, contributing, or release-only updates.

Join the Discord: https://discord.gg/cjutpDv6q

Contributing

View the contributing guidelines before making any pull requests.


Portals To Use

  • xdg-desktop-portal-halley for ScreenCast, including monitor and window sharing
  • xdg-desktop-portal-gtk for common desktop dialogs not implemented by Halley

Website

Project website: saltnpepper97.github.io/halley-site


Inspirations

  • niri — for how to do Wayland compositor things in Rust
  • vxwm — for studying some of its eyecandy
  • hevel — for zoooooooom
  • Hyprland — for some config organization and eyecandy
  • newm — Godfather of spatial compositing

License

Released under the GPL-3.0 license.


Patches in this fork (Mikuri)

This fork (mikuri12/halley) is upstream Halley v0.5.0 with six local fixes applied inline to src/. They're already in the tree you just cloned — no patch file you have to apply yourself. Summary of what they do and why:

  1. Direct-scanout no longer disabled by pending frame-callbacks — a fullscreen client always has callbacks pending, and the old gate (which turned off direct-scanout when callbacks were pending) made every fullscreen game oscillate scanout ↔ GL and drop fps. The gate was redundant: the direct-scanout path is already paced by page-flip + presentation feedback. (src/crates/halley-wl/src/backend/tty/drm.rs)

  2. Fullscreen apps cover the Top/Overlay layer-shell surfaces — Halley has no dedicated fullscreen render route, so the bar / notifications / layer-shell launcher sat on top of a fullscreen app. The patch adds a current_monitor_has_settled_fullscreen predicate and a suppress_top_overlay_layers flag the frame builder consults to skip drawing those layers when a fullscreen window is settled. The hit-test is taught the same predicate, otherwise the layers stayed invisible but clickable. (drives: system.rs, draw.rs, scene.rs, surface.rs)

  3. send_pending_configure() instead of unconditional send_configure() — Chromium/Electron re-request set_fullscreen when you switch tab/video, and the unconditional configure made them re-show the "Press Esc to leave fullscreen" toast that never went away. Now we use Smithay's dedup no-op. (fullscreen/system.rs)

  4. Animated XCursor support (multi-frame) — upstream kept only the first frame of animated cursor themes, so every XCursors-animated theme was stuck static. The patch adds a FrameData{pixels_bgra, delay_ms} type, a SoftwareCursorSprite::frame_at(elapsed_ms) lookup, and the CursorManager animation state. (cursor_theme.rs, cursor.rs, draw.rs, activity.rs, portal/mod.rs)

  5. Adaptive idle tick + display-fd in calloop — the master calloop timer re-armed on every iteration; the process never went idle even at rest. Now it picks a slow IDLE_TICK_MS guard tick when no work is pending, and registers the Wayland display fd in calloop so a client commit wakes the loop by itself. (backend/tty/mod.rs)

  6. CursorManager carried into the direct-scanout cursor path — side effect of fix #4: the direct-scanout cursor path read the global cache directly, bypassing the animation state. The patch threads &mut CursorManager down through the scanout path so the animation keeps started_at/cycle_ms authoritative even when the cursor goes out via the DRM HW plane. (drm.rs)

These fixes are explained in code comments at the hunk they touch.

Why a separate fork?

Honestly: I don't have experience writing compositors and I'm not sure these arreglos son the right way to fix these problems for everyone — they work on my setup but I don't want to push upstream something I'm not confident is the correct general fix. I'd rather keep them in a fork so anyone who wants to try Halley with Noctalia / Void / a similar layer-shell setup has something confortable to grab. If upstream wants to take any of them, cool — I'll be happier maintaining less code; if not, the fork is here.


Layout of this repo

.
├── README.md        # this file (upstream README + the patches section above)
├── src/             # upstream Halley v0.5.0 with the 6 fixes already applied
│   ├── crates/      #   Cargo workspace (halley-wl = main crate)
│   ├── packaging/   #   upstream wayland-sessions .desktop, systemd-user units,
│   │                #   xdg-desktop-portal config, dbus services
│   └── Cargo.toml    #   workspace manifest
├── void/            # Void Linux packaging (xbps-src template + session wrapper)
│   ├── template         #   xbps-src template (downloads src via distfiles, builds, installs)
│   ├── halley-session  #   wrapper with the dbus-run-session guard for runit/no-systemd
│   ├── halley.desktop   #   wayland-sessions .desktop pointing at /usr/bin/halley-session
│   ├── halley.portal       #   xdg-desktop-portal backend metadata
│   ├── halley-portals.conf #   portal routing (ScreenCast/Screenshot -> halley backend)
│   └── README.md        #   build & install notes for Void
├── nix/             # Nix flake exposing the package + an HM configuration
│   ├── flake.nix        #   packages.halley + homeConfigurations.mikuri
│   └── halley.nix       #   Rust derivation (callPackage-able)
└── LICENSE / CONTRIBUTING.md / CHANGELOG.md  # straight from upstream

About

Spatial Wayland compositor built around infinite workspace navigation

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages