Presenting from a Mac without constantly turning around
Presenting from a laptop often means craning your neck to check what the audience sees. The following workflow creates a controlled presenter setup: selected apps launch maximized on the projector, the projector view is mirrored back to the MacBook with click-through support, and notes remain isolated on the laptop display.
1. Set the projector as an extended display
System Settings → Displays → select the projector/external display → Use as: Extended display
2. Install and configure Hammerspoon
- Install Hammerspoon
- Grant Accessibility permission when prompted
- Hammerspoon menu bar icon → Open Config
- Paste the script below into
init.luaand save - Hammerspoon menu bar icon → Reload Config
-- Auto-move and maximize QuickTime Player and Preview windows
-- on the first external display.
hs.window.animationDuration = 0
local wf = hs.window.filter.new({
"QuickTime Player",
"Preview",
})
local function externalScreen()
local primary = hs.screen.primaryScreen()
for _, screen in ipairs(hs.screen.allScreens()) do
if screen:id() ~= primary:id() then
return screen
end
end
-- Fallback if no external display is connected.
return primary
end
local function moveAndMaximizeWindow(win)
if not win then return end
local winID = win:id()
if not winID then return end
local function apply()
local currentWin = hs.window.get(winID)
if not currentWin or not currentWin:isStandard() then
return
end
local targetScreen = externalScreen()
if targetScreen and currentWin:screen():id() ~= targetScreen:id() then
currentWin:moveToScreen(targetScreen, false, true, 0)
end
currentWin:maximize()
end
-- First pass after the window is created.
hs.timer.doAfter(0.25, apply)
-- Second pass catches apps that restore/resize shortly after opening.
hs.timer.doAfter(0.75, apply)
end
-- Only handle newly-created windows.
-- This avoids fighting manual resizing during the presentation.
wf:subscribe(hs.window.filter.windowCreated, moveAndMaximizeWindow)
-- Handle existing matching windows when Hammerspoon loads/reloads.
hs.timer.doAfter(0.5, function()
for _, win in ipairs(wf:getWindows()) do
moveAndMaximizeWindow(win)
end
end)
hs.alert.show("Auto-move/maximize QuickTime/Preview loaded")
Add or remove managed apps using their exact names in the Hammerspoon window filter.
3. Install and start Side Mirror
Install Side Mirror, select the projector/external display from drop down menu at top right, then click Start.
4. Presenting
Opening QuickTime Player or Preview-associated files will display them in full screen on the projector. Use Side Mirror on your MacBook to see and control the projected content. Clicking through moves focus and your cursor to the external display; recover via Opt+Shift+Return.
If you have multiple external displays, replace:
local function externalScreen()
local primary = hs.screen.primaryScreen()
for _, screen in ipairs(hs.screen.allScreens()) do
if screen:id() ~= primary:id() then
return screen
end
end
return primary
end
with:
local function externalScreen()
return hs.screen.find("BenQ") or hs.screen.primaryScreen()
end
Replace "BenQ" with a substring matching your projector's display name. You can list connected display names in the Hammerspoon console with:
hs.fnutils.each(hs.screen.allScreens(), function(s) print(s:name()) end)
Related
For AirPlay displays, macOS 15.2+ supports per-window/app screen mirroring: Control Center → Screen Mirroring → select display → "Change or Choose Content" → "Window or App"
Presenter Mode (FOSS, 8.9MB): "Share a single, easily-switchable application window on a projector"
How to mirror a selected area/window in primary display to second display (via OBS)
Privacy Screen Sharing Tool (Free, 24.3MB): "Your audience sees a clean presentation, while you still see your own notifications and private windows"
CleanPresenter ($40, 58.7MB): "Mirror one window"
Screen Guard (listed as free with no IAP, but the demo video briefly displays "Note: some features in this video require payment to unlock" near the end, 8.8MB): "Instantly hide apps you choose"
Zone Share:Screen Sharing Tool (various prices, 18.4MB): "Ultrawide partial screen share"
❧ 2026-04-27