Skip to content

Released Sep 2026

Record sheet · No. 147

Phantomat

A Hyprland plugin that puts every window on one endless canvas, then flies the camera to whichever one you type.

Screenshot of Phantomat
Editor screenshot, 1 Nov 2026Phantomat ↗

What it is

Tiling window managers divide the desktop into workspaces, and an overview only shows them for a moment. With a desk full of windows open, the day goes into remembering which workspace holds what, and a second monitor adds a second set of places to remember.

Phantomat makes the overview the desktop. Every window keeps a position on one plane; a monitor is a camera looking at part of it; zooming out pulls the camera back through a curved lens, and typing part of a title flies the camera to the matching window. Workspaces become places on the canvas, and a window can sit across the seam between two screens.

It is a plugin, not a compositor. It loads into Hyprland, takes over the workspace renderer through function hooks, and keeps the window model Hyprland already has. The builder forked hyprland-scroll-overview, kept its history, and added the canvas layer in a single day with Claude Opus 5.5; the commits say so in their trailers, and the launch post says so in the builder's own words.

The result is a serious piece of systems code with a narrow support surface: no releases, installation from source, open issues, and a README that says it has been used daily on one setup. Hyprland updates can break it until it is rebuilt.

Who built it

A design engineer in Portsmouth, UK. His X bio reads Fractional design engineer for startups. Clients backed by YC, $20M+ raised. 2 slots for November. His GitHub account dates from 2014 and carries 24 public repositories; most of them are visual work, including monolith-terrain, a Three.js topographic map with 105 stars, machine-sight, a Three.js perception lens, and omarchy-cosmos-screensaver, a GLSL screensaver. He made 9 of the 14 commits that sit on top of the upstream plugin, and all 9 credit Claude Opus 5.5 as a co-author.

How it is put together

The parts · 8

Phantomat treats the desktop as a scene with a camera, and treats Hyprland as the renderer it borrows. Every managed window gets a box in one world coordinate space; each monitor owns a camera offset and a zoom into that space; the render path draws the part each camera sees. The plugin does not reimplement the compositor. It hooks the functions that draw workspaces, schedule frames, route surface damage and place popups, and substitutes a canvas scene for the workspace scene. That choice keeps Hyprland's window model, input routing and protocol support, and it puts the project's maintenance burden on the internal function signatures it hooks. The canvas layer is split into modules with narrow jobs: Navigator for search and selection, Hud for the overlay, BarrelShader for the lens, Memory for persistence, Config for the Lua surface, and Window for the X11 and popup translations. The largest file, scrollOverview.cpp, remains the place where the canvas state and the render loop meet.

main.cpp
Plugin entry and lifecycle. Declares 14 CFunctionHook pointers, installs and removes them, exposes PLUGIN_API_VERSION, and fails with a notification when another overview plugin already holds the hooks.
scrollOverview.cpp / scrollOverview.hpp
The canvas itself: CScrollOverview, one per monitor, with camera offset, zoom, window boxes, linked-screen camera sharing, fullscreen, fill and pin state, the render loop and the input forwarding. 9,305 lines in the .cpp.
Navigator.cpp
Type-to-find: folds text, scores tokens against title, class and category, orders results, draws app icons, and implements the arrow-key geometry and the Alt-Tab switcher.
Hud.cpp / Tuning.cpp
The overlay and the live tuner: palette, minimap, key sheet, corner readouts, and the settings list that writes each adjustment to the tuning Lua file.
BarrelShader.cpp / shaders/barrel.frag
The final-pass lens: barrel distortion, edge blur, vignette and chromatic fringe, with the HUD and minimap composited after the warp.
Memory.cpp
Layout persistence: a TSV file under XDG_STATE_HOME, at most 96 window entries, a camera per monitor, and sanity checks on every value loaded.
Config.cpp / examples/spatialoverview.lua
The Lua surface: 96 config values and six Lua functions under plugin.spatialoverview, plus the example file the installer copies.
tests/ and scripts/
17 nested Python tests with C helpers, and the install, uninstall and safe-unload scripts.

Choices, and the alternative

  • Fork hyprland-scroll-overview instead of writing a compositor over a new compositor or a standalone overview

    The upstream supplies the Hyprland plugin plumbing, the workspace renderer and the fixes already in its history. the fork keeps that history and credits it. The cost is a 9,305-line scrollOverview.cpp and 386 upstream commits the new project has to carry.

  • Hook 14 compositor functions over the public plugin API alone

    A custom workspace renderer and a custom input route are not in the public API; the hooks are what let the canvas replace the workspace scene. The cost is version fragility: issue #20 reports the build failing on Hyprland 0.57.

  • Treat the monitors as one linked desk by default over one independent canvas per monitor

    Linked cameras keep a window's position continuous across the seam and make the two screens one space; canvas.linked_screens = false keeps the separate-camera mode for people who want it. The cost is a more complex focus and fullscreen model.

  • Keep the spatialoverview names after renaming the product over renaming everything

    The plugin id, settings file, dispatchers and hyprctl command keep working for existing configs; only what people read changes. The cost is two names in the product, and a README paragraph explaining why.

  • Store layout in a plain TSV and settings in Lua over a database or a settings UI

    The memory file is inspectable, tolerant of damaged lines and small enough to read; the Lua files match Omarchy's config and let the live tuner write changes as they are made. The cost is a second tuning file and an order of application the user has to know.

Read fromREADME.md, docs/window-rules.md, main.cpp, scrollOverview.cpp, scrollOverview.hpp, Navigator.cpp, Memory.cpp, Config.cpp, BarrelShader.cpp, shaders/barrel.frag, Hud.cpp, Tuning.cpp, Window.cpp, tests/ and scripts/install.sh in kaolti/phantomat at main, read 2026-11-02; the nine commit messages and file lists from the GitHub API; hyprpm.toml, CMakeLists.txt and examples/spatialoverview.lua.

Build log

7 stages
  1. 01

    The desktop a tiling window manager hides

    Hyprland tiles windows into workspaces. A workspace is a screenful; switching to another one is a keypress, and the windows on the old one stop being visible. An overview, the zoomed-out grid most compositors offer, is a temporary look: hold a key, see the shapes, pick one, and the grid closes. The desktop is still a stack of screens, not a space. That is the gap Phantomat aims at. Its README calls it a zoomable, infinite-canvas window manager: every window lives on one endless plane instead of in workspaces. The monitor is a camera onto that plane, not the plane itself. Zooming out is not a mode that ends when you pick a window; the canvas persists, and the 100% view is the same canvas seen close up. The builder put the motive in the launch post: I wanted infinite canvas for my desktop. So I built it with Omarchy and Opus. The target user is someone with many windows and more than one monitor, the kind of person who already uses an overview often enough to want it to stay open. Phantomat is not a compositor. It is a Hyprland plugin, and it needs a Hyprland new enough to expose the Lua configuration it reads. That narrows the audience to Linux users on Hyprland, mostly the Omarchy distribution the builder uses, and it is why the README's install section begins with Hyprland 0.56 or newer.

  2. 02

    A design engineer, a fork, and one day of Opus

    The builder is Zsolt Kacso, kaolti on GitHub and X. His public repositories are mostly visual: monolith-terrain, a Three.js topographic map with 105 stars; machine-sight, a Three.js perception lens; omarchy-cosmos-screensaver, a GLSL screensaver. Phantomat is the outlier: a C++ system plugin. It is a fork. yayuuu/hyprland-scroll-overview is a Hyprland plugin that scrolls workspaces like Niri; it was created on 2026-04-18, has 515 stars and 47 forks, and was still being pushed on 2026-11-01. Phantomat's README credits yayuuu, Daniel Skorupa, Vaxry and the Hypr Development team, and the upstream history is kept in the repository. The GitHub API counts 400 commits on main; 386 of them are upstream, and 14 were made after the fork point. The 14 are where the canvas work is. Nine are by Kacso, all dated 2026-09-24, from 08:05:18 to 22:38:31 UTC: 14 hours 33 minutes. All nine carry Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>. Together they add 18,209 lines and remove 3,195. The first commit alone changes 62 files, adds 14,087 and removes 2,950, and rewrites scrollOverview.cpp by +6,538/−2,160 while adding Navigator.cpp, Hud.cpp, BarrelShader.cpp, Memory.cpp, Tuning.cpp, Icons.cpp, Popups.cpp, the lens shader, the install scripts and a nested-test harness. Eighteen minutes after the last commit, at 22:56:09Z, he posted the launch: I wanted infinite canvas for my desktop. So I built it with Omarchy and Opus. I'm calling it Phantomat. The post carries a 47-second 3840×2160 demo video and, at the reading on 2026-11-02, 1,181 likes, 75 retweets and 69 replies. The other five commits after the fork are other people's. Paul Harfas made three, Pablo made one and Eo made one. Pablo's commit, which draws the HUD and minimap upright on rotated monitors, carries a Cursor co-author trailer. The trailers name the model, not the host: nothing in the repository says whether the agent was Claude Code, another harness, or a mixture. What the repository does show is that nine commits are the builder's entire contribution and that Claude Opus 5.5 is credited on every one of them.

  3. 03

    The canvas is a renderer and an input router

    main.cpp is the entry point. It declares 14 CFunctionHook pointers and hooks the compositor functions the canvas has to replace: renderWorkspace, two damage paths, scheduleFrame, sendFrameEventsToWorkspace, surface frame, two drawTex paths, popup reposition, drag-target begin, and three X11 configure and message paths. PLUGIN_API_VERSION returns HYPRLAND_API_VERSION, so a build is tied to the headers it was compiled against. CScrollOverview is the canvas object, one per monitor. It holds a camera offset and a zoom, maps a window's world box to a screen box (canvasWorldToScreen) and back (canvasScreenToWorld), and decides which windows a canvas draws. With canvas.linked_screens on, the monitors show adjacent parts of one plane and their cameras move together; with it off, each monitor has its own camera. The header exposes the operations the canvas needs: landOnWindow, summonWindow, fitAllWindows, panCamera, zoomCameraBy, nudgeWindow, canvasRedo, followCanvasWindow, checkpointCanvas, saveSharedCanvasLayout. The hooks are the design. Hyprland's public plugin API does not offer a custom workspace renderer or a custom input route, so the plugin replaces the functions that draw workspaces and handle surface frames, then draws its own scene. The same interception is what makes X11 windows usable on a canvas: an X11 client knows only the position the X server holds, which on the canvas is often not where the window is drawn. Window.cpp re-sends the drawn position and translates the positions the app asks for back. Popups are drawn fixed to the screen instead of on the canvas, because a menu that opens at a transformed position is a menu the pointer cannot hit. This is why the plugin is powerful and fragile in the same place. A canvas that owns the render path can put every window on one plane; it also owns the contract with the compositor's internals, and that contract changes between Hyprland versions.

  4. 04

    Navigator, lens, HUD, and the files that remember

    The visible layer is four programs. Navigator.cpp is 689 lines: it folds text to a comparable form, scores each token against the title, class and category of every window, sorts the results, and draws the palette with app icons. The arrow keys follow Android's rules: a candidate has to reach further in that direction with both edges and lie within 45° of the side; a window in line with the current one comes first. Alt+Tab uses the same selection model for recent windows. BarrelShader.cpp and shaders/barrel.frag are the lens. The fragment shader is 208 lines and does the barrel distortion, edge blur, vignette and red/blue fringe in one final pass. The minimap and the search palette are composited after the lens, so the text stays flat while the desktop bends. Hud.cpp is 1,070 lines of palette, minimap, key sheet and corner readouts; Tuning.cpp is 440 lines of live tuner that writes each change to spatialoverview-tuning.lua as it is made. Memory.cpp is the smallest piece and the one that makes the canvas feel persistent. It writes a tab-separated file at $XDG_STATE_HOME/spatial-overview/canvas-memory.tsv (or ~/.local/state/...), keeps at most 96 window entries, stores a camera per monitor, and rejects non-finite or absurd geometry before it reaches the scene. A damaged line costs that one window its memory, not the file. Config.cpp is the surface: 96 addConfigValueV2 calls and six Lua functions, all under plugin.spatialoverview, from canvas.linked_screens and canvas.persistent to navigator.accent and distortion.chromatic. hyprctl spatialoverview prints the canvases' state as JSON. The live tuner writes a second Lua file that is applied after the main one, so a tuned value wins until its line is deleted.

  5. 05

    What it asks of the machine

    The build is C++23 with CMake, and there are Makefile, Meson and Nix flake paths beside it. The target links hyprland, hyprgraphics, pangocairo, pixman-1, libdrm, libinput, libudev, wayland-server, xkbcommon and Lua 5.4. The installer checks for g++ 15 or newer, make, pkg-config, python3, and those development packages; on Arch or Omarchy the package line is base-devel git hyprland hyprgraphics pango lua. scripts/install.sh is 114 lines and does more than copy a file. It refuses to run without ~/.config/hypr/hyprland.lua, compares the installed Hyprland headers with the running compositor, builds spatialoverview.so, installs it under ~/.local/share/spatial-overview/, copies examples/spatialoverview.lua if the user has none, backs up hyprland.lua, appends a marked block that loads the plugin and the settings, and calls hyprctl plugin load. scripts/uninstall.sh removes the block and restores the layout. There are no GitHub releases and no tags. Installation is from a checkout, and the README says to run the installer again after a Hyprland update because the plugin is built against the headers. hyprpm.toml exists for Hyprland's plugin manager, with make all as the build command, but the supported path in the README is the shell installer. The machine requirements are modest by model standards and steep by desktop standards: no GPU model is named beyond the tested NVIDIA setup, but the plugin needs a working Hyprland 0.56 or newer with its Lua config, a C++23 compiler new enough to be GCC 15, and development headers that match the running compositor. The cost is setup time and the maintenance that comes with a source build.

  6. 06

    Seventeen test files, fifteen open issues, one setup

    The test suite runs a nested Hyprland inside a window and drives it with Python. There are 17 files in tests/, 15 of them *-nested.py, plus tests/nested.lua, an X11 test app, a virtual-pointer protocol description and a probe that measures frames per second. The names map to the rules: navigator, fullscreen, fullscreen-cases, keys, linked, fill, places, arrows, drag, popup, tuner, framerate, multimonitor, x11, install. The window-rules document states the invariant each one checks: no other window moves, the window stays floating and drawn, both screens stay in the same view, and zooming out and back changes nothing. The tests are the part of the repository that most clearly came from the same day as the features. The commit message for the frame fix says a window showed 15 fps before and 60 after; tests/framerate-nested.py is the measurement, and tests/tools/fps-probe.py is the window that animates on every frame it is given. The X11 commit adds tests/x11-nested.py, tests/tools/x11-menu.c and tests/tools/wl-click.py. The support surface is narrower than the test list suggests. On 2026-11-02 the repository has 15 open issues and pull requests, no releases and no tags. Issue #20, opened 2026-10-30, says the build fails on Hyprland 0.57.0 because desktop/Workspace.hpp no longer exists. Issue #21 reports a visible window throttled to 15–60 fps at 240 Hz. Issue #18 reports drag-and-drop broken in canvas mode. The README is direct about the reason: This hooks deep into Hyprland internals, so a Hyprland update can break it until it is updated too. It has been used daily on one setup (Omarchy, Hyprland 0.56.2, NVIDIA, two monitors); other setups are less tested. There is no CI directory in the tree. The nested tests are run by hand, and the last push is 2026-10-08, three weeks before the second wave of attention.

  7. 07

    246 stars, a launch video, and a second wave

    The GitHub reading on 2026-11-02 is 246 stars, 20 forks, 1 watcher, 15 open issues and pull requests, 0 releases and 0 tags, under BSD-3-Clause. The repository was created on 2026-09-24T08:07:06Z, two minutes after the first commit's timestamp, and its last push is 2026-10-08T09:45:55Z. The upstream it forked, yayuuu/hyprland-scroll-overview, has 515 stars and 47 forks. The first wave is the launch post. On 2026-09-24 at 22:56:09Z, Kacso posted the 47-second demo video with the sentence about wanting an infinite canvas and building it with Omarchy and Opus. At the reading it has 1,181 likes, 75 retweets and 69 replies. The replies are short and technical: one person says he tried an infinite-canvas concept years earlier and likes the choices here; another says it would suit a Vision Pro; another just says it is good. The second wave is a creator pick. On 2026-10-31 at 21:00:09Z, @OmarchyUpdates, a community-run account with 1,878 followers and the bio Independent Omarchy updates: releases, PR watch and fixes you can copy, posted a short recommendation. That post has 121 likes, 11 retweets, 6 replies and 67 bookmarks, and X's trending page Omarchy Linux Expands to Phones, TVs and Easy Installs embeds it alongside hop and OmarchyTV. The second wave came three weeks after the code stopped moving; it is attention on the idea, not on a new release. Against the upstream, the numbers are a derivative's numbers: 246 stars against 515, 14 own commits against 386 upstream ones. Against the launch post, the stars are smaller than the likes. The video did the work, and the repository's own last push predates the second wave.

What they would tell you

  • Nine commits, all with Claude Opus 5.5 in the trailer, add 18,209 lines and remove 3,195 in 14 hours 33 minutes. That is the AI-written delta. The other 386 commits are the upstream plugin, and the 246 stars sit on both. The model gets credit for the canvas layer, not for the Hyprland plugin plumbing underneath it.
  • The launch post has 1,181 likes and a 47-second 4K video; the repository has 246 stars. The video is the thing that travelled. The second wave, 121 likes on a community account five weeks after launch, arrived when the last push was already three weeks old.
  • The 9,305-line scrollOverview.cpp is the price of the fork. The initial commit changed 6,538 lines in it and added ten new modules around it; the new code is modular, and the file it plugs into is not. Anyone reviewing the canvas has to read a 9,305-line translation unit.
  • Fourteen internal function hooks are the mechanism and the risk. Issue #20 says the build fails on Hyprland 0.57 because a header moved; the README says an update can break the plugin until it is rebuilt. A plugin that owns the render path is a bet on a moving internal API.
  • The support surface is one setup. The README says Omarchy, Hyprland 0.56.2, NVIDIA and two monitors; issue #21 reports 15–60 fps at 240 Hz, issue #18 reports drag-and-drop broken, and there are 15 open issues and no releases. The tests are real, and they do not cover the configurations the issues come from.
  • The trailers are co-author credits, not line-level provenance. They establish that the model was at the table for every commit; they do not say which lines it wrote, and the commit messages, which read like behavioural specs, are the better record of what was intended.
  • The rename is a compatibility decision. The product is Phantomat; the plugin id, settings file and dispatcher are still spatialoverview, and the README explains that existing configs keep working. The name from Lem is the user-facing half; the old name is the part that has to stay stable.

Adjacent records

All records →