i3 / sway like layout for hyprland.
- i3 like tiling
- Node based window manipulation (you can interact with multiple windows at once)
- Greatly improved tabbed node groups over base hyprland
- Optional autotiling
Additional features may be suggested in the repo issues or the matrix room.
general.mp4
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 corrosponding hyprland tag.
If you encounter any bugs, please report them in the issue tracker.
When reporting bugs, please include:
- Commit hash of the version you are running.
- Steps to reproduce the bug (if you can figure them out)
- backtrace of the crash (if applicable)
If you are too lazy to use the issue tracker, please at least ping @outfoxxed:outfoxxed.me
in the matrix room with your bug information.
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 = "github:hyprwm/Hyprland";
# or "github:hyprwm/Hyprland?ref=v{version}" for a release version of hyprland
hy3 = {
url = "github:outfoxxed/hy3";
# or "github:outfoxxed/hy3?ref=hl{version}" for a release version of 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
'';
};
There is an unofficial hy3-git package,
usable with the hyprland-git
package.
Install hyprland, including its headers and pkg-config file, then run the following commands:
cmake -DCMAKE_BUILD_TYPE=Debug -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.
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:movefocus
movewindow
->hy3:movewindow
You 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 {
# disable gaps when only one window is onscreen
no_gaps_when_only = <bool> # default: false
# 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
# tab group settings
tabs {
# height of the tab bar
height = <int> # default: 15
# padding between the tab bar and its focused node
padding = <int> # default: 5
# the tab bar should animate in/out from the top instead of below the window
from_top = <bool> # default: false
# rounding of tab bar corners
rounding = <int> # default: 3
# render the window title on the bar
render_text = <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
# active tab bar segment color
col.active = <color> # default: 0xff32b4ff
# urgent tab bar segment color
col.urgent = <color> # default: 0xffff4f4f
# inactive tab bar segment color
col.inactive = <color> # default: 0x80808080
# active tab bar text color
col.text.active = <color> # default: 0xff000000
# urgent tab bar text color
col.text.urgent = <color> # default: 0xff000000
# inactive tab bar text color
col.text.inactive = <color> # default: 0xff000000
}
# 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 height 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
}
}
}
hy3:makegroup, <h | v | opposite | tab>, [ephemeral | force_ephemeral]
- make a vertical / horizontal split or tab groupephemeral
- 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 layoutuntab
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]
- move the focus left, up, down, or rightvisible
- only move between visible nodes, not hidden tabs
hy3:movewindow, <l | u | d | r | left | down | up | right>, [once], [visible]
- move a window left, up, down, or rightonce
- only move directly to the neighboring group, without moving into any of its subgroupsvisible
- only move between visible nodes, not hidden tabs
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 tab
hy3:focustab <mouse | [l | r | left | right | index, <index>], [prioritize_hovered | require_hovered], [wrap]>
mouse
- focus the tab under the mouse, works well with a non consuming bind, e.g.# binds hy3:focustab to lmb and still allows windows to receive clicks bindn = , mouse:272, hy3:focustab, mouse
l | r | left | right
- direction to change focus towardsindex, <index>
- select theindex
th 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 end
hy3:debugnodes
- print the node tree into the hyprland log⚠️ ALPHA QUALITYhy3:setswallow, <true | false | toggle>
- set the containing node's window swallow state⚠️ ALPHA QUALITYhy3:expand, <expand | shrink | base>
- expand the current node to cover other nodesexpand
- expand by one nodeshrink
- shrink by one nodebase
- undo all expansions