These instructions cover firmware builds for macOS, Linux, and Windows, plus static hosting of the WebUSB app through GitHub Pages.
Hardware:
Software:
arduino-clibrew install arduino-cli
Use your package manager if it ships a recent arduino-cli, or download the release archive from Arduino and place arduino-cli on PATH.
Use choco and do a choco install arduino-cli. If you don't have that then install the official Arduino CLI zip or MSI, then ensure arduino-cli.exe is on PATH.
Run once on any platform:
arduino-cli config init
arduino-cli core update-index
arduino-cli core install adafruit:nrf52 --additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
From the repository root:
arduino-cli compile -b adafruit:nrf52:feather52840 --build-property "build.extra_flags=-DNRF52840_XXAA {build.flags.usb} -DCFG_TUD_HID=4" OpenPuck
This sketch requires CFG_TUD_HID=4 because Steam mode exposes four HID interfaces.
Find the board port:
arduino-cli board list
Upload:
arduino-cli upload \
-b adafruit:nrf52:feather52840 \
-p /dev/ttyACM0 \
OpenPuck
Replace /dev/ttyACM0 with the actual port. On macOS it is usually /dev/cu.usbmodem*.
Find the COM port:
arduino-cli board list
Upload:
arduino-cli upload `
-b adafruit:nrf52:feather52840 `
-p COM5 `
OpenPuck
Replace COM5 with the actual board port.
Re-flashing firmware does not erase the board's internal LittleFS. The paired-controller bond (bonds.bin) and every saved setting (cfg.bin: USB mode, chord assignments, back-paddle map, mouse sensitivity) survive a fresh build and upload. To bring a board up in a truly clean state — a new unit, a hand-me-down with a stale bond, or a corrupted config — wipe the filesystem with one of:
Build flag (wipe on flash): compile with -DOPK_FACTORY_RESET=1 and upload. This build reformats all persistent storage on boot, so flashing it brings the board up on clean defaults — no console or panel needed:
arduino-cli compile -b adafruit:nrf52:feather52840 --build-property "build.extra_flags=-DNRF52840_XXAA {build.flags.usb} -DCFG_TUD_HID=4 -DOPK_FACTORY_RESET=1" OpenPuck
It wipes on every boot while the flag is compiled in, so this is a one-shot reset tool: flash the reset build once, let it boot (storage erased), then build and flash a normal firmware (without the flag) for regular use.
ERASE when prompted. The board reformats its filesystem and reboots to factory defaults. This works in every USB mode.ERASE-ALL (exact, all caps). Same effect: reformat + reboot.Both reformat the entire internal filesystem (cfg.bin + bonds.bin and anything else), so the action is irreversible and the controller must be re-paired afterwards (see §7).
Note on the serial method: puck (Steam/Lizard) mode drops the CDC console by default to free a USB endpoint for the wake-mouse interface, so the serial port may not be present in that mode. Either arm the one-shot debug CDC first (panel debug-CDC toggle / D console command, which keeps the console for the next boot), or just use the WebUSB Factory erase button, which is available in all modes.
0xB4 = 0x02 when connected.WebUSB requires a secure context. http://localhost qualifies.
cd docs
python3 -m http.server 8008
Open:
http://localhost:8008
cd docs
py -m http.server 8008
Open:
http://localhost:8008