post-cover
My MacOS rice.
Written Fri Dec 26 2025
Edited: Tue Jan 06 2026
By Michael Freno
515 Hits
My MacOS rice.

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 Dock

The 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_connection

Both 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

Comments
No Comments Yet