Smooth, animated window snapping on macOS using Raycast + Hammerspoon.
Bring macOS-native-feeling window movements to your desktop with clean animations for:
No jarring jumps. Just smooth, polished transitions.
This extension uses Hammerspoon to apply window animations.
For bash and zsh:
brew install --cask hammerspoon && mkdir -p ~/.hammerspoon && curl -o ~/.hammerspoon/init.lua https://raw.githubusercontent.com/raycast/extensions/refs/heads/main/extensions/animated-window-manager/hammerspoon/init.lua && (if [[ $(uname -m) == 'arm64' ]]; then sudo ln -s ~/.hammerspoon/hs /opt/homebrew/bin/hs; else sudo ln -s ~/.hammerspoon/hs /usr/local/bin/hs; fi) && open -a Hammerspoon
For Fish shell:
bash -c 'brew install --cask hammerspoon && mkdir -p ~/.hammerspoon && curl -o ~/.hammerspoon/init.lua https://raw.githubusercontent.com/raycast/extensions/refs/heads/main/extensions/animated-window-manager/hammerspoon/init.lua && if [[ $(uname -m) == "arm64" ]]; then sudo ln -sf ~/.hammerspoon/hs /opt/homebrew/bin/hs; else sudo ln -sf ~/.hammerspoon/hs /usr/local/bin/hs; fi && open -a Hammerspoon'
☝️ This installs Hammerspoon, applies the animated layout config, symlinks hs CLI to the correct location based on architecture (Apple or Intel chip) and opens Hammerspoon.
| Command | Description |
|---|---|
| Move Window Left (Animated) | Slides focused window to the left half |
| Move Window Right (Animated) | Slides focused window to the right half |
| Maximize Window (Animated) | Smoothly fills the whole screen |
| Reasonable Size (Animated) | Centers window with ~60% width & 70% height |
All animations use native-feeling macOS transitions.
Install Hammerspoon
brew install --cask hammerspoon
Enable CLI access
Create a symlink to expose the Hammerspoon CLI (hs) to your system.
For Apple Silicon (M1, M2, M3 Macs):
sudo ln -s ~/.hammerspoon/hs /opt/homebrew/bin/hs
For Intel Macs:
sudo ln -s ~/.hammerspoon/hs /usr/local/bin/hs
Add the layout functions
Paste this into ~/.hammerspoon/init.lua:
require("hs.ipc")
function moveWindowLeftAnimated()
local win = hs.window.focusedWindow()
if not win then return end
local screen = win:screen()
local frame = screen:frame()
local targetFrame = {
x = frame.x,
y = frame.y,
w = frame.w / 2,
h = frame.h
}
win:move(targetFrame, nil, true, 0.3)
end
function moveWindowRightAnimated()
local win = hs.window.focusedWindow()
if not win then return end
local screen = win:screen()
local frame = screen:frame()
local targetFrame = {
x = frame.x + (frame.w / 2),
y = frame.y,
w = frame.w / 2,
h = frame.h
}
win:move(targetFrame, nil, true, 0.3)
end
function maximizeWindowAnimated()
local win = hs.window.focusedWindow()
if not win then return end
local screen = win:screen()
local frame = screen:frame()
win:move(frame, nil, true, 0.3)
end
function moveWindowReasonableSize()
local win = hs.window.focusedWindow()
if not win then return end
local screen = win:screen()
local frame = screen:frame()
local targetWidth = frame.w * 0.6
local targetHeight = frame.h * 0.7
local targetFrame = {
x = frame.x + ((frame.w - targetWidth) / 2),
y = frame.y + ((frame.h - targetHeight) / 2),
w = targetWidth,
h = targetHeight
}
win:move(targetFrame, nil, true, 0.3)
end
Open Hammerspoon and load the config
open -a Hammerspoon
This extension calls your custom Hammerspoon functions like:
hs -c "moveWindowLeftAnimated()"
Hammerspoon then smoothly animates your window into place using native macOS window APIs.
can't access message portYou forgot to enable IPC. Add this to the top of your init.lua:
require("hs.ipc")
Raycast was focused. We fixed that by automatically closing Raycast before calling hs using closeMainWindow().
This project was built to make macOS window management feel less robotic and more native. Animations make a big difference — and Raycast + Hammerspoon is the perfect lightweight combo.
Open an issue or submit a pull request on GitHub. Happy snapping! ⚡️