Take an interactive screenshot and float it as a click-through, always-on-top overlay pinned to the bottom-right corner. Useful for referencing something while you work.
- Cmd+4 triggers
screenshot_float.sh— gives you the macOS crosshair to select a region - Select a region — it's displayed as a borderless, transparent, floating window via PyObjC
- Press Escape instead — all existing floating screenshots are dismissed
- The window is fully click-through — it never steals focus or interferes with your work
One key does everything. Invoke multiple times to stack reference screenshots, cancel to clear them all.
- macOS
- Python 3 with PyObjC (
pip install pyobjc) - Karabiner-Elements (for the keyboard shortcuts, or bind however you like)
#!/bin/bash
# Take interactive screenshot and float it as always-on-top window
# Cancel the selection (Esc) to dismiss all existing floats instead
SCALE="${1:-2.0}"
FILE="/tmp/screenshot_peek_$(date +%s).png"
/usr/sbin/screencapture -i "$FILE"
if [ -s "$FILE" ]; then
python3 "$HOME/bin/float_image.py" "$FILE" "$SCALE" &
else
rm -f "$FILE"
pkill -f "float_image.py" 2>/dev/null
sleep 0.5
pkill -9 -f "float_image.py" 2>/dev/null
rm -f /tmp/screenshot_peek_*.png 2>/dev/null
fi#!/usr/bin/env python3
"""Float a screenshot as an always-on-top window that auto-dismisses."""
import sys
import os
import signal
import AppKit
import Quartz
from Foundation import NSObject, NSTimer, NSRunLoop, NSDefaultRunLoopMode
def main():
if len(sys.argv) < 2:
print("Usage: float_image.py <image_path> [scale] [duration]")
sys.exit(1)
image_path = sys.argv[1]
scale = float(sys.argv[2]) if len(sys.argv) > 2 else 2.0
duration = float(sys.argv[3]) if len(sys.argv) > 3 else 0 # 0 = no auto-close
if not os.path.exists(image_path):
print(f"File not found: {image_path}")
sys.exit(1)
app = AppKit.NSApplication.sharedApplication()
app.setActivationPolicy_(AppKit.NSApplicationActivationPolicyAccessory)
image = AppKit.NSImage.alloc().initWithContentsOfFile_(image_path)
if image is None:
print(f"Could not load image: {image_path}")
sys.exit(1)
img_size = image.size()
# Get screen dimensions first
screen = AppKit.NSScreen.mainScreen()
screen_frame = screen.visibleFrame()
scr_w = screen_frame.size.width
scr_h = screen_frame.size.height
# Scale image but cap to bottom-quarter of screen
max_w = scr_w * 0.75
max_h = scr_h * 0.35
win_w = img_size.width * scale
win_h = img_size.height * scale
# Shrink proportionally if too large
if win_w > max_w or win_h > max_h:
ratio = min(max_w / win_w, max_h / win_h)
win_w *= ratio
win_h *= ratio
# Position at bottom-right corner (macOS y=0 is bottom of screen)
x = screen_frame.origin.x + scr_w - win_w - 20
y = screen_frame.origin.y + 20
frame = ((x, y), (win_w, win_h))
window = AppKit.NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
frame,
AppKit.NSWindowStyleMaskBorderless,
AppKit.NSBackingStoreBuffered,
False,
)
window.setLevel_(AppKit.NSFloatingWindowLevel)
window.setOpaque_(False)
window.setBackgroundColor_(AppKit.NSColor.clearColor())
window.setHasShadow_(True)
window.setIgnoresMouseEvents_(True)
image_view = AppKit.NSImageView.alloc().initWithFrame_(((0, 0), (win_w, win_h)))
image_view.setImage_(image)
image_view.setImageScaling_(AppKit.NSImageScaleProportionallyUpOrDown)
window.contentView().addSubview_(image_view)
window.makeKeyAndOrderFront_(None)
# Auto-close after duration (if set)
if duration > 0:
def close_app(timer):
app.terminate_(None)
NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
duration, app, "terminate:", None, False
)
# Handle SIGTERM/SIGINT gracefully (for kill_floats.sh)
_should_quit = [False]
def handle_signal(signum, frame):
_should_quit[0] = True
signal.signal(signal.SIGTERM, handle_signal)
signal.signal(signal.SIGINT, handle_signal)
# app.run() blocks Python's signal handlers, so poll a flag via NSTimer
class SignalChecker(NSObject):
def check_(self, timer):
if _should_quit[0]:
app.terminate_(None)
checker = SignalChecker.alloc().init()
NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
0.5, checker, "check:", None, True
)
app.run()
if __name__ == "__main__":
main()The kill logic is now built into screenshot_float.sh (cancel to dismiss), but you can keep this as a standalone script if you want a dedicated kill binding too.
#!/bin/bash
# Kill all floating screenshot windows
pkill -f "float_image.py" 2>/dev/null
sleep 0.5
# Force kill any that didn't exit gracefully
pkill -9 -f "float_image.py" 2>/dev/null
# Clean up temp screenshot files
rm -f /tmp/screenshot_peek_*.png 2>/dev/nullAdd this to your Karabiner rules array — one key does everything:
{
"from": { "key_code": "4", "modifiers": { "mandatory": ["command"] } },
"to": [{ "shell_command": "/Users/YOU/bin/screenshot_float.sh" }],
"type": "basic"
}- Click-through:
setIgnoresMouseEvents_(True)— the overlay never steals focus - No dock/menubar presence: runs as
NSApplicationActivationPolicyAccessory - Stackable: each invocation spawns a new process with a timestamped temp file
- Graceful shutdown: since
app.run()blocks in the ObjC event loop, a 0.5sNSTimerpolls a Python flag to handle SIGTERM from the kill script - Auto-sizing: scales the image (default 2x) but caps at 75% screen width / 35% screen height