When I started using macOS I hand only ever been a Windows Andy at that point, but I wanted to use a Unix based OS as I was starting to really hate the Windows experience as a developer. I don’t nearly went for a thinkpad with the plans to put Ubuntu on it. By change I found a base M1 MacBook Air on Amazon that was listed as Refurbished in Excellent condition for like 600 bucks[1].
The windows laptop world has improved since and the gap has narrowed but the m1 Mac really blew the door of all its competitors in terms of performance and battery life, and at the price it really was a no brainer.
Anyway, as soon as I started the damn thing I was blown away by the fact that there was no sort of window snapping! I mean common fellas it’s 2022 what tha hell are we doing!?[2]
Problems immediately
While the window snapping was my biggest issue with macOS it was far from my only one. Here’s my full list[3]:
No window snapping
Focus not following mouse - meaning you first need to click into a window to give it focus before you can interact[4]
Settings looks like it was designed for mobile[5]
The dock is just not quite right
The Air line only supports 1 external display
Scrolling is jank with many mice[6]
No per app audio handling at a system level
So I had to get that all sorted and after some googling I found a few different things that would sort out some of my issues to varying degrees of quality. This would ultimately be the first setup that I ran for a while ~6 months or so. This is the most approachable setup for a nontechnical person, but it is also not any good.
The meh. setup
I first found rectangle to solve the biggest and most straightforward issue. The I found smooze to solve the issues I had with scrolling - this was very shortly made redundant with the purchase of the Logitech MX Master 3S[7]. I also found this handy dandy script for decreasing the time for the dock to be revealed from hidden.
defaults write com.apple.dock autohide-delay -float 0.1
# hide timing config
defaults write com.apple.dock autohide-time-modifier -float 0.5
# to take effect, a restart is needed
killall DockThe last in pure software, Soundsource, this app is pricy for sure, but it's also great, solving a seriously lacking problem with macOS very very well. Rouge Amoeba makes a bunch of great software, in addition to Soundsource, I use Audio Hijack regularly, which gives per app audio sourcing/recording and a bunch of handy processing features too.
By pure happenstance I was at a goodwill with my girlfriend in Manhattan and while she found nothing but a belt (she was trying to thrift clothing - truly an effort in futility) I was able to source one of these bad boys for $8. Along with some software this allowed for powering 2 external displays and supplied power over a single wire.
This setup was fine, basically what I would consider a necessary minimum. It would take time for me to discover the various projects that exist.
Now that’s what I call pod ricing
I unfortunately don’t remember when I first discovered yabai, but that and its sister project[8], skhd, were my first experience with anything that could be considered ricing[9]. These completely transformed how I used my laptop. Yabai is a tiling window manager, and like many of them is based on binary space partitioning, meaning that new windows divide the previous windows space in half, now occupying the same amount of space. While it’s great on its own, it really does shine when combined with keyboard shortcuts, which is what skhd provides. At time of writing this is my setup:
For yabai
yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa"
sudo yabai --load-sa &>/dev/null
display_count=$(yabai -m query --displays | jq length)
echo "Number of displays detected: $display_count"
is_blender_running() {
pgrep -x "Blender" >/dev/null
}
is_emulator_running() {
pgrep -x "Simulator" >/dev/null || pgrep "qemu-system-aarch64" >/dev/null
}
is_bambu_running() {
pgrep -x "BambuStudio" >/dev/null
}
# Function to get current space count
get_space_count() {
yabai -m query --spaces | jq length
}
# Function to add or remove spaces as needed
adjust_space_count() {
local needed_spaces=$1
local current_spaces=$(get_space_count)
while [ $current_spaces -lt $needed_spaces ]; do
yabai -m space --create
current_spaces=$((current_spaces + 1))
done
while [ $current_spaces -gt $needed_spaces ]; do
yabai -m space $current_spaces --destroy
current_spaces=$((current_spaces - 1))
done
}
setup_spaces() {
local needed_spaces
if [ "$display_count" -eq 1 ]; then
if is_blender_running || is_bambu_running; then
needed_spaces=5 # main, web, comms, misc, audio
else
needed_spaces=4 # main, web, comms, audio
fi
else
if (is_blender_running || is_bambu_running) && is_emulator_running; then
needed_spaces=6 # audio, misc, main, web, comms, emulators
elif is_blender_running || is_bambu_running || is_bambu_running; then
needed_spaces=5 # audio, misc, main, web, comms
else
needed_spaces=4 # audio, main, web, comms
fi
fi
# Adjust space count first
adjust_space_count $needed_spaces
if [ "$display_count" -eq 1 ]; then
# Single display configuration
yabai -m space 1 --label main
yabai -m space 2 --label web
yabai -m space 3 --label comms
if is_blender_running || is_bambu_running; then
yabai -m space 4 --label misc
yabai -m space 5 --label audio
else
yabai -m space 4 --label audio
fi
else
# Multi-display configuration
# Label spaces
yabai -m space 1 --label audio
if is_blender_running && is_emulator_running; then
yabai -m space 2 --label misc
yabai -m space 3 --label main
yabai -m space 4 --label web
yabai -m space 5 --label comms
yabai -m space 6 --label emulators
elif is_blender_running; then
yabai -m space 2 --label misc
yabai -m space 3 --label main
yabai -m space 4 --label web
yabai -m space 5 --label comms
elif is_emulator_running; then
yabai -m space 2 --label main
yabai -m space 3 --label web
yabai -m space 4 --label comms
yabai -m space 5 --label emulators
else
yabai -m space 2 --label main
yabai -m space 3 --label web
yabai -m space 4 --label comms
fi
# Get display indexes
local display1=$(yabai -m query --displays | jq '.[0].index')
local display2=$(yabai -m query --displays | jq '.[1].index')
# Move spaces to correct displays
yabai -m space 1 --display $display1
yabai -m space 2 --display $display1
yabai -m space 3 --display $display2
yabai -m space 4 --display $display2
if is_blender_running && is_emulator_running; then
yabai -m space 5 --display $display2
yabai -m space 6 --display $display2
elif is_blender_running || is_emulator_running; then
yabai -m space 5 --display $display2
fi
fi
}
setup_rules() {
local main_space="main"
local web_space="web"
local comms_space="comms"
local audio_space="audio"
local misc_space="misc"
local emulators_space="emulators"
if [ "$display_count" -gt 1 ]; then
audio_space="audio"
main_space="main"
web_space="web"
comms_space="comms"
misc_space="misc"
emulators_space="emulators"
fi
# Clear existing rules first
yabai -m rule --remove ".*" 2>/dev/null
yabai -m rule --add app="^(Alacritty|kitty|Ghostty)$" space="$main_space"
yabai -m rule --add app="^Xcode(-beta)?$" space="$main_space"
yabai -m rule --add app="^(Orion|Safari|Brave|SigmaOS|Zen Browser|Zen)$" space="$web_space"
yabai -m rule --add app="^(Mail|Messages|Things|Obsidian)$" space="$comms_space"
yabai -m rule --add app="^(YouTube Music|Podcasts|Spotify|Music|Plex|Jellyfin Media Player|Discord)$" space="$audio_space"
if is_blender_running || is_bambu_running; then
yabai -m rule --add app="^(Blender|Bambu Studio)$" space="$misc_space"
fi
# Handle emulators based on display count
if [ "$display_count" -eq 1 ] || ! is_emulator_running; then
# Single display: emulators go to main space
yabai -m rule --add app="^(Simulator|Android Emulator|qemu-system-aarch64)$" space="$main_space" manage=on
else
# Multiple displays and emulator running: emulators get their own space
yabai -m rule --add app="^(Simulator|Android Emulator|qemu-system-aarch64)$" space="$emulators_space" manage=on
fi
yabai -m rule --add title="^Ubuntu$" space="$main_space" manage=off
yabai -m rule --add title="^(Preview|Preferences|Settings|Control Center|Steam)$" manage=off
yabai -m rule --add app="^(Calculator|System Preferences|System Settings|Activity Monitor|Archive Utility|Finder|Notes|Numi|Weather|DaisyDisk|Raycast|Raycast Settings|Dato|Terminal|Proton VPN|iStat Menus|Transmission|AlDente|Steam|Little Snitch|Radio Silence|TextEdit|love|Bitwarden|App Store)$" manage=off
}
# Function to handle display changes
handle_display_change() {
local new_display_count=$(yabai -m query --displays | jq length)
if [ "$display_count" -ne "$new_display_count" ]; then
display_count=$new_display_count
echo "Display count changed to: $display_count"
setup_spaces
setup_rules
fi
}
# Add signal handlers
yabai -m signal --add event=display_added action="$0"
yabai -m signal --add event=display_removed action="$0"
# Set up spaces
setup_spaces
# Set up window management rules
setup_rules
# General yabai configuration
yabai -m config \
layout bsp \
top_padding 10 \
bottom_padding 10 \
left_padding 10 \
right_padding 10 \
window_gap 16 \
window_shadow float \
mouse_modifier cmd \
mouse_action1 move \
mouse_action2 resize \
external_bar all:40:0 \
# Apply rules
yabai -m rule --apply
if ! pgrep -x "borders" >/dev/null; then
borders &
fi
echo "yabai configuration loaded successfully"And skhd
# https://github.com/koekeishiya/yabai/wiki/Commands#focus-display
# https://github.com/koekeishiya/dotfiles/blob/master/skhd/skhdrc
.blacklist [
"Blender"
"Ubuntu"
"nixOS"
"Parallels Desktop"
]
# -----------------------------
# Space/Focus Management
# -----------------------------
# Move focus to space
lcmd - 1 : yabai -m space --focus 1
lcmd - 2 : yabai -m space --focus 2
lcmd - 3 : yabai -m space --focus 3
lcmd - 4 : yabai -m space --focus 4
lcmd - 5 : yabai -m space --focus 5
lcmd - 6 : yabai -m space --focus 6
lcmd - 7 : yabai -m space --focus 7
lcmd - 8 : yabai -m space --focus 8
lcmd - 9 : yabai -m space --focus 9
# Move focus container to space - don't follow
lalt - 1 : yabai -m window --space 1
lalt - 2 : yabai -m window --space 2
lalt - 3 : yabai -m window --space 3
lalt - 4 : yabai -m window --space 4
lalt - 5 : yabai -m window --space 5
lalt - 6 : yabai -m window --space 6
lalt - 7 : yabai -m window --space 7
lalt - 8 : yabai -m window --space 8
lalt - 9 : yabai -m window --space 9
# Move focus container to space
rcmd - 1 : yabai -m window --space 1 --focus
rcmd - 2 : yabai -m window --space 2 --focus
rcmd - 3 : yabai -m window --space 3 --focus
rcmd - 4 : yabai -m window --space 4 --focus
rcmd - 5 : yabai -m window --space 5 --focus
rcmd - 6 : yabai -m window --space 6 --focus
rcmd - 7 : yabai -m window --space 7 --focus
rcmd - 8 : yabai -m window --space 8 --focus
rcmd - 9 : yabai -m window --space 9 --focus
# ------------------------------
# Window Management
# ------------------------------
# balance window sizes
alt - e : yabai -m space --balance
# Moving windows
lcmd - h : yabai -m window --warp west
lcmd - l : yabai -m window --warp east
lcmd - j : yabai -m window --warp south
lcmd - k : yabai -m window --warp north
#swap windows
lalt - h : yabai -m window --swap west
lalt - j : yabai -m window --swap south
lalt - k : yabai -m window --swap north
lalt - l : yabai -m window --swap east
# Float and center / Unfloat window
alt - space : yabai -m window --toggle float \
yabai -m window --grid 4:4:1:1:2:2
# Make fullscreen
lalt - f : yabai -m window --toggle windowed-fullscreen
ralt - f : yabai -m window --toggle native-fullscreen
# Mouse focus
alt - o : yabai -m config focus_follows_mouse autoraise
alt - p : yabai -m config focus_follows_mouse off
# Rotate layout
lcmd - m : yabai -m space --rotate 90
# ----------------------------
# Space Management
# ----------------------------
# create space, move to it
lalt - n : yabai -m space --create && \
index="$(yabai -m query --spaces --display | jq 'map(select(."is-native-fullscreen" == false))[-1].index')" && \
yabai -m window --space "${index}" && \
yabai -m space --focus "${index}"
# just create space
ralt - n : yabai -m space --create
# destroy spaces
ralt- 1 : yabai -m space --destroy 1
ralt- 2 : yabai -m space --destroy 2
ralt- 3 : yabai -m space --destroy 3
ralt- 4 : yabai -m space --destroy 4
ralt- 5 : yabai -m space --destroy 5
# ----------------------------
# Other
# ----------------------------
# Restart desktop management
cmd + shift - r : yabai --restart-service && \
brew services restart sketchybar && \
brew services restart borders && \
~/.config/btop/btop_colorswap.sh
lalt + shift - o : restart_obsidian_connectionBoth of these (especially the yabai configuration) are highly specific to me and how I like to organize my environment. I'm not sure how useful they'd be to anyone else, but others may find some limited use in it.
Shortly thereafter I also found SketchyBar[10]. SketchyBar is a bar replacement for macOS that allows you to create a create a statusbar that is highly customizable, but is very much targeted at a highly technical audience - you can check out the discussion page for widgets and setups made by others, however. Here is what my setup looks like (in my dark mode):

On the left you have my spaces, pulled from yabai (with a toggle that gives the settings menu for the focused app). Then a VPN widget that shows whether I'm connected to a VPN or not. There is a large gap in the center to accomodate my macs notch (currently running a 14in M3 MacBook Pro). On the far right I have system control menu (log out, lock, restart etc.). Then a toggle for the native control center, date, weather, battery, volume, blah blah. The last two things are cool tho, a cpu/gpu utilization indicator and finally a homebrew outdated package counter. Almost all of these are also interactable as well.
My sketchybar config is without question the most complicated part of my setup, far too complicated to put here, you can see it here on my GitHub if interested.
Like yabai/skhd, the engineer behind it has a number of projects, and JankyBorders while serving absolutely no functional purpose, looks great.
Just recently I made a dynamic wallpaper using this website (and some basic photoshop skillage) to go perfectly with my rice which is all centered around my terminal/neovim theme (which this site also utilizes). That can be found here.
Putting everything together and we’ve got this
Light mode

Dark mode

Here, I'm showing my terminal, I use neovim, tmux and ghostty, I use this across machines, and the setup is pretty extensive, and will write about that separately.
You can find my most up-to-date config here.
📌 References Section
Notes & References
[1] This was legit a great deal at the time. Also when it arrived it only had a single power battery cycle and 100% battery health
[2] This has since been added, some people complained - because they are dumb.
[3] As far as I can remember
[4] Legitimately awful UX decision, a search for focus following mouse yield countless posts of complains and almost as many different solutions.
[5] The settings app was redesigned in Ventura which was shortly after I got my Mac in 2022
[6] I think this is related to resolutions scaling. If unaware, the displays on Macs are of significantly higher resolution that what they show you the user as possible resolution settings, all resolution settings are scaled to some degree.
[7] Best mouse ever - they recently released a v4 that seems gimmicky af, but the 3S is discounted now so at least that can be said in its favor.
[8] Made by the same engineer
[9] Add your reference text here
[10] I specifically use the Lua variant