Turn your Novation Launchpad into a macOS shortcut deck with real-time LED
feedback.
Assign buttons to apps and control them instantly (launch, focus, minimize, or close windows) with LEDs that always
stay in sync with your system.
Inspired by the idea of a Stream Deck, but using MIDI hardware and open-source software.
- Each button can be mapped to a macOS application.
- Actions trigger with minimal latency and always stay in sync with the systemβs actual state.
- LED colors indicate the app's current state in real time.
- Includes customizable boot and shutdown LED animations for clear visual cues.
- Optimized bulk LED state sync loop for sub-200 ms refresh rate and low CPU usage.
For detailed LED behavior and interaction rules, see Technical Specification.
- macOS (tested on Apple Silicon, should work on Intel).
- Node.js 22.x LTS
(recommended to install with nvm) or fnm - pnpm as the package manager.
- A Novation Launchpad connected via USB.
Developed and tested with a Launchpad S model. - Hammerspoon β required for macOS app control (see setup below).
git clone [email protected]:sergio-santiago/launchpad-shortcut-deck.git
cd launchpad-shortcut-deck
# Set correct Node version
nvm use # or fnm use
# Install dependencies
pnpm install
pnpm approve-builds # allow @julusian/midi to build
To let the Launchpad open, close, minimize, and maximize macOS apps, this project uses a lightweight local backend powered by Hammerspoon.
brew install --cask hammerspoon
This repo includes a configuration file at
hammerspoon/launchpad-shortcut-deck/init.lua
.
This file contains the Lua API used by the app to control macOS apps and windows.
You need to copy or symlink it into your Hammerspoon config folder:
mkdir -p ~/.hammerspoon/launchpad-shortcut-deck
# Option A β symlink (preferred, keeps in sync with repo)
ln -sfn "$(pwd)/hammerspoon/launchpad-shortcut-deck/init.lua" ~/.hammerspoon/launchpad-shortcut-deck/init.lua
# Option B β copy (static)
cp ./hammerspoon/launchpad-shortcut-deck/init.lua ~/.hammerspoon/launchpad-shortcut-deck/init.lua
require('launchpad-shortcut-deck')
β οΈ If you already have a custom~/.hammerspoon/init.lua
, the line above must be present somewhere in it so the module loads.
βΉοΈ This repo also includes a file athammerspoon/init.lua
only as an example β it will not run by itself. Use it as a reference if you need to integrate the module into an existing config.
You can automate this step with:
# Ensure ~/.hammerspoon/init.lua contains the require line (add only if missing)
grep -qxF "require('launchpad-shortcut-deck')" ~/.hammerspoon/init.lua 2>/dev/null || echo "require('launchpad-shortcut-deck')" >> ~/.hammerspoon/init.lua
Start the app:
pnpm start
The app will check if Hammerspoon is running and attempt to launch it if not found. On the first run, you may need to grant Accessibility permissions to Hammerspoon when prompted by macOS.
You can quit at any time by pressingESC
orCtrl+C
.
On exit, a shutdown animation will play and all LEDs will be cleared.
You can verify macOS application control via Hammerspoon by running:
pnpm test:hammerspoon
This command will open, focus, minimize, maximize, toggle fullscreen,
close all windows while keeping the app running, re-open a window,
and finally quit each app listed in the APPS
constant inside
tests/hammerspoon-integration.test.js
.
You can edit that array to select which apps to test.
This test now also checks live application state via getState
to verify actions were applied successfully.
β οΈ Warning: Running this test will actively open and close apps on your machine.
-
HS_FUNCS_MISSING: ...
Hammerspoon started but the Lua API wasnβt loaded yet. Ensure:- The symlink/copy is correct:
~/.hammerspoon/launchpad-shortcut-deck/init.lua
~/.hammerspoon/init.lua
contains:
require('launchpad-shortcut-deck')
- Reload Hammerspoon config (menu bar icon β Reload Config).
- The symlink/copy is correct:
-
Actions fail for window operations (minimize/maximize/fullscreen/close):
Grant Hammerspoon Accessibility permission:
System Settings β Privacy & Security β Accessibility.
This project is licensed under the GNU General Public License v3.0 or later β see the LICENSE file for details.