@@ 0,0 1,118 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "keyball-qmk-firmware": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1763193823,
+ "narHash": "sha256-MB3MnvXprF4LsnFB0tTHRi8SWiBaCfrWXjQWX1BQYNA=",
+ "ref": "refs/heads/hk-master",
+ "rev": "19fd205b8411ce787d26c899cc5ad09ee4d77cb6",
+ "revCount": 28836,
+ "submodules": true,
+ "type": "git",
+ "url": "https://github.com/holykeebs/qmk_firmware"
+ },
+ "original": {
+ "submodules": true,
+ "type": "git",
+ "url": "https://github.com/holykeebs/qmk_firmware"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1770562336,
+ "narHash": "sha256-ub1gpAONMFsT/GU2hV6ZWJjur8rJ6kKxdm9IlCT0j84=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "d6c71932130818840fc8fe9509cf50be8c64634f",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "qmk-firmware": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1770841410,
+ "narHash": "sha256-BCLpMbcO3IS8qxRcfLff7HvjnsBKAlBweAVTGLpKDZc=",
+ "ref": "refs/heads/master",
+ "rev": "45ccd2e9351b979f8eb8fa359db732e5374b0d53",
+ "revCount": 29267,
+ "submodules": true,
+ "type": "git",
+ "url": "https://github.com/qmk/qmk_firmware"
+ },
+ "original": {
+ "submodules": true,
+ "type": "git",
+ "url": "https://github.com/qmk/qmk_firmware"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "keyball-qmk-firmware": "keyball-qmk-firmware",
+ "nixpkgs": "nixpkgs",
+ "qmk-firmware": "qmk-firmware",
+ "zsa-qmk-firmware": "zsa-qmk-firmware"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ },
+ "zsa-qmk-firmware": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1769675113,
+ "narHash": "sha256-JQ2A7UHvClZg2PhIbIxWMW8+3qWyPZpcNsCqSqkjY28=",
+ "ref": "refs/heads/firmware25",
+ "rev": "2f7463bddd017600910958528a2632f26bd67a70",
+ "revCount": 28639,
+ "submodules": true,
+ "type": "git",
+ "url": "https://github.com/zsa/qmk_firmware"
+ },
+ "original": {
+ "submodules": true,
+ "type": "git",
+ "url": "https://github.com/zsa/qmk_firmware"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
@@ 0,0 1,255 @@
+{
+ description = "QMK Userspace - Personal keyboard firmware configurations";
+
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+ flake-utils.url = "github:numtide/flake-utils";
+
+ # Upstream QMK firmware (for Ploopyco and other standard keyboards)
+ qmk-firmware = {
+ url = "git+https://github.com/qmk/qmk_firmware?submodules=1";
+ flake = false;
+ };
+
+ # ZSA fork of QMK firmware (for Voyager, Moonlander, Planck EZ, Ergodox EZ)
+ zsa-qmk-firmware = {
+ url = "git+https://github.com/zsa/qmk_firmware?submodules=1";
+ flake = false;
+ };
+
+ # Holykeebs fork of QMK firmware (for Keyball keyboards)
+ keyball-qmk-firmware = {
+ url = "git+https://github.com/holykeebs/qmk_firmware?submodules=1";
+ flake = false;
+ };
+ };
+
+ outputs = { self, nixpkgs, flake-utils, qmk-firmware, zsa-qmk-firmware, keyball-qmk-firmware }:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs {
+ inherit system;
+ config.allowUnfree = true;
+ };
+
+ # Common QMK build dependencies
+ qmkBuildInputs = with pkgs; [
+ # AVR toolchain (for ATmega-based keyboards like Ploopyco)
+ pkgsCross.avr.buildPackages.gcc
+ avrdude
+
+ # ARM toolchain (for ARM-based keyboards like Voyager, Keyball)
+ gcc-arm-embedded
+
+ # Build tools
+ gnumake
+ git
+ which
+ diffutils
+ util-linux
+
+ # Python with QMK dependencies
+ (python3.withPackages (ps: with ps; [
+ pip
+ setuptools
+ wheel
+ pillow
+ qmk
+ hid
+ pyusb
+ hjson
+ jsonschema
+ milc
+ pygments
+ dotty-dict
+ ]))
+
+ # Additional dependencies
+ libusb1
+ dfu-programmer
+ dfu-util
+ teensy-loader-cli
+ qmk
+ ];
+
+ # Helper to link userspace into QMK firmware
+ setupUserspace = qmkSrc: pkgs.runCommand "qmk-with-userspace" {} ''
+ cp -r ${qmkSrc} $out
+ chmod -R +w $out
+
+ # Link keyboards from userspace
+ if [ -d ${self}/keyboards ]; then
+ for kb in ${self}/keyboards/*; do
+ kbname=$(basename $kb)
+ if [ -d "$out/keyboards/$kbname" ]; then
+ # Merge with existing keyboard (copy keymaps)
+ cp -r $kb/* $out/keyboards/$kbname/ 2>/dev/null || true
+ else
+ # New keyboard, copy entirely
+ cp -r $kb $out/keyboards/
+ fi
+ done
+ fi
+
+ # Link users directory
+ if [ -d ${self}/users ]; then
+ cp -r ${self}/users/* $out/users/ 2>/dev/null || true
+ fi
+
+ # Link layouts
+ if [ -d ${self}/layouts ]; then
+ for layout in ${self}/layouts/*; do
+ layoutname=$(basename $layout)
+ mkdir -p $out/layouts/$layoutname
+ cp -r $layout/* $out/layouts/$layoutname/ 2>/dev/null || true
+ done
+ fi
+ '';
+
+ # QMK sources with userspace integrated
+ qmkUpstream = setupUserspace qmk-firmware;
+ qmkZsa = setupUserspace zsa-qmk-firmware;
+ qmkKeyball = setupUserspace keyball-qmk-firmware;
+
+ # Build a QMK firmware
+ buildFirmware = { name, keyboard, keymap, qmkSource }:
+ pkgs.stdenv.mkDerivation {
+ pname = "qmk-${name}";
+ version = "0.1.0";
+
+ src = qmkSource;
+
+ nativeBuildInputs = qmkBuildInputs;
+
+ buildPhase = ''
+ runHook preBuild
+
+ # QMK needs a writable home directory
+ export HOME="$NIX_BUILD_TOP/home"
+ mkdir -p $HOME
+
+ # Build the firmware
+ make ${keyboard}:${keymap}
+
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ mkdir -p $out
+ # Copy all generated firmware files
+ find . -maxdepth 1 \( -name "*.hex" -o -name "*.bin" -o -name "*.uf2" \) \
+ -exec cp {} $out/ \;
+
+ runHook postInstall
+ '';
+
+ # Don't try to strip firmware files
+ dontStrip = true;
+ dontPatchELF = true;
+ dontFixup = true;
+ };
+
+ # Define keyboard builds
+ keyboards = {
+ # ZSA Voyager - uses ZSA QMK fork
+ voyager-pers = buildFirmware {
+ name = "voyager-pers";
+ keyboard = "zsa/voyager";
+ keymap = "pers";
+ qmkSource = qmkZsa;
+ };
+
+ voyager-ball = buildFirmware {
+ name = "voyager-ball";
+ keyboard = "zsa/voyager";
+ keymap = "ball";
+ qmkSource = qmkZsa;
+ };
+
+ voyager-mod = buildFirmware {
+ name = "voyager-mod";
+ keyboard = "zsa/voyager";
+ keymap = "mod";
+ qmkSource = qmkZsa;
+ };
+
+ # Keyball39 - uses holykeebs QMK fork
+ keyball39-init = buildFirmware {
+ name = "keyball39-init";
+ keyboard = "keyball/keyball39";
+ keymap = "init";
+ qmkSource = qmkKeyball;
+ };
+
+ # Ploopyco Trackball - uses upstream QMK
+ ploopyco-trackball-rev1_005-pers = buildFirmware {
+ name = "ploopyco-trackball-rev1_005-pers";
+ keyboard = "ploopyco/trackball/rev1_005";
+ keymap = "pers";
+ qmkSource = qmkUpstream;
+ };
+
+ ploopyco-trackball-rev1_007-pers = buildFirmware {
+ name = "ploopyco-trackball-rev1_007-pers";
+ keyboard = "ploopyco/trackball/rev1_007";
+ keymap = "pers";
+ qmkSource = qmkUpstream;
+ };
+ };
+
+ in {
+ # Individual keyboard packages
+ packages = keyboards // {
+ # Build all keyboards
+ all = pkgs.symlinkJoin {
+ name = "qmk-all-keyboards";
+ paths = builtins.attrValues keyboards;
+ };
+
+ default = self.packages.${system}.all;
+ };
+
+ # Development shell with QMK tooling
+ devShells.default = pkgs.mkShell {
+ buildInputs = qmkBuildInputs ++ (with pkgs; [
+ # Additional dev tools
+ qmk
+ ]);
+
+ shellHook = ''
+ echo "QMK Userspace Development Environment"
+ echo ""
+ echo "Available keyboards:"
+ echo " ZSA (use zsa/qmk_firmware):"
+ echo " - zsa/voyager:pers"
+ echo " - zsa/voyager:ball"
+ echo " - zsa/voyager:mod"
+ echo ""
+ echo " Keyball (use holykeebs/qmk_firmware):"
+ echo " - keyball/keyball39:init"
+ echo ""
+ echo " Ploopyco (use upstream qmk_firmware):"
+ echo " - ploopyco/trackball/rev1_005:pers"
+ echo " - ploopyco/trackball/rev1_007:pers"
+ echo ""
+ echo "Build with: nix build .#<keyboard-name>"
+ echo " e.g.: nix build .#voyager-pers"
+ echo " nix build .#keyball39-init"
+ echo " nix build .#all"
+ echo ""
+ '';
+ };
+
+ # Apps for flashing firmware
+ apps = {
+ flash-voyager = flake-utils.lib.mkApp {
+ drv = pkgs.writeShellScriptBin "flash-voyager" ''
+ ${pkgs.wally-cli}/bin/wally-cli ${self.packages.${system}.voyager-pers}/*.bin
+ '';
+ };
+ };
+ }
+ );
+}