Hyprland plugin for an i3 / sway like manual tiling layout
C++
1,197
455 commits
updated Oct 12, 2026
i3 / sway like layout for hyprland.
Check the changelog for a list of new features and improvements
Additional features may be suggested in the repo issues or the matrix room.
In addition to hy3, I maintain Quickshell, a toolkit for creating custom bars, widgets, lockscreens, and other desktop shell components with first class support for Hyprland.
If that sounds interesting, check out the website.
hy3 has a tagged release for each hyprland update, and master tracks hyprland's main branch.
If you are running a release version of hyprland then use the matching tagged hy3 version.
If you are running an untagged hyprland release then use the master branch of hy3.
Commits are tested before pushing and will build against the hyprland release in the flake.lock file. There may be a mismatch with hyprland's main branch. If hy3 fails to build against hyprland's main branch please make an issue or ping me in the hy3 matrix room.
Tagged hy3 versions are always checked against the corresponding hyprland tag.
If you encounter any bugs, please report them in the issue tracker.
When reporting bugs, please include:
[!IMPORTANT] The master branch of hy3 follows the master branch of hyprland. Attempting to use a mismatched hyprland release will result in failure when building or loading hy3.
To use hy3 against a release version of hyprland, check out the matching hy3 tag for the hyprland version. hy3 tags are formatted as
hl{version}where{version}matches the release version of hyprland.
Assuming you use hyprland's home manager module, you can easily integrate hy3 by adding it to the plugins array.
# flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1&ref={version}";
# where {version} is the hyprland release version
# or "github:hyprwm/Hyprland?submodules=1" to follow the development branch
hy3 = {
url = "github:outfoxxed/hy3?ref=hl{version}"; # where {version} is the hyprland release version
# or "github:outfoxxed/hy3" to follow the development branch.
# (you may encounter issues if you dont do the same for hyprland)
inputs.hyprland.follows = "hyprland";
};
};
outputs = { nixpkgs, home-manager, hyprland, hy3, ... }: {
homeConfigurations."user@hostname" = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
modules = [
hyprland.homeManagerModules.default
{
wayland.windowManager.hyprland = {
enable = true;
plugins = [ hy3.packages.x86_64-linux.hy3 ];
};
}
];
};
};
}
hy3's binary is availible as ${hy3.packages.<system>.hy3}/lib/libhy3.so, so you can also
directly use it in your hyprland config like so:
# ...
wayland.windowManager.hyprland = {
# ...
extraConfig = ''
plugin = ${hy3.packages.x86_64-linux.hy3}/lib/libhy3.so
'';
};
Hyprland now has a dedicated plugin manager, which should be used when your package manager isn't capable of locking hy3 builds to the correct hyprland version.
[!IMPORTANT] Make sure hyprpm is activated by putting
exec-once = hyprpm reload -nin your hyprland.conf. (See the wiki for details.)
To install hy3 via hyprpm run
hyprpm add https://github.com/outfoxxed/hy3
To update hy3 (and all other plugins), run
hyprpm update
Sometimes the headers from hyprland are not updated, if this happens run (See issue #109 for an example of where this happened)
hyprpm update -f
(See the wiki for details.)
[!WARNING] When you are running a tagged hyprland version hyprpm (0.34.0+) will build against hy3's corrosponding release. However if you are running an untagged build (aka
-git) hyprpm will build against hy3's latest commit. This means if you are running an out of date untagged build of hyprland, hyprpm may pick an incompatible revision of hy3.To fix this problem you will either need to update hyprland or manually build the correct version of hy3.
Install hyprland, including its headers and pkg-config file, then run the following commands:
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
The plugin will be located at build/libhy3.so, and you can load it normally
(See the hyprland wiki for details.)
Note that the hyprland headers and pkg-config file MUST be installed correctly, for the target version of hyprland.
[!NOTE] This method of installation is deprecated and you should use hyprpm instead, as it is simpler and less error prone.
[!CAUTION] Pacman is not very reliable when it comes to building packages in the correct order. If you get a notification saying hy3 was compiled for a different version of hyprland then your packages likely updated in the wrong order, or you have hyprland headers in
/usr/local.To fix this, remove
/usr/include/hyprland,/usr/local/include/hyprland,/usr/share/pkgconfig/hyprland.pcand/usr/local/share/pkgconfig/hyprland.pc, then reinstall hyprland and hy3.If you know how to fix this please open an issue or pr, or message
@outfoxxed:outfoxxed.mein the matrix room.
hy3 stable (for arch's hyprland package) is availible on the AUR as hy3.
hy3-git (for hyprland-git on the AUR, unofficial package) is availible on the AUR as hy3-git.
Both packages install hy3 as /usr/lib/libhy3.so.
You can enable it in your hyprland configuration by adding the following line anywhere in your hyprland.conf
plugin = /usr/lib/libhy3.so
[!IMPORTANT] The configuration listed below is for the current hy3 commit. If you are using a release version of hy3 then make sure you are reading the tagged revision of this readme.
Set your general:layout to hy3 in hyprland.conf.
hy3 requires using a few custom dispatchers for normal operation. In your hyprland config replace the following dispatchers:
movefocus -> hy3:movefocusmovewindow -> hy3:movewindowYou can use hy3:makegroup to create a new split.
The dispatcher list and config fields sections have all the configuration options, and some explanation as to what they do. The hyprland config in my dots can also be used as a reference.
plugin {
hy3 {
# policy controlling what happens when a node is removed from a group,
# leaving only a group
# 0 = remove the nested group
# 1 = keep the nested group
# 2 = keep the nested group only if its parent is a tab group
node_collapse_policy = <int> # default: 2
# offset from group split direction when only one window is in a group
group_inset = <int> # default: 10
# if a tab group will automatically be created for the first window spawned in a workspace
tab_first_window = <bool>
# tab group settings
tabs {
# height of the tab bar
height = <int> # default: 22
# padding between the tab bar and its focused node
padding = <int> # default: 6
# the tab bar should animate in/out from the top instead of below the window
from_top = <bool> # default: false
# radius of tab bar corners
radius = <int> # default: 6
# tab bar border width
border_width = <int> # default: 2
# render the window title on the bar
render_text = <bool> # default: true
# center the window title
text_center = <bool> # default: true
# font to render the window title with
text_font = <string> # default: Sans
# height of the window title
text_height = <int> # default: 8
# left padding of the window title
text_padding = <int> # default: 3
colors {
# active tab bar segment colors
active = <color> # default: rgba(33ccff40)
active_border = <color> # default: rgba(33ccffee)
active_text = <color> # default: rgba(ffffffff)
# active tab bar segment colors for bars on an unfocused monitor
active_alt_monitor = <color> # default: rgba(60606040)
active_alt_monitor_border = <color> # default: rgba(808080ee)
active_alt_monitor_text = <color> # default: rgba(ffffffff)
# focused tab bar segment colors (focused node in unfocused container)
focused = <color> # default: rgba(60606040)
focused_border = <color> # default: rgba(808080ee)
focused_text = <color> # default: rgba(ffffffff)
# inactive tab bar segment colors
inactive = <color> # default: rgba(30303020)
inactive_border = <color> # default: rgba(606060aa)
inactive_text = <color> # default: rgba(ffffffff)
# urgent tab bar segment colors
urgent = <color> # default: rgba(ff223340)
urgent_border = <color> # default: rgba(ff2233ee)
urgent_text = <color> # default: rgba(ffffffff)
# locked tab bar segment colors
locked = <color> # default: rgba(90903340)
locked_border = <color> # default: rgba(909033ee)
locked_text = <color> # default: rgba(ffffffff)
}
# if tab backgrounds should be blurred
# Blur is only visible when the above colors are not opaque.
blur = <bool> # default: true
# opacity multiplier for tabs
# Applies to blur as well as the given colors.
opacity = <float> # default: 1.0
}
# autotiling settings
autotile {
# enable autotile
enable = <bool> # default: false
# make autotile-created groups ephemeral
ephemeral_groups = <bool> # default: true
# if a window would be squished smaller than this width, a vertical split will be created
# -1 = never automatically split vertically
# 0 = always automatically split vertically
# <number> = pixel width to split at
trigger_width = <int> # default: 0
# if a window would be squished smaller than this height, a horizontal split will be created
# -1 = never automatically split horizontally
# 0 = always automatically split horizontally
# <number> = pixel height to split at
trigger_height = <int> # default: 0
# a space or comma separated list of workspace ids where autotile should be enabled
# it's possible to create an exception rule by prefixing the definition with "not:"
# workspaces = 1,2 # autotiling will only be enabled on workspaces 1 and 2
# workspaces = not:1,2 # autotiling will be enabled on all workspaces except 1 and 2
workspaces = <string> # default: all
}
}
}
hy3:makegroup, <h | v | opposite | tab>, [toggle], [ephemeral | force_ephemeral] - make a vertical / horizontal split or tab group
toggle - if the focused node is the only child of its parent, which is of the type specified, the node's parent will be removed.ephemeral - the group will be removed once it contains only one node. does not affect existing groups.force_ephemeral - same as ephemeral, but converts existing single windows groups.hy3:changegroup, <h | v | tab | untab | toggletab | opposite> - change the group the node belongs to, to a different layout
untab will untab the group if it was previously tabbedtoggletab will untab if group is tabbed, and tab if group is untabbedopposite will toggle between horizontal and vertical layouts if the group is not tabbed.hy3:setephemeral, <true | false> - change the ephemerality of the group the node belongs tohy3:movefocus, <l | u | d | r | left | down | up | right>, [visible], [warp | nowarp] - move the focus left, up, down, or right
visible - only move between visible nodes, not hidden tabswarp - warp the mouse to the selected window, even if general:no_cursor_warps is true.nowarp - does not warp the mouse to the selected window, even if general:no_cursor_warps is false.hy3:warpcursor - warp the cursor to the center of the focused nodehy3:movewindow, <l | u | d | r | left | down | up | right>, [once], [visible] - move a window left, up, down, or right
once - only move directly to the neighboring group, without moving into any of its subgroupsvisible - only move between visible nodes, not hidden tabshy3:movetoworkspace, <workspace>, [follow, [warp | nowarp]] - move the active node to the given workspace
follow - change focus to the given workspace when moving the selected nodewarp - warp the mouse to the selected window, even if general:no_cursor_warps is true.nowarp - does not warp the mouse to the selected window, even if general:no_cursor_warps is false.hy3:killactive - close all windows in the focused nodehy3:changefocus, <top | bottom | raise | lower | tab | tabnode>
top - focus all nodes in the workspacebottom - focus the single root selection windowraise - raise focus one levellower - lower focus one leveltab - raise focus to the nearest tabtabnode - raise focus to the nearest node under the tabhy3:togglefocuslayer, [nowarp] - toggle focus between tiled and floating layers
nowarp - do not warp the mouse to the newly focused windowhy3:focustab, [l | r | left | right | index, <index>], [prioritize_hovered | require_hovered], [wrap]
l | r | left | right - direction to change focus towardsindex, <index> - select the indexth tabprioritize_hovered - prioritize the tab group under the mouse when multiple are stacked. use the lowest group if none is under the mouse.require_hovered - affect the tab group under the mouse. do nothing if none are hovered.wrap - wrap to the opposite size of the tab bar if moving off the endhy3:locktab, [lock | unlock] - lock the current tab, makingg it behave like a nodehy3:debugnodes - print the node tree into the hyprland loghy3:setswallow, <true | false | toggle> - set the containing node's window swallow statehy3:expand, <expand | shrink | base> - expand the current node to cover other nodes
expand - expand by one nodeshrink - shrink by one nodebase - undo all expansionshy3:equalize, [workspace] - equalize window sizes in group
workspace: equalizes all windows across the entire workspace treeWhen using Hyprland's Lua config, hy3 exposes dispatcher factories under hl.plugin.hy3.
The returned functions can be passed to hl.bind(...).
local hy3 = hl.plugin.hy3
-- all factories return dispatcher functions and dispatchers return no values
-- option tables are optional except for focus_tab
hy3.make_group("h" | "v" | "tab" | "opposite", {
toggle = true | false, -- default: false
ephemeral = true | false | "force", -- default: false
})
hy3.change_group("h" | "v" | "tab" | "untab" | "toggletab" | "opposite")
hy3.set_ephemeral(true | false | "true" | "false")
hy3.move_focus("l" | "r" | "u" | "d" | "left" | "right" | "up" | "down", {
visible = true | false, -- default: false
warp = true | false, -- default: follows cursor:no_warps
})
hy3.toggle_focus_layer({
warp = true | false, -- default: true
})
hy3.warp_cursor()
hy3.move_window("l" | "r" | "u" | "d" | "left" | "right" | "up" | "down", {
once = true | false, -- default: false
visible = true | false, -- default: false
})
hy3.move_to_workspace("<workspace>", {
follow = true | false, -- default: false
warp = true | false, -- default: follows cursor:no_warps when follow = true
})
hy3.change_focus("top" | "bottom" | "raise" | "lower" | "tab" | "tabnode")
-- direction and index are mutually exclusive
hy3.focus_tab({
direction = "l" | "r" | "left" | "right",
mouse = "ignore" | "prioritize_hovered" | "require_hovered", -- default: "ignore"
wrap = true | false, -- default: false
})
hy3.focus_tab({
index = <number>,
mouse = "ignore" | "prioritize_hovered" | "require_hovered", -- default: "ignore"
wrap = true | false, -- default: false
})
hy3.set_swallow(true | false | "true" | "false" | "toggle")
hy3.kill_active()
hy3.expand("expand" | "shrink" | "base" | "maximize" | "fullscreen", {
fullscreen = "" | "intermediate_maximize" | "fullscreen_maximize" | "maximize_only",
})
hy3.lock_tab(nil | "" | "toggle" | "lock" | "unlock")
hy3.equalize({
scope = "" | "group" | "workspace", -- default: "group"
workspace = true | false, -- overrides scope if present
recursive = true | false, -- overrides workspace if present
})
hy3.debug_nodes()
579 followers · starred Aug 2026
71 followers · starred Jan 2024
831 followers · starred Jan 2024
423 followers · starred Nov 2025
Hyprland plugin for an i3 / sway like manual tiling layout
C++
1,197
455 commits
updated Oct 12, 2026
i3 / sway like layout for hyprland.
Check the changelog for a list of new features and improvements
Additional features may be suggested in the repo issues or the matrix room.
In addition to hy3, I maintain Quickshell, a toolkit for creating custom bars, widgets, lockscreens, and other desktop shell components with first class support for Hyprland.
If that sounds interesting, check out the website.
hy3 has a tagged release for each hyprland update, and master tracks hyprland's main branch.
If you are running a release version of hyprland then use the matching tagged hy3 version.
If you are running an untagged hyprland release then use the master branch of hy3.
Commits are tested before pushing and will build against the hyprland release in the flake.lock file. There may be a mismatch with hyprland's main branch. If hy3 fails to build against hyprland's main branch please make an issue or ping me in the hy3 matrix room.
Tagged hy3 versions are always checked against the corresponding hyprland tag.
If you encounter any bugs, please report them in the issue tracker.
When reporting bugs, please include:
[!IMPORTANT] The master branch of hy3 follows the master branch of hyprland. Attempting to use a mismatched hyprland release will result in failure when building or loading hy3.
To use hy3 against a release version of hyprland, check out the matching hy3 tag for the hyprland version. hy3 tags are formatted as
hl{version}where{version}matches the release version of hyprland.
Assuming you use hyprland's home manager module, you can easily integrate hy3 by adding it to the plugins array.
# flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1&ref={version}";
# where {version} is the hyprland release version
# or "github:hyprwm/Hyprland?submodules=1" to follow the development branch
hy3 = {
url = "github:outfoxxed/hy3?ref=hl{version}"; # where {version} is the hyprland release version
# or "github:outfoxxed/hy3" to follow the development branch.
# (you may encounter issues if you dont do the same for hyprland)
inputs.hyprland.follows = "hyprland";
};
};
outputs = { nixpkgs, home-manager, hyprland, hy3, ... }: {
homeConfigurations."user@hostname" = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
modules = [
hyprland.homeManagerModules.default
{
wayland.windowManager.hyprland = {
enable = true;
plugins = [ hy3.packages.x86_64-linux.hy3 ];
};
}
];
};
};
}
hy3's binary is availible as ${hy3.packages.<system>.hy3}/lib/libhy3.so, so you can also
directly use it in your hyprland config like so:
# ...
wayland.windowManager.hyprland = {
# ...
extraConfig = ''
plugin = ${hy3.packages.x86_64-linux.hy3}/lib/libhy3.so
'';
};
Hyprland now has a dedicated plugin manager, which should be used when your package manager isn't capable of locking hy3 builds to the correct hyprland version.
[!IMPORTANT] Make sure hyprpm is activated by putting
exec-once = hyprpm reload -nin your hyprland.conf. (See the wiki for details.)
To install hy3 via hyprpm run
hyprpm add https://github.com/outfoxxed/hy3
To update hy3 (and all other plugins), run
hyprpm update
Sometimes the headers from hyprland are not updated, if this happens run (See issue #109 for an example of where this happened)
hyprpm update -f
(See the wiki for details.)
[!WARNING] When you are running a tagged hyprland version hyprpm (0.34.0+) will build against hy3's corrosponding release. However if you are running an untagged build (aka
-git) hyprpm will build against hy3's latest commit. This means if you are running an out of date untagged build of hyprland, hyprpm may pick an incompatible revision of hy3.To fix this problem you will either need to update hyprland or manually build the correct version of hy3.
Install hyprland, including its headers and pkg-config file, then run the following commands:
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
The plugin will be located at build/libhy3.so, and you can load it normally
(See the hyprland wiki for details.)
Note that the hyprland headers and pkg-config file MUST be installed correctly, for the target version of hyprland.
[!NOTE] This method of installation is deprecated and you should use hyprpm instead, as it is simpler and less error prone.
[!CAUTION] Pacman is not very reliable when it comes to building packages in the correct order. If you get a notification saying hy3 was compiled for a different version of hyprland then your packages likely updated in the wrong order, or you have hyprland headers in
/usr/local.To fix this, remove
/usr/include/hyprland,/usr/local/include/hyprland,/usr/share/pkgconfig/hyprland.pcand/usr/local/share/pkgconfig/hyprland.pc, then reinstall hyprland and hy3.If you know how to fix this please open an issue or pr, or message
@outfoxxed:outfoxxed.mein the matrix room.
hy3 stable (for arch's hyprland package) is availible on the AUR as hy3.
hy3-git (for hyprland-git on the AUR, unofficial package) is availible on the AUR as hy3-git.
Both packages install hy3 as /usr/lib/libhy3.so.
You can enable it in your hyprland configuration by adding the following line anywhere in your hyprland.conf
plugin = /usr/lib/libhy3.so
[!IMPORTANT] The configuration listed below is for the current hy3 commit. If you are using a release version of hy3 then make sure you are reading the tagged revision of this readme.
Set your general:layout to hy3 in hyprland.conf.
hy3 requires using a few custom dispatchers for normal operation. In your hyprland config replace the following dispatchers:
movefocus -> hy3:movefocusmovewindow -> hy3:movewindowYou can use hy3:makegroup to create a new split.
The dispatcher list and config fields sections have all the configuration options, and some explanation as to what they do. The hyprland config in my dots can also be used as a reference.
plugin {
hy3 {
# policy controlling what happens when a node is removed from a group,
# leaving only a group
# 0 = remove the nested group
# 1 = keep the nested group
# 2 = keep the nested group only if its parent is a tab group
node_collapse_policy = <int> # default: 2
# offset from group split direction when only one window is in a group
group_inset = <int> # default: 10
# if a tab group will automatically be created for the first window spawned in a workspace
tab_first_window = <bool>
# tab group settings
tabs {
# height of the tab bar
height = <int> # default: 22
# padding between the tab bar and its focused node
padding = <int> # default: 6
# the tab bar should animate in/out from the top instead of below the window
from_top = <bool> # default: false
# radius of tab bar corners
radius = <int> # default: 6
# tab bar border width
border_width = <int> # default: 2
# render the window title on the bar
render_text = <bool> # default: true
# center the window title
text_center = <bool> # default: true
# font to render the window title with
text_font = <string> # default: Sans
# height of the window title
text_height = <int> # default: 8
# left padding of the window title
text_padding = <int> # default: 3
colors {
# active tab bar segment colors
active = <color> # default: rgba(33ccff40)
active_border = <color> # default: rgba(33ccffee)
active_text = <color> # default: rgba(ffffffff)
# active tab bar segment colors for bars on an unfocused monitor
active_alt_monitor = <color> # default: rgba(60606040)
active_alt_monitor_border = <color> # default: rgba(808080ee)
active_alt_monitor_text = <color> # default: rgba(ffffffff)
# focused tab bar segment colors (focused node in unfocused container)
focused = <color> # default: rgba(60606040)
focused_border = <color> # default: rgba(808080ee)
focused_text = <color> # default: rgba(ffffffff)
# inactive tab bar segment colors
inactive = <color> # default: rgba(30303020)
inactive_border = <color> # default: rgba(606060aa)
inactive_text = <color> # default: rgba(ffffffff)
# urgent tab bar segment colors
urgent = <color> # default: rgba(ff223340)
urgent_border = <color> # default: rgba(ff2233ee)
urgent_text = <color> # default: rgba(ffffffff)
# locked tab bar segment colors
locked = <color> # default: rgba(90903340)
locked_border = <color> # default: rgba(909033ee)
locked_text = <color> # default: rgba(ffffffff)
}
# if tab backgrounds should be blurred
# Blur is only visible when the above colors are not opaque.
blur = <bool> # default: true
# opacity multiplier for tabs
# Applies to blur as well as the given colors.
opacity = <float> # default: 1.0
}
# autotiling settings
autotile {
# enable autotile
enable = <bool> # default: false
# make autotile-created groups ephemeral
ephemeral_groups = <bool> # default: true
# if a window would be squished smaller than this width, a vertical split will be created
# -1 = never automatically split vertically
# 0 = always automatically split vertically
# <number> = pixel width to split at
trigger_width = <int> # default: 0
# if a window would be squished smaller than this height, a horizontal split will be created
# -1 = never automatically split horizontally
# 0 = always automatically split horizontally
# <number> = pixel height to split at
trigger_height = <int> # default: 0
# a space or comma separated list of workspace ids where autotile should be enabled
# it's possible to create an exception rule by prefixing the definition with "not:"
# workspaces = 1,2 # autotiling will only be enabled on workspaces 1 and 2
# workspaces = not:1,2 # autotiling will be enabled on all workspaces except 1 and 2
workspaces = <string> # default: all
}
}
}
hy3:makegroup, <h | v | opposite | tab>, [toggle], [ephemeral | force_ephemeral] - make a vertical / horizontal split or tab group
toggle - if the focused node is the only child of its parent, which is of the type specified, the node's parent will be removed.ephemeral - the group will be removed once it contains only one node. does not affect existing groups.force_ephemeral - same as ephemeral, but converts existing single windows groups.hy3:changegroup, <h | v | tab | untab | toggletab | opposite> - change the group the node belongs to, to a different layout
untab will untab the group if it was previously tabbedtoggletab will untab if group is tabbed, and tab if group is untabbedopposite will toggle between horizontal and vertical layouts if the group is not tabbed.hy3:setephemeral, <true | false> - change the ephemerality of the group the node belongs tohy3:movefocus, <l | u | d | r | left | down | up | right>, [visible], [warp | nowarp] - move the focus left, up, down, or right
visible - only move between visible nodes, not hidden tabswarp - warp the mouse to the selected window, even if general:no_cursor_warps is true.nowarp - does not warp the mouse to the selected window, even if general:no_cursor_warps is false.hy3:warpcursor - warp the cursor to the center of the focused nodehy3:movewindow, <l | u | d | r | left | down | up | right>, [once], [visible] - move a window left, up, down, or right
once - only move directly to the neighboring group, without moving into any of its subgroupsvisible - only move between visible nodes, not hidden tabshy3:movetoworkspace, <workspace>, [follow, [warp | nowarp]] - move the active node to the given workspace
follow - change focus to the given workspace when moving the selected nodewarp - warp the mouse to the selected window, even if general:no_cursor_warps is true.nowarp - does not warp the mouse to the selected window, even if general:no_cursor_warps is false.hy3:killactive - close all windows in the focused nodehy3:changefocus, <top | bottom | raise | lower | tab | tabnode>
top - focus all nodes in the workspacebottom - focus the single root selection windowraise - raise focus one levellower - lower focus one leveltab - raise focus to the nearest tabtabnode - raise focus to the nearest node under the tabhy3:togglefocuslayer, [nowarp] - toggle focus between tiled and floating layers
nowarp - do not warp the mouse to the newly focused windowhy3:focustab, [l | r | left | right | index, <index>], [prioritize_hovered | require_hovered], [wrap]
l | r | left | right - direction to change focus towardsindex, <index> - select the indexth tabprioritize_hovered - prioritize the tab group under the mouse when multiple are stacked. use the lowest group if none is under the mouse.require_hovered - affect the tab group under the mouse. do nothing if none are hovered.wrap - wrap to the opposite size of the tab bar if moving off the endhy3:locktab, [lock | unlock] - lock the current tab, makingg it behave like a nodehy3:debugnodes - print the node tree into the hyprland loghy3:setswallow, <true | false | toggle> - set the containing node's window swallow statehy3:expand, <expand | shrink | base> - expand the current node to cover other nodes
expand - expand by one nodeshrink - shrink by one nodebase - undo all expansionshy3:equalize, [workspace] - equalize window sizes in group
workspace: equalizes all windows across the entire workspace treeWhen using Hyprland's Lua config, hy3 exposes dispatcher factories under hl.plugin.hy3.
The returned functions can be passed to hl.bind(...).
local hy3 = hl.plugin.hy3
-- all factories return dispatcher functions and dispatchers return no values
-- option tables are optional except for focus_tab
hy3.make_group("h" | "v" | "tab" | "opposite", {
toggle = true | false, -- default: false
ephemeral = true | false | "force", -- default: false
})
hy3.change_group("h" | "v" | "tab" | "untab" | "toggletab" | "opposite")
hy3.set_ephemeral(true | false | "true" | "false")
hy3.move_focus("l" | "r" | "u" | "d" | "left" | "right" | "up" | "down", {
visible = true | false, -- default: false
warp = true | false, -- default: follows cursor:no_warps
})
hy3.toggle_focus_layer({
warp = true | false, -- default: true
})
hy3.warp_cursor()
hy3.move_window("l" | "r" | "u" | "d" | "left" | "right" | "up" | "down", {
once = true | false, -- default: false
visible = true | false, -- default: false
})
hy3.move_to_workspace("<workspace>", {
follow = true | false, -- default: false
warp = true | false, -- default: follows cursor:no_warps when follow = true
})
hy3.change_focus("top" | "bottom" | "raise" | "lower" | "tab" | "tabnode")
-- direction and index are mutually exclusive
hy3.focus_tab({
direction = "l" | "r" | "left" | "right",
mouse = "ignore" | "prioritize_hovered" | "require_hovered", -- default: "ignore"
wrap = true | false, -- default: false
})
hy3.focus_tab({
index = <number>,
mouse = "ignore" | "prioritize_hovered" | "require_hovered", -- default: "ignore"
wrap = true | false, -- default: false
})
hy3.set_swallow(true | false | "true" | "false" | "toggle")
hy3.kill_active()
hy3.expand("expand" | "shrink" | "base" | "maximize" | "fullscreen", {
fullscreen = "" | "intermediate_maximize" | "fullscreen_maximize" | "maximize_only",
})
hy3.lock_tab(nil | "" | "toggle" | "lock" | "unlock")
hy3.equalize({
scope = "" | "group" | "workspace", -- default: "group"
workspace = true | false, -- overrides scope if present
recursive = true | false, -- overrides workspace if present
})
hy3.debug_nodes()
579 followers · starred Aug 2026
71 followers · starred Jan 2024
831 followers · starred Jan 2024
423 followers · starred Nov 2025