~ruther/qmk_firmware

d997fe1a4a8cc9530b3b9349441681c3fdeb1fe6 — Drashna Jael're 2 years ago 9b89ad1 + 27e6e27
Merge remote-tracking branch 'origin/master' into develop
70 files changed, 3906 insertions(+), 1 deletions(-)

A keyboards/butterkeebs/pocketpad/info.json
A keyboards/butterkeebs/pocketpad/keymaps/default/keymap.c
A keyboards/butterkeebs/pocketpad/readme.md
A keyboards/butterkeebs/pocketpad/rules.mk
A keyboards/citrus/erdnuss65/config.h
A keyboards/citrus/erdnuss65/erdnuss65.c
A keyboards/citrus/erdnuss65/info.json
A keyboards/citrus/erdnuss65/keymaps/default/keymap.c
A keyboards/citrus/erdnuss65/keymaps/via/keymap.c
A keyboards/citrus/erdnuss65/keymaps/via/rules.mk
A keyboards/citrus/erdnuss65/readme.md
A keyboards/citrus/erdnuss65/rules.mk
A keyboards/citrus/readme.md
A keyboards/geistmaschine/macropod/config.h
A keyboards/geistmaschine/macropod/info.json
A keyboards/geistmaschine/macropod/keymaps/default/keymap.c
A keyboards/geistmaschine/macropod/keymaps/default/rules.mk
A keyboards/geistmaschine/macropod/keymaps/via/keymap.c
A keyboards/geistmaschine/macropod/keymaps/via/rules.mk
A keyboards/geistmaschine/macropod/macropod.c
A keyboards/geistmaschine/macropod/matrix.c
A keyboards/geistmaschine/macropod/readme.md
A keyboards/geistmaschine/macropod/rules.mk
A keyboards/hotdox76v2/keymaps/dancxjo/config.h
A keyboards/hotdox76v2/keymaps/dancxjo/keymap.c
A keyboards/hotdox76v2/keymaps/dancxjo/rules.mk
M keyboards/mechlovin/mechlovin9/rev1/info.json
M keyboards/mechlovin/mechlovin9/rev2/info.json
A keyboards/mechlovin/mechlovin9/rev3/info.json
A keyboards/mechlovin/mechlovin9/rev3/readme.md
A keyboards/mechlovin/mechlovin9/rev3/rules.mk
M keyboards/mechlovin/mechlovin9/rules.mk
A keyboards/nullbitsco/snap/config.h
A keyboards/nullbitsco/snap/info.json
A keyboards/nullbitsco/snap/keymaps/bongo_reactive/bongo.h
A keyboards/nullbitsco/snap/keymaps/bongo_reactive/bongo_graphics.h
A keyboards/nullbitsco/snap/keymaps/bongo_reactive/config.h
A keyboards/nullbitsco/snap/keymaps/bongo_reactive/keymap.c
A keyboards/nullbitsco/snap/keymaps/bongo_reactive/rules.mk
A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/bongo.h
A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/bongo_graphics.h
A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/config.h
A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/keymap.c
A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/rules.mk
A keyboards/nullbitsco/snap/keymaps/default/keymap.c
A keyboards/nullbitsco/snap/keymaps/iso/keymap.c
A keyboards/nullbitsco/snap/keymaps/oled/config.h
A keyboards/nullbitsco/snap/keymaps/oled/keymap.c
A keyboards/nullbitsco/snap/keymaps/oled/oled_graphics.h
A keyboards/nullbitsco/snap/keymaps/oled/rules.mk
A keyboards/nullbitsco/snap/keymaps/typehud/config.h
A keyboards/nullbitsco/snap/keymaps/typehud/keymap.c
A keyboards/nullbitsco/snap/keymaps/typehud/readme.md
A keyboards/nullbitsco/snap/keymaps/typehud/rules.mk
A keyboards/nullbitsco/snap/keymaps/typehud/typehud.c
A keyboards/nullbitsco/snap/keymaps/typehud/typehud.h
A keyboards/nullbitsco/snap/keymaps/via/config.h
A keyboards/nullbitsco/snap/keymaps/via/keymap.c
A keyboards/nullbitsco/snap/keymaps/via/rules.mk
A keyboards/nullbitsco/snap/matrix.c
A keyboards/nullbitsco/snap/readme.md
A keyboards/nullbitsco/snap/rules.mk
A keyboards/nullbitsco/snap/snap.c
A keyboards/nullbitsco/snap/snap.h
A keyboards/rkg68/info.json
A keyboards/rkg68/keymaps/default/keymap.c
A keyboards/rkg68/keymaps/via/keymap.c
A keyboards/rkg68/keymaps/via/rules.mk
A keyboards/rkg68/readme.md
A keyboards/rkg68/rules.mk
A keyboards/butterkeebs/pocketpad/info.json => keyboards/butterkeebs/pocketpad/info.json +56 -0
@@ 0,0 1,56 @@
{
	"manufacturer": "ButterKeebs",
    "keyboard_name": "PocketPad",
    "maintainer": "qmk",
    "diode_direction": "ROW2COL",
	
	"usb": {
		"device_version": "1.0.0",
        "pid": "0x1475",
        "vid": "0xFEED"
    },
	
    "features": {
        "bootmagic": true,
        "command": false,
        "console": false,
        "extrakey": true,
        "mousekey": true,
        "nkro": true
    },
    "matrix_pins": {
        "cols": ["F1", "C7", "D5", "B7"],
        "rows": ["F7", "F6", "F5", "F4", "B1"]
    },

    "processor": "atmega32u4",
	"bootloader": "atmel-dfu",
    "layouts": {
		"LAYOUT": {
			"layout": [
				{"x": 0, "y": 0, "matrix": [0,0]},
				{"x": 1, "y": 0, "matrix": [0,1]},
				{"x": 2, "y": 0, "matrix": [0,2]},
				{"x": 3, "y": 0, "matrix": [0,3]},
					
				{"x": 0, "y": 1, "matrix": [1,0]},
				{"x": 1, "y": 1, "matrix": [1,1]},
				{"x": 2, "y": 1, "matrix": [1,2]},
				{"x": 3, "y": 1, "matrix": [1,3]},
					
				{"x": 0, "y": 2, "matrix": [2,0]},
				{"x": 1, "y": 2, "matrix": [2,1]},
				{"x": 2, "y": 2, "matrix": [2,2]},
				{"x": 3, "y": 2, "matrix": [2,3]},
					
				{"x": 0, "y": 3, "matrix": [3,0]},
				{"x": 1, "y": 3, "matrix": [3,1]},
				{"x": 2, "y": 3, "matrix": [3,2]},
				{"x": 3, "y": 3, "matrix": [3,3]},
					
				{"x": 0, "y": 4, "matrix": [4,0]},
				{"x": 1, "y": 4, "matrix": [4,1]}	
			]
		}
	}
}
\ No newline at end of file

A keyboards/butterkeebs/pocketpad/keymaps/default/keymap.c => keyboards/butterkeebs/pocketpad/keymaps/default/keymap.c +14 -0
@@ 0,0 1,14 @@
// ButterKeebs <butterkeebs@github>
// SPDX-License-Identifier: GPL-2.0+

#include QMK_KEYBOARD_H

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

	LAYOUT(
		KC_NUM_LOCK, KC_KP_SLASH, KC_KP_ASTERISK, KC_KP_MINUS, 
		KC_KP_7, KC_KP_8, KC_KP_9, KC_KP_PLUS, 
		KC_KP_4, KC_KP_5, KC_KP_6, KC_KP_ENTER, 
		KC_KP_1, KC_KP_2, KC_KP_3, KC_KP_DOT, 
		KC_F, KC_KP_0)
};
\ No newline at end of file

A keyboards/butterkeebs/pocketpad/readme.md => keyboards/butterkeebs/pocketpad/readme.md +27 -0
@@ 0,0 1,27 @@
# PocketPad

![PocketPad](https://tinyurl.com/2hffvnvb)

*The PocketPad is a tiny 18 key macropad/numpad using 6mm tactile switches.*

* Keyboard Maintainer: [ButterKeebs](https://github.com/butterkeebs)
* Hardware Supported: *Supports current V1.0.0 PocketPad PCB and Elite C / pin compatible MCU boards.*
* Hardware Availability: *Currently not for sale*

Make example for this keyboard (after setting up your build environment):

    make butterkeebs/pocketpad:default

Flashing example for this keyboard:

    make butterkeebs/pocketpad:default:flash

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

## Bootloader

Enter the bootloader in 3 ways:

* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
* **Physical reset button**: Briefly press the button on the back of the PCB. (Not available on Revision 1.0.0 PCB)
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available

A keyboards/butterkeebs/pocketpad/rules.mk => keyboards/butterkeebs/pocketpad/rules.mk +1 -0
@@ 0,0 1,1 @@
# This file intentionally blank
\ No newline at end of file

A keyboards/citrus/erdnuss65/config.h => keyboards/citrus/erdnuss65/config.h +23 -0
@@ 0,0 1,23 @@
/* Copyright 2023 Citrus Lab
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#pragma once

// The pin connected to the data pin of the LEDs
#define RGBLIGHT_LAYERS//允许您定义可打开或关闭的照明层。非常适合显示当前键盘层或大写锁定状态。
#define RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF//如果已定义,则即使 RGB 光源处于关闭状态,也会显示照明图层。

#define LOCKING_SUPPORT_ENABLE
#define LOCKING_RESYNC_ENABLE//尝试使开关状态与键盘指示灯状态保持一致
\ No newline at end of file

A keyboards/citrus/erdnuss65/erdnuss65.c => keyboards/citrus/erdnuss65/erdnuss65.c +28 -0
@@ 0,0 1,28 @@
/* Copyright 2023 Citrus Lab
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "quantum.h"

//Indicator light function
bool led_update_kb(led_t led_state) {
    if (led_update_user(led_state)) {
        if (led_state.caps_lock) {
            rgblight_setrgb_at(255, 255, 255, 0); //white
        } else {
            rgblight_setrgb_at(0, 0, 0, 0);
        }
    }
    return true;
}
\ No newline at end of file

A keyboards/citrus/erdnuss65/info.json => keyboards/citrus/erdnuss65/info.json +109 -0
@@ 0,0 1,109 @@
{
    "keyboard_name": "Erdnuss65",
    "manufacturer": "Citrus Lab",
    "processor": "STM32F103",
    "bootloader": "stm32duino",
    "maintainer": "ctt",
    "usb": {
        "vid": "0x636C",
        "pid": "0x6374",
        "device_version": "0.0.1"
    },

    "matrix_pins": {
        "rows": 
        ["B10","B1", "B0","A7","A6"],  
        "cols": 
        ["B12","B14","B15","A8","B13","B3","B4","B5","A1","A2","A0","A3","A4","A5","B11"]
    },

    "diode_direction": "COL2ROW",

    "features": {
        "bootmagic": true,
        "mousekey": true,
        "extrakey": true,
        "console": false,
        "command": false,
        "nkro": true,
        "backlight": false,
        "rgblight": true,
        "audio": false
    },
    "rgblight": {
        "pin": "A15",
        "led_count": 1
    },
    "layouts": {
        "LAYOUT": {
            "layout": [
                {"label": "ESC K00 (B10,B12)", "matrix": [0, 0], "x": 0, "y": 0},
                {"label": "1 K01 (B10,B14)", "matrix": [0, 1], "x": 1, "y": 0},
                {"label": "2 K02 (B10,B15)", "matrix": [0, 2], "x": 2, "y": 0},
                {"label": "3 K03 (B10,A8)", "matrix": [0, 3], "x": 3, "y": 0},
                {"label": "4 K04 (B10,B13)", "matrix": [0, 4], "x": 4, "y": 0},
                {"label": "5 K05 (B10,B3)", "matrix": [0, 5], "x": 5, "y": 0},
                {"label": "6 K06 (B10,B4)", "matrix": [0, 6], "x": 6, "y": 0},
                {"label": "7 K07 (B10,B5)", "matrix": [0, 7], "x": 7, "y": 0},
                {"label": "8 K08 (B10,A1)", "matrix": [0, 8], "x": 8, "y": 0},
                {"label": "9 K09 (B10,A2)", "matrix": [0, 9], "x": 9, "y": 0},
                {"label": "0 K0A (B10,A0)", "matrix": [0, 10], "x": 10, "y": 0},
                {"label": "- K0B (B10,A3)", "matrix": [0, 11], "x": 11, "y": 0},
                {"label": "= K0C (B10,A4)", "matrix": [0, 12], "x": 12, "y": 0},
                {"label": "BACKSPACE K0D (B10,A5)", "matrix": [0, 13], "x": 13, "y": 0, "w": 2},
                {"label": "INS (B10,B11)", "matrix": [0, 14], "x": 15, "y": 0},
                {"label": "TAB (B1,B12)", "matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
                {"label": "Q (B1,B14)", "matrix": [1, 1], "x": 1.5, "y": 1},
                {"label": "W (B1,B15)", "matrix": [1, 2], "x": 2.5, "y": 1},
                {"label": "E (B1,A8)", "matrix": [1, 3], "x": 3.5, "y": 1},
                {"label": "R (B1,B13)", "matrix": [1, 4], "x": 4.5, "y": 1},
                {"label": "T (B1,B3)", "matrix": [1, 5], "x": 5.5, "y": 1},
                {"label": "Y (B1,B4)", "matrix": [1, 6], "x": 6.5, "y": 1},
                {"label": "U (B1,B5)", "matrix": [1, 7], "x": 7.5, "y": 1},
                {"label": "I (B1,A1)", "matrix": [1, 8], "x": 8.5, "y": 1},
                {"label": "O (B1,A2)", "matrix": [1, 9], "x": 9.5, "y": 1},
                {"label": "P (B1,A0)", "matrix": [1, 10], "x": 10.5, "y": 1},
                {"label": "[ (B1,A3)", "matrix": [1, 11], "x": 11.5, "y": 1},
                {"label": "] (B1,A4)", "matrix": [1, 12], "x": 12.5, "y": 1},
                {"label": "\" (B1,A5)", "matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
                {"label": "DEL (B1,B11)", "matrix": [1, 14], "x": 15, "y": 1},
                {"label": "CAPSLOCK (B0,B12)", "matrix": [2, 0], "x": 0, "y": 2, "w": 1.25},
                {"label": "A (B0,B14)", "matrix": [2, 1], "x": 1.75, "y": 2},
                {"label": "S (B0,B15)", "matrix": [2, 2], "x": 2.75, "y": 2},
                {"label": "D (B0,A8)", "matrix": [2, 3], "x": 3.75, "y": 2},
                {"label": "F (B0,B13)", "matrix": [2, 4], "x": 4.75, "y": 2},
                {"label": "G (B0,B3)", "matrix": [2, 5], "x": 5.75, "y": 2},
                {"label": "H (B0,B4)", "matrix": [2, 6], "x": 6.75, "y": 2},
                {"label": "J (B0,B5)", "matrix": [2, 7], "x": 7.75, "y": 2},
                {"label": "K (B0,A1)", "matrix": [2, 8], "x": 8.75, "y": 2},
                {"label": "L (B0,A2)", "matrix": [2, 9], "x": 9.75, "y": 2},
                {"label": "; (B0,A0)", "matrix": [2, 10], "x": 10.75, "y": 2},
                {"label": "' (B0,A3)", "matrix": [2, 11], "x": 11.75, "y": 2},
                {"label": "ENTER (B0,A5)", "matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
                {"label": "PGUP (B0,B11)", "matrix": [2, 14], "x": 15, "y": 2},
                {"label": "LSHIFT (A7,B12)", "matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
                {"label": "Z (A7,B14)", "matrix": [3, 1], "x": 2.25, "y": 3},
                {"label": "X (A7,B15)", "matrix": [3, 2], "x": 3.25, "y": 3},
                {"label": "C (A7,A8)", "matrix": [3, 3], "x": 4.25, "y": 3},
                {"label": "V (A7,B13)", "matrix": [3, 4], "x": 5.25, "y": 3},
                {"label": "B (A7,B3)", "matrix": [3, 5], "x": 6.25, "y": 3},
                {"label": "N (A7,B4)", "matrix": [3, 6], "x": 7.25, "y": 3},
                {"label": "M (A7,B5)", "matrix": [3, 7], "x": 8.25, "y": 3},
                {"label": ", (A7,A1)", "matrix": [3, 8], "x": 9.25, "y": 3},
                {"label": ". (A7,A2)", "matrix": [3, 9], "x": 10.25, "y": 3},
                {"label": "/ (A7,A0)", "matrix": [3, 10], "x": 11.25, "y": 3},
                {"label": "RSHIFT (A7,A4)", "matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
                {"label": "UP (A7,A5)", "matrix": [3, 13], "x": 14, "y": 3},
                {"label": "PGDN (A7,B11)", "matrix": [3, 14], "x": 15, "y": 3},
                {"label": "LCTRL (A6,B12)", "matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
                {"label": "WIN (A6,B14)", "matrix": [4, 1], "x": 1.5, "y": 4},
                {"label": "ALT (A6,B15)", "matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
                {"label": "SPACE (A6,A8)", "matrix": [4, 3], "x": 4, "y": 4, "w": 7},
                {"label": "FN (A6,A0)", "matrix": [4, 10], "x": 11, "y": 4, "w": 1.5},
                {"label": "LEFT (A6,A4)", "matrix": [4, 12], "x": 13, "y": 4},
                {"label": "DOWN (A6,A5)", "matrix": [4, 13], "x": 14, "y": 4},
                {"label": "RIGHT (A6,B11)", "matrix": [4, 14], "x": 15, "y": 4}
           ]
        }
    }
}

A keyboards/citrus/erdnuss65/keymaps/default/keymap.c => keyboards/citrus/erdnuss65/keymaps/default/keymap.c +23 -0
@@ 0,0 1,23 @@
// Copyright 2023 Citrus Lab
// SPDX-License-Identifier: GPL-2.0
#include QMK_KEYBOARD_H

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

    [0] = LAYOUT(
        KC_ESC,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_MINS, KC_EQL,  KC_BSPC, KC_INS,  
        KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL,  
        KC_CAPS, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT, KC_ENT,  KC_PGUP, 
        KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_LSFT, KC_UP,   KC_PGDN,  
        KC_LCTL, KC_LGUI, KC_LALT, KC_SPC,  MO(1),   KC_LEFT, KC_DOWN, KC_RGHT
    ),

    [1] = LAYOUT(
        KC_GRV,  KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  _______, KC_MPRV,
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PSCR, _______, _______, RESET,   KC_MNXT,
        _______, _______, _______, _______, _______, _______, _______, KC_CALC, _______, _______, _______, _______, _______, KC_HOME,
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MYCM, KC_VOLU, KC_END,
        _______, _______, _______, _______, _______, KC_MUTE, KC_VOLU, KC_MPLY
    )
};


A keyboards/citrus/erdnuss65/keymaps/via/keymap.c => keyboards/citrus/erdnuss65/keymaps/via/keymap.c +39 -0
@@ 0,0 1,39 @@
// Copyright 2023 Citrus Lab
// SPDX-License-Identifier: GPL-2.0
#include QMK_KEYBOARD_H

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

    [0] = LAYOUT(
        KC_ESC,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_MINS, KC_EQL,  KC_BSPC, KC_INS,  
        KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL,  
        KC_CAPS, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT, KC_ENT,  KC_PGUP, 
        KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_LSFT, KC_UP,   KC_PGDN,  
        KC_LCTL, KC_LGUI, KC_LALT, KC_SPC,  MO(1),   KC_LEFT, KC_DOWN, KC_RGHT
    ),

    [1] = LAYOUT(
        KC_GRV,  KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  _______, KC_MPRV,
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PSCR, _______, _______, RESET,   KC_MNXT,
        _______, _______, _______, _______, _______, _______, _______, KC_CALC, _______, _______, _______, _______, _______, KC_HOME,
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MYCM, KC_VOLU, KC_END,
        _______, _______, _______, _______, _______, KC_MUTE, KC_VOLU, KC_MPLY
    ),

    [2] = LAYOUT(
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, 
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, 
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, 
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,  
        _______, _______, _______, _______, _______, _______, _______, _______  
    ),

    [3] = LAYOUT(
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, 
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, 
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, 
        _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,  
        _______, _______, _______, _______, _______, _______, _______, _______  
    ),

};

A keyboards/citrus/erdnuss65/keymaps/via/rules.mk => keyboards/citrus/erdnuss65/keymaps/via/rules.mk +1 -0
@@ 0,0 1,1 @@
VIA_ENABLE = yes
\ No newline at end of file

A keyboards/citrus/erdnuss65/readme.md => keyboards/citrus/erdnuss65/readme.md +22 -0
@@ 0,0 1,22 @@
# Erdnuss65

* Keyboard Maintainer: [Citrus Lab](https://github.com/ctt-t) 
* Hardware Supported: STM32F103C8T6

Make example for this keyboard (after setting up your build environment):

    make citrus/erdnuss65:default

Flashing example for this keyboard:

    make citrus/erdnuss65:default:flash

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

## Bootloader

Enter the bootloader in 3 ways:

* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
\ No newline at end of file

A keyboards/citrus/erdnuss65/rules.mk => keyboards/citrus/erdnuss65/rules.mk +2 -0
@@ 0,0 1,2 @@
# Enter lower-power sleep mode when on the ChibiOS idle thread
OPT_DEFS += -DCORTEX_ENABLE_WFI_IDLE=TRUE
\ No newline at end of file

A keyboards/citrus/readme.md => keyboards/citrus/readme.md +2 -0
@@ 0,0 1,2 @@
# Citrus Lab
QMK folders for PCB commissions.
\ No newline at end of file

A keyboards/geistmaschine/macropod/config.h => keyboards/geistmaschine/macropod/config.h +21 -0
@@ 0,0 1,21 @@
/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

/* key matrix size, only 1x4 are used in current state.
   IO expander setup would allow up to 1x16 + 1 from the MCU */
#define MATRIX_ROWS 1
#define MATRIX_COLS 17

A keyboards/geistmaschine/macropod/info.json => keyboards/geistmaschine/macropod/info.json +41 -0
@@ 0,0 1,41 @@
{
    "manufacturer": "Geistmaschine",
    "keyboard_name": "Macropod",
    "maintainer": "ebastler",
    "bootloader": "atmel-dfu",
    "processor": "atmega32u4",
    "url": "https://geistmaschine.io/",
    "usb": {
        "device_version": "1.0.0",
        "pid": "0x0004",
        "vid": "0x676D"
    },
    "features": {
        "bootmagic":    true,
        "command":      false,
        "console":      false,
        "extrakey":     true,
        "mousekey":     false,
        "nkro":         false,
        "encoder":      true
    },
    "encoder": {
        "rotary": [
            { 
                "pin_a": "D3", 
                "pin_b": "D5",
                "resolution": 2
            }
        ]
    },
    "layouts": {
        "LAYOUT_fourkey": {
            "layout": [
              {"x":0,  "y":0,    "matrix":[0,0] },
              {"x":0,  "y":1.25, "matrix":[0,1] },
              {"x":0,  "y":2.25, "matrix":[0,2] },
              {"x":0,  "y":3.25, "matrix":[0,3] }
            ]
        }
    }
}
\ No newline at end of file

A keyboards/geistmaschine/macropod/keymaps/default/keymap.c => keyboards/geistmaschine/macropod/keymaps/default/keymap.c +35 -0
@@ 0,0 1,35 @@
/* Copyright 2023 Moritz Plattner
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include QMK_KEYBOARD_H

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [0] = LAYOUT_fourkey (
        LT(1, KC_MUTE),     KC_MPRV, KC_MPLY, KC_MNXT
    ),

    [1] = LAYOUT_fourkey (
        KC_TRNS,            KC_TRNS, KC_TRNS, KC_TRNS
    ),

};

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
    [0] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)  },
    [1] = { ENCODER_CCW_CW(KC_MRWD, KC_MFFD)  },
};
#endif
\ No newline at end of file

A keyboards/geistmaschine/macropod/keymaps/default/rules.mk => keyboards/geistmaschine/macropod/keymaps/default/rules.mk +1 -0
@@ 0,0 1,1 @@
ENCODER_MAP_ENABLE = yes

A keyboards/geistmaschine/macropod/keymaps/via/keymap.c => keyboards/geistmaschine/macropod/keymaps/via/keymap.c +35 -0
@@ 0,0 1,35 @@
/* Copyright 2023 Moritz Plattner
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include QMK_KEYBOARD_H

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [0] = LAYOUT_fourkey (
        LT(1, KC_MUTE),     KC_MPRV, KC_MPLY, KC_MNXT
    ),

    [1] = LAYOUT_fourkey (
        KC_TRNS,            KC_TRNS, KC_TRNS, KC_TRNS
    ),

};

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
    [0] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)  },
    [1] = { ENCODER_CCW_CW(KC_MRWD, KC_MFFD)  },
};
#endif
\ No newline at end of file

A keyboards/geistmaschine/macropod/keymaps/via/rules.mk => keyboards/geistmaschine/macropod/keymaps/via/rules.mk +2 -0
@@ 0,0 1,2 @@
ENCODER_MAP_ENABLE = yes
VIA_ENABLE = yes
\ No newline at end of file

A keyboards/geistmaschine/macropod/macropod.c => keyboards/geistmaschine/macropod/macropod.c +21 -0
@@ 0,0 1,21 @@
// Copyright 2022 QMK
// SPDX-License-Identifier: GPL-2.0-or-later

#include "quantum.h"

// This will be overridden by encoder map in all default keymaps, but serves as a catch-all for user keymaps that may omit the map.
#if defined (ENCODER_ENABLE) && !defined (ENCODER_MAP_ENABLE)
bool encoder_update_kb(uint8_t index, bool clockwise) {
    if (!encoder_update_user(index, clockwise)) {
      return false; /* Don't process further events if user function exists and returns false */
    }
    if (index == 0) { /* First encoder */
        if (clockwise) {
            tap_code_delay(KC_VOLU, 10);
        } else {
            tap_code_delay(KC_VOLD, 10);
        }
    }
    return true;
}
#endif
\ No newline at end of file

A keyboards/geistmaschine/macropod/matrix.c => keyboards/geistmaschine/macropod/matrix.c +87 -0
@@ 0,0 1,87 @@
/* Copyright 2023 ebastler and elpekenin
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "pca9555.h"
#include "quantum.h"

// PCA9555 i2c address, 0x20: A0 = 0, A1 = 0, A2 = 0
#define IC1 0x20

// Define how long to wait to reach the IO expander after connection loss again
// Since this board is modular, it should not spam unnecessary i2c requests if used without a module
#define RETRY_TIMESPAN 2000

typedef enum {
    PLUGGED,
    DOUBTFUL,
    UNPLUGGED
} expander_status_t;

void pca9555_setup(void) {
    // Initialize the expander, no need to set ports to inputs as that is the default behavior
    pca9555_init(IC1);
}

void matrix_init_custom(void) {
    // Encoder pushbutton on the MCU is connected to PD2
    setPinInputHigh(D2);
    pca9555_setup();
}

bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    static expander_status_t status      = DOUBTFUL;
    static uint32_t          retry_timer = 0;

    // initialize one byte filled with 1
    uint8_t pin_states = 0xFF;
    
    
    if (status != UNPLUGGED || timer_elapsed32(retry_timer) > RETRY_TIMESPAN) {
        // If the chip was unplugged before, it needs to be re-initialized
        if(status==UNPLUGGED) {
            pca9555_setup();
        }
        // Read the entire port into this byte, 1 = not pressed, 0 = pressed
        bool ret = pca9555_readPins(IC1, PCA9555_PORT0, &pin_states);

        // Update state
        if (ret) {
            status = PLUGGED;
        } else {
            switch (status) {
                case PLUGGED:
                    status = DOUBTFUL;
                    break;

                case DOUBTFUL:
                    status = UNPLUGGED;
                    break;

                // If we've diagnosed as unplugged, update timer to not read I2C
                case UNPLUGGED:
                    retry_timer = timer_read32();
            }
        }
    }

    // Shift pin states by 1 to make room for the switch connected to the MCU, then OR them together and invert (as QMK uses inverted logic compared to the electrical levels)
    matrix_row_t data = ~(pin_states << 1 | readPin(D2));

    bool changed = current_matrix[0] != data;
    current_matrix[0] = data;

    return changed;
}
\ No newline at end of file

A keyboards/geistmaschine/macropod/readme.md => keyboards/geistmaschine/macropod/readme.md +25 -0
@@ 0,0 1,25 @@
# Geistmaschine Macropod

![macropod](https://i.imgur.com/lAsCslA.png)

Macropod is a modular macropad, designed around a central big encoder with a magnetic connector for modularity. The default module uses three MX style keys.
* Keyboard Maintainer: [ebastler](https://github.com/ebastler)
* Hardware Supported: Macropod rev1
* Hardware Availability: [geistmaschine.io](https://geistmaschine.io/)

Make example for this keyboard (after setting up your build environment):

    qmk compile -kb geistmaschine/macropod -km default

Flashing example for this keyboard:

    qmk flash -kb geistmaschine/macropod -km default

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

## Bootloader

Enter the bootloader in 2 ways:

* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (the knob on the main module) and plug in the keyboard
* **Physical reset button**: Briefly tap the button marked "RST" on the back of the main module PCB

A keyboards/geistmaschine/macropod/rules.mk => keyboards/geistmaschine/macropod/rules.mk +5 -0
@@ 0,0 1,5 @@
CUSTOM_MATRIX = lite

VPATH += drivers/gpio
SRC += pca9555.c matrix.c
QUANTUM_LIB_SRC += i2c_master.c
\ No newline at end of file

A keyboards/hotdox76v2/keymaps/dancxjo/config.h => keyboards/hotdox76v2/keymaps/dancxjo/config.h +6 -0
@@ 0,0 1,6 @@
// Copyright 2023 Travis Reed (@dancxjo)
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once
#define DYNAMIC_KEYMAP_LAYER_COUNT 5
#define EE_HANDS

A keyboards/hotdox76v2/keymaps/dancxjo/keymap.c => keyboards/hotdox76v2/keymaps/dancxjo/keymap.c +177 -0
@@ 0,0 1,177 @@
// Copyright 2023 Travis Reed (@dancxjo)
// SPDX-License-Identifier: GPL-2.0-or-later

#include QMK_KEYBOARD_H

enum layer {
    _ENGRAM = 0,
    _QWERTY,
    _ENGRAM_SHIFT,
    _FUNCTION,
    _MEDIA
};

/* Combines the compose key (right super) and the AltGr */
#define KC_COMP MT(MOD_RALT, KC_RGUI)
#define KC_SCMP MT(MOD_RSFT | MOD_RALT, KC_RGUI)

#define KC_STAB MT(MOD_LSFT, KC_TAB)

/* Use a fake shift layer since Engram switches level 2 assignments */
#define KC_PSFT MO(_ENGRAM_SHIFT)

#define KC_FUNC TT(_FUNCTION)
#define KC_MEDI TT(_MEDIA)

/* Easily switch between MacOS & other OSes*/
#define KC_HLM1 LM(1, MOD_LCTL)
#define KC_HLM2 LM(1, MOD_LGUI)
#define KC_SHM1 LM(1, MOD_LCTL | MOD_LSFT)
#define KC_SHM2 LM(1, MOD_LGUI | MOD_LSFT)
#define KC_STRN RSFT(KC_TRNS)

#define KC_FORW LGUI(KC_TAB)
#define KC_BACK LGUI(LSFT(KC_TAB))

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
        /* Differs slightly from official Engram in that {} are the level 1 and [] are the level 2 */
        [_ENGRAM] = LAYOUT_ergodox_pretty(
            KC_LCBR, KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    CG_NORM, KC_PAUSE, KC_6,    KC_7,    KC_8,    KC_9,   KC_0,    KC_RCBR,
            KC_TAB,  KC_B,    KC_Y,    KC_O,    KC_U,    KC_QUOT, KC_AT,   KC_HASH,  KC_DQUO, KC_L,    KC_D,    KC_W,   KC_V,    KC_Z,
            KC_CAPS, KC_C,    KC_I,    KC_E,    KC_A,    KC_COMM,                    KC_DOT,  KC_H,    KC_T,    KC_S,   KC_N,    KC_Q,
            KC_PSFT, KC_G,    KC_X,    KC_J,    KC_K,    KC_MINS, KC_SLSH, KC_PSCR,  KC_QUES, KC_R,    KC_M,    KC_F,   KC_P,    KC_PSFT,
            KC_HLM1, KC_FUNC, KC_MEDI, KC_LALT, KC_HLM2,                             KC_RGUI, KC_RALT, KC_MEDI, KC_FUNC,KC_HLM1,
                                       KC_INS,  KC_HOME,                             KC_END,  KC_DEL,
                                                KC_PGUP,                             KC_PGDN,
                                       KC_ENT,  KC_ESC,  KC_LSFT,                    KC_RSFT, KC_BSPC, KC_SPC
        ),
        [_ENGRAM_SHIFT] = LAYOUT_ergodox_pretty(
            KC_LBRC, KC_PIPE,    KC_EQL,     KC_TILD,    KC_PLUS,    KC_LT,   CG_SWAP, KC_STRN, KC_GT,   KC_CIRC,    KC_AMPR,    KC_PERC,    KC_ASTR,    KC_RBRC,
            KC_STRN, RSFT(KC_B), RSFT(KC_Y), RSFT(KC_O), RSFT(KC_U), KC_LPRN, KC_GRV,  KC_DLR,  KC_RPRN, RSFT(KC_L), RSFT(KC_D), RSFT(KC_W), RSFT(KC_V), RSFT(KC_Z),
            KC_STRN, RSFT(KC_C), RSFT(KC_I), RSFT(KC_E), RSFT(KC_A), KC_SCLN,                   KC_COLN, RSFT(KC_H), RSFT(KC_T), RSFT(KC_S), RSFT(KC_N), RSFT(KC_Q),
            KC_TRNS, RSFT(KC_G), RSFT(KC_X), RSFT(KC_J), RSFT(KC_K), KC_UNDS, KC_BSLS, KC_STRN, KC_EXLM, RSFT(KC_R), RSFT(KC_M), RSFT(KC_F), RSFT(KC_P), KC_TRNS,
            KC_SHM1, KC_STRN,    KC_STRN,    KC_STRN,    KC_SHM2,                               KC_STRN, KC_STRN,    KC_STRN,    KC_STRN,    KC_SHM1,
                                             KC_STRN,    KC_STRN,                               KC_HYPR, KC_STRN,
                                                         KC_STRN,                               KC_STRN,
                                             KC_SHM1,    KC_STRN,    KC_STRN,                   KC_SHM2, KC_STRN, KC_STRN
        ),
        [_QWERTY] = LAYOUT_ergodox_pretty(
            KC_GRV,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_TRNS, KC_TRNS, KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_MINS,
            KC_TRNS, KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_LBRC, KC_RBRC, KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_BSLS,
            KC_TRNS, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,                      KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT,
            KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_EQL, KC_TRNS,  KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_RSFT,
            KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,                            KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
                                       KC_TRNS, KC_TRNS,                            KC_TRNS, KC_TRNS,
                                                KC_TRNS,                            KC_TRNS,
                                       KC_TRNS, KC_TRNS, KC_TRNS,                   KC_TRNS, KC_TRNS, KC_TRNS
        ),
        [_FUNCTION] = LAYOUT_ergodox_pretty(
            KC_PSCR, KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_BRID, KC_BRIU, KC_F6,   KC_F7,   KC_F8,   KC_F9,    KC_F10, KC_PWR,
            KC_APP,  KC_F11,  KC_F12,  KC_F13,  KC_F14,  KC_F15,  TG(1),   TG(1),   KC_F16,  KC_F17,  KC_F18,  KC_F19,   KC_F20, KC_SLEP,
            KC_SCRL, KC_F21,  KC_F22,  KC_F23,  KC_F24,  KC_NO,                     KC_NO,   KC_NO,   KC_NO,   KC_NO,    KC_NO,  KC_WAKE,
            KC_PAUS, KC_UNDO, KC_CUT,  KC_COPY, KC_PSTE, KC_NO,   CG_SWAP, CG_NORM, KC_NO,   KC_NO,   KC_NO,   KC_NO,    KC_NO,  QK_BOOT,
            KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,   KC_TRNS,                                   KC_TRNS,   KC_TRNS,   KC_TRNS, KC_TRNS,   KC_TRNS,
                                       RGB_SAD, RGB_HUD,                                     RGB_HUI, RGB_SAI,
                                                RGB_RMOD,                                     RGB_MOD,
                                       RGB_SPD, RGB_VAD, KC_TRNS,                  KC_TRNS, RGB_VAI, RGB_SPI
        ),
        [_MEDIA] = LAYOUT_ergodox_pretty(
            KC_NO,   KC_NO, KC_NO,   KC_NO,   KC_NO,   KC_WREF, KC_NO, KC_NO, KC_NO,   KC_NO,   KC_NO,   KC_NO, KC_NO,   KC_NO,
            KC_NO,   KC_NO, KC_NO,   KC_NO,   KC_WREF, KC_NO,   KC_NO, KC_NO, KC_NO,   KC_PGUP, KC_UP,   KC_PGDN, KC_MSEL, KC_NO,
            KC_NO,   KC_NO, KC_WSTP, KC_MYCM, KC_WSCH, KC_FIND,               KC_WHOM, KC_LEFT, KC_DOWN, KC_RIGHT, KC_NO,   KC_NO,
            KC_LSFT, KC_NO, KC_NO,   KC_CALC, KC_NO,   KC_WFAV, KC_NO, KC_NO, KC_NO,   KC_HOME, KC_MAIL, KC_END, KC_NO,   KC_NO,
            KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,   KC_TRNS,                                   KC_TRNS,   KC_TRNS,   KC_TRNS, KC_TRNS,   KC_TRNS,
                                   KC_MUTE, KC_EJCT,                                 KC_MSTP, KC_MPLY,
                                            KC_MPRV,                                 KC_MNXT,
                                   KC_MRWD, KC_VOLD, KC_TRNS,                        KC_TRNS, KC_VOLU, KC_MFFD
        )
};

char* get_layer_name(uint8_t layer, bool capitalized) {
    char *layer_name = "Unknown ";

    switch (layer) {
        case _ENGRAM:
        case _ENGRAM_SHIFT:
            if (capitalized) {
                layer_name = "ENGRAM  ";
            } else {
                layer_name = "engram  ";
            }
            break;
        case _QWERTY:
            if (capitalized) {
                layer_name = "QWERTY  ";
            } else {
                layer_name = "qwerty  ";
            }
            break;
        case _MEDIA:
            layer_name = "Media+  ";
            break;
        case _FUNCTION:
            layer_name = "Function";
            break;
    }
    return layer_name;
}

void render_locks(led_t led_state) {
    oled_write_P(led_state.num_lock ? PSTR("NUM ") : PSTR("    "), false);
    oled_write_P(led_state.caps_lock ? PSTR("CAP ") : PSTR("    "), false);
    oled_write_P(led_state.scroll_lock ? PSTR("SCR ") : PSTR("    "), false);
}

void render_mods(uint8_t modifiers, uint8_t layer) {
    oled_write_P(modifiers & MOD_MASK_GUI ? PSTR("Super") : PSTR("     "), false);
    oled_write_P(PSTR(" "), false);
    oled_write_P(modifiers & MOD_MASK_ALT ? PSTR("Alt") : PSTR("   "), false);
    oled_write_P(PSTR(" "), false);
    oled_write_P(modifiers & MOD_MASK_CTRL ? PSTR("Ctl") : PSTR("   "), false);
    oled_write_P(PSTR(" "), false);

    if (layer == _ENGRAM_SHIFT) {
        oled_write_P(PSTR("Pseudo"), false);
    } else {
        oled_write_P(modifiers & MOD_MASK_SHIFT ? PSTR("Shift ") : PSTR("      "), false);
    }
}

char* get_helm_key(void) {
    if (keymap_config.swap_lctl_lgui) {
        return "Super";
    } else {
        return "Control";
    }
}

bool oled_task_user(void) {
    uint8_t layer = get_highest_layer(layer_state);
    uint8_t modifiers = get_mods()|get_oneshot_mods();
    led_t led_state = host_keyboard_led_state();

    bool real_shifted = modifiers & MOD_MASK_SHIFT;
    bool pseudo_shifted = layer == _ENGRAM_SHIFT;
    bool shifted = real_shifted || pseudo_shifted;
    bool caps = led_state.caps_lock;
    bool capitalized = (caps && !shifted) || (!caps && shifted);

    oled_write_P(PSTR("Layer: "), false);
    oled_write(get_layer_name(layer, capitalized), false);
    oled_write_P(PSTR("\n"), false);

    // Only the master knows if we've swapped the gui and ctl key
    if (is_keyboard_master()) {
        oled_write_P(PSTR(" Helm: "), false);
        oled_write(get_helm_key(), false);
    }

    oled_write_P(PSTR("\n"), false);

    render_mods(modifiers, layer);
    oled_write_P(PSTR("\n"), false);

    render_locks(led_state);

    return false;
}

A keyboards/hotdox76v2/keymaps/dancxjo/rules.mk => keyboards/hotdox76v2/keymaps/dancxjo/rules.mk +4 -0
@@ 0,0 1,4 @@
COMMAND_ENABLE = yes
VIA_ENABLE = yes
EXTRAKEY_ENABLE = no
MOUSEKEY_ENABLE = no

M keyboards/mechlovin/mechlovin9/rev1/info.json => keyboards/mechlovin/mechlovin9/rev1/info.json +3 -0
@@ 9,6 9,9 @@
        "rows": ["A4", "A5", "A3", "A2", "A1"]
    },
    "diode_direction": "COL2ROW",
    "features": {
        "backlight": true
    },
    "backlight": {
        "pin": "B8",
        "breathing": true

M keyboards/mechlovin/mechlovin9/rev2/info.json => keyboards/mechlovin/mechlovin9/rev2/info.json +3 -0
@@ 9,6 9,9 @@
        "rows": ["A0", "A1", "A2", "A3", "A4"]
    },
    "diode_direction": "COL2ROW",
    "features": {
        "backlight": true
    },
    "backlight": {
        "pin": "D4",
        "breathing": true

A keyboards/mechlovin/mechlovin9/rev3/info.json => keyboards/mechlovin/mechlovin9/rev3/info.json +22 -0
@@ 0,0 1,22 @@
{
    "keyboard_name": "Mechlovin9 Rev3",
    "processor": "STM32F103",
    "bootloader": "stm32duino",
    "usb": {
        "pid": "0x6509",
        "device_version": "0.0.3"
    },
    "features": {
        "backlight": false
    },
    "bootmagic": {
        "matrix": [0, 13]
    },
    "matrix_pins": {
        "rows": ["B12", "B13", "B14", "B15", "A1"],
        "cols": ["B11", "B10", "B2", "B1", "B0", "A6", "A5", "A4", "A3", "C13", "B7", "B6", "B5", "B4", "B3"]
    },
    "indicators": {
        "caps_lock": "B9"
    }
}

A keyboards/mechlovin/mechlovin9/rev3/readme.md => keyboards/mechlovin/mechlovin9/rev3/readme.md +23 -0
@@ 0,0 1,23 @@
# mechlovin9

![mechlovin9](https://i.imgur.com/T5Lm6OYlh.png)

A 65% PCB, compatible with Kyuu.

* Keyboard Maintainer: [Team Mechlovin](https://github.com/mechlovin)
* Hardware Supported: Kyuu Keyboard.
* Hardware Availability: [Reddit GB](https://www.reddit.com/r/mechmarket/comments/i61par/gb_mechlovin_9_a_kyuu_65_keyboard_compatible_pcb/)

Make example for this keyboard (after setting up your build environment):

    make mechlovin/mechlovin9/rev3:default

Flashing example for this keyboard:

    make mechlovin/mechlovin9/rev3:default:flash

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

## Bootloader

**Reset Key:** To put the mechlovin9 PCB into bootloader, hold ESC and plug cable.
\ No newline at end of file

A keyboards/mechlovin/mechlovin9/rev3/rules.mk => keyboards/mechlovin/mechlovin9/rev3/rules.mk +0 -0
M keyboards/mechlovin/mechlovin9/rules.mk => keyboards/mechlovin/mechlovin9/rules.mk +0 -1
@@ 7,7 7,6 @@ EXTRAKEY_ENABLE = yes       # Audio control and System control
CONSOLE_ENABLE = no         # Console for debug
COMMAND_ENABLE = no         # Commands for debug and configuration
NKRO_ENABLE = no            # Enable N-Key Rollover
BACKLIGHT_ENABLE = yes      # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no        # Enable keyboard RGB underglow
AUDIO_ENABLE = no           # Audio output


A keyboards/nullbitsco/snap/config.h => keyboards/nullbitsco/snap/config.h +87 -0
@@ 0,0 1,87 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
// clang-format off
#pragma once

/* Used to set host for remote KB if VUSB detect doesn't work. */
// #define KEYBOARD_HOST // Force host mode
// #define KEYBOARD_REMOTE // Force remote mode

// Workarounds for sleep/wake issues
#define USB_SUSPEND_WAKEUP_DELAY 250

// NOTE: There is a bug in AVR deep sleep, which
// causes the MCU to stop responding in some cases.
// Disabling the watchdog prevents the MCU from entering 
// power down, while still turning off LEDs, audio, etc.
// See qmk_firmware/issues/20087 for background
#undef WDT_vect

/* split config */
// #define SPLIT_USB_DETECT // Enable if you have issues with USB
#define SOFT_SERIAL_PIN E6
#define SPLIT_HAND_PIN B6
#define DISABLE_SYNC_TIMER
#define SPLIT_HAND_PIN_LOW_IS_LEFT

/* key matrix size */
#define MATRIX_ROWS 12
#define MATRIX_COLS 9
#define MATRIX_MUX_COLS 3

/*
 * Keyboard Matrix Assignments
 * The snap uses a demultiplexer for the cols.
 * to free up more IOs for awesomeness!
 * See matrix.c for more details.
*/
// Left side
#define MATRIX_ROW_PINS { D4, C6, D7, F4, B4, B5 }
#define MATRIX_COL_MUX_PINS { F7, F6, F5 }

//Right side
#define MATRIX_ROW_PINS_RIGHT { F4, F5, F6, F7, B1, B3 }
#define MATRIX_COL_MUX_PINS_RIGHT { D7, C6, D4 }
#define MATRIX_EXT_PIN_RIGHT B6

/* Optional SMT LED pins */
#define RGB_DI_PIN B2
#define RGBLED_NUM 10
#define RGBLED_SPLIT { 5, 5 }
#define RGBLIGHT_LED_MAP { 8, 9, 0, 1, 2, 6, 7, 3, 4, 5 }  
#define RGBLIGHT_SLEEP
#define RGBLIGHT_EFFECT_BREATHING
#define RGBLIGHT_EFFECT_RAINBOW_MOOD
#define RGBLIGHT_EFFECT_RAINBOW_SWIRL
#define RGBLIGHT_EFFECT_SNAKE
#define RGBLIGHT_EFFECT_KNIGHT
#define RGBLIGHT_EFFECT_CHRISTMAS
#define RGBLIGHT_EFFECT_STATIC_GRADIENT
#define RGBLIGHT_EFFECT_RGB_TEST
#define RGBLIGHT_EFFECT_ALTERNATING
#define RGBLIGHT_EFFECT_TWINKLE

/* Optional encoder pins */
#define ENCODERS_PAD_A { B3 }
#define ENCODERS_PAD_B { B1 }
#define ENCODERS_PAD_A_RIGHT { B4 }
#define ENCODERS_PAD_B_RIGHT { B5 }

/* Optional speaker pin */
#define AUDIO_PIN B6

/* Optional split transactions */
#define SPLIT_OLED_ENABLE

A keyboards/nullbitsco/snap/info.json => keyboards/nullbitsco/snap/info.json +24 -0
@@ 0,0 1,24 @@
{
    "keyboard_name": "SNAP",
    "manufacturer": "nullbits",
    "url": "https://nullbits.co/snap/",
    "usb": {
        "vid": "0x6E61",
        "pid": "0x6063",
        "device_version": "0.0.1"
    },
    "debounce": 10,
    "processor": "atmega32u4",
    "bootloader": "atmel-dfu",
    "layouts": {
        "LAYOUT_all": {
            "layout": [{"label":"Esc", "x":1, "y":0}, {"label":"F1", "x":2, "y":0}, {"label":"F2", "x":3, "y":0}, {"label":"F3", "x":4, "y":0}, {"label":"F4", "x":5, "y":0}, {"label":"F5", "x":6, "y":0}, {"label":"F6", "x":7, "y":0}, {"label":"F7", "x":8, "y":0}, {"label":"F8", "x":9, "y":0}, {"label":"F9", "x":10, "y":0}, {"label":"F10", "x":11, "y":0}, {"label":"F11", "x":12, "y":0}, {"label":"F12", "x":13, "y":0}, {"label":"PrtSc", "x":14, "y":0}, {"label":"Pause", "x":15, "y":0}, {"label":"M", "x":0, "y":1}, {"label":"~", "x":1, "y":1}, {"label":"!", "x":2, "y":1}, {"label":"@", "x":3, "y":1}, {"label":"#", "x":4, "y":1}, {"label":"$", "x":5, "y":1}, {"label":"%", "x":6, "y":1}, {"label":"^", "x":7, "y":1}, {"label":"&", "x":8, "y":1}, {"label":"*", "x":9, "y":1}, {"label":"(", "x":10, "y":1}, {"label":")", "x":11, "y":1}, {"label":"_", "x":12, "y":1}, {"label":"+", "x":13, "y":1}, {"label":"Bksp1", "x":14, "y":1}, {"label":"Bksp2", "x":15, "y":1}, {"label":"Home", "x":16, "y":1}, {"label":"M", "x":0, "y":2}, {"label":"Tab", "x":1, "y":2, "w":1.5}, {"label":"Q", "x":2.5, "y":2}, {"label":"W", "x":3.5, "y":2}, {"label":"E", "x":4.5, "y":2}, {"label":"R", "x":5.5, "y":2}, {"label":"T", "x":6.5, "y":2}, {"label":"Y", "x":7.5, "y":2}, {"label":"U", "x":8.5, "y":2}, {"label":"I", "x":9.5, "y":2}, {"label":"O", "x":10.5, "y":2}, {"label":"P", "x":11.5, "y":2}, {"label":"{", "x":12.5, "y":2}, {"label":"}", "x":13.5, "y":2}, {"label":"|", "x":14.5, "y":2, "w":1.5}, {"label":"End", "x":16, "y":2}, {"label":"M", "x":0, "y":3}, {"label":"Caps Lock", "x":1, "y":3, "w":1.75}, {"label":"A", "x":2.75, "y":3}, {"label":"S", "x":3.75, "y":3}, {"label":"D", "x":4.75, "y":3}, {"label":"F", "x":5.75, "y":3}, {"label":"G", "x":6.75, "y":3}, {"label":"H", "x":7.75, "y":3}, {"label":"J", "x":8.75, "y":3}, {"label":"K", "x":9.75, "y":3}, {"label":"L", "x":10.75, "y":3}, {"label":":", "x":11.75, "y":3}, {"label":"\"", "x":12.75, "y":3}, {"label":"Enter", "x":13.75, "y":3, "w":2.25}, {"label":"Page Up", "x":16, "y":3}, {"label":"M", "x":0, "y":4}, {"label":"Shift", "x":1, "y":4, "w":1.25}, {"label":"#", "x":2.25, "y":4}, {"label":"Z", "x":3.25, "y":4}, {"label":"X", "x":4.25, "y":4}, {"label":"C", "x":5.25, "y":4}, {"label":"V", "x":6.25, "y":4}, {"label":"B", "x":7.25, "y":4}, {"label":"N", "x":8.25, "y":4}, {"label":"M", "x":9.25, "y":4}, {"label":"<", "x":10.25, "y":4}, {"label":">", "x":11.25, "y":4}, {"label":"?", "x":12.25, "y":4}, {"label":"Shift", "x":13.25, "y":4, "w":1.75}, {"label":"\u2191", "x":15, "y":4}, {"label":"Page Down", "x":16, "y":4}, {"label":"M", "x":0, "y":5}, {"label":"Ctrl", "x":1, "y":5, "w":1.25}, {"label":"Win", "x":2.25, "y":5, "w":1.25}, {"label":"Alt", "x":3.5, "y":5, "w":1.25}, {"label":"Fn", "x":4.75, "y":5, "w":1.25}, {"label":"Space", "x":6, "y":5, "w":2.25}, {"label":"Space", "x":8.25, "y":5, "w":2.75}, {"label":"Alt", "x":11, "y":5}, {"label":"Fn", "x":12, "y":5}, {"label":"Ctrl", "x":13, "y":5}, {"label":"\u2190", "x":14, "y":5}, {"label":"\u2193", "x":15, "y":5}, {"label":"\u2192", "x":16, "y":5}]
        },
        "LAYOUT_ansi": {
            "layout": [{"label":"Esc", "x":1, "y":0}, {"label":"F1", "x":2, "y":0}, {"label":"F2", "x":3, "y":0}, {"label":"F3", "x":4, "y":0}, {"label":"F4", "x":5, "y":0}, {"label":"F5", "x":6, "y":0}, {"label":"F6", "x":7, "y":0}, {"label":"F7", "x":8, "y":0}, {"label":"F8", "x":9, "y":0}, {"label":"F9", "x":10, "y":0}, {"label":"F10", "x":11, "y":0}, {"label":"F11", "x":12, "y":0}, {"label":"F12", "x":13, "y":0}, {"label":"PrtSc", "x":14, "y":0}, {"label":"Pause", "x":15, "y":0}, {"label":"M", "x":0, "y":1}, {"label":"~", "x":1, "y":1}, {"label":"!", "x":2, "y":1}, {"label":"@", "x":3, "y":1}, {"label":"#", "x":4, "y":1}, {"label":"$", "x":5, "y":1}, {"label":"%", "x":6, "y":1}, {"label":"^", "x":7, "y":1}, {"label":"&", "x":8, "y":1}, {"label":"*", "x":9, "y":1}, {"label":"(", "x":10, "y":1}, {"label":")", "x":11, "y":1}, {"label":"_", "x":12, "y":1}, {"label":"+", "x":13, "y":1}, {"label":"Bksp", "x":14, "y":1, "w":2}, {"label":"Home", "x":16, "y":1}, {"label":"M", "x":0, "y":2}, {"label":"Tab", "x":1, "y":2, "w":1.5}, {"label":"Q", "x":2.5, "y":2}, {"label":"W", "x":3.5, "y":2}, {"label":"E", "x":4.5, "y":2}, {"label":"R", "x":5.5, "y":2}, {"label":"T", "x":6.5, "y":2}, {"label":"Y", "x":7.5, "y":2}, {"label":"U", "x":8.5, "y":2}, {"label":"I", "x":9.5, "y":2}, {"label":"O", "x":10.5, "y":2}, {"label":"P", "x":11.5, "y":2}, {"label":"{", "x":12.5, "y":2}, {"label":"}", "x":13.5, "y":2}, {"label":"|", "x":14.5, "y":2, "w":1.5}, {"label":"End", "x":16, "y":2}, {"label":"M", "x":0, "y":3}, {"label":"Caps Lock", "x":1, "y":3, "w":1.75}, {"label":"A", "x":2.75, "y":3}, {"label":"S", "x":3.75, "y":3}, {"label":"D", "x":4.75, "y":3}, {"label":"F", "x":5.75, "y":3}, {"label":"G", "x":6.75, "y":3}, {"label":"H", "x":7.75, "y":3}, {"label":"J", "x":8.75, "y":3}, {"label":"K", "x":9.75, "y":3}, {"label":"L", "x":10.75, "y":3}, {"label":":", "x":11.75, "y":3}, {"label":"\"", "x":12.75, "y":3}, {"label":"Enter", "x":13.75, "y":3, "w":2.25}, {"label":"Page Up", "x":16, "y":3}, {"label":"M", "x":0, "y":4}, {"label":"Shift", "x":1, "y":4, "w":2.25}, {"label":"Z", "x":3.25, "y":4}, {"label":"X", "x":4.25, "y":4}, {"label":"C", "x":5.25, "y":4}, {"label":"V", "x":6.25, "y":4}, {"label":"B", "x":7.25, "y":4}, {"label":"N", "x":8.25, "y":4}, {"label":"M", "x":9.25, "y":4}, {"label":"<", "x":10.25, "y":4}, {"label":">", "x":11.25, "y":4}, {"label":"?", "x":12.25, "y":4}, {"label":"Shift", "x":13.25, "y":4, "w":1.75}, {"label":"\u2191", "x":15, "y":4}, {"label":"Page Down", "x":16, "y":4}, {"label":"M", "x":0, "y":5}, {"label":"Ctrl", "x":1, "y":5, "w":1.25}, {"label":"Win", "x":2.25, "y":5, "w":1.25}, {"label":"Alt", "x":3.5, "y":5, "w":1.25}, {"label":"Fn", "x":4.75, "y":5, "w":1.25}, {"label":"Space", "x":6, "y":5, "w":2.25}, {"label":"Space", "x":8.25, "y":5, "w":2.75}, {"label":"Alt", "x":11, "y":5}, {"label":"Fn", "x":12, "y":5}, {"label":"Ctrl", "x":13, "y":5}, {"label":"\u2190", "x":14, "y":5}, {"label":"\u2193", "x":15, "y":5}, {"label":"\u2192", "x":16, "y":5}]
        },
        "LAYOUT_iso": {
            "layout": [{"label":"Esc", "x":1, "y":0}, {"label":"F1", "x":2, "y":0}, {"label":"F2", "x":3, "y":0}, {"label":"F3", "x":4, "y":0}, {"label":"F4", "x":5, "y":0}, {"label":"F5", "x":6, "y":0}, {"label":"F6", "x":7, "y":0}, {"label":"F7", "x":8, "y":0}, {"label":"F8", "x":9, "y":0}, {"label":"F9", "x":10, "y":0}, {"label":"F10", "x":11, "y":0}, {"label":"F11", "x":12, "y":0}, {"label":"F12", "x":13, "y":0}, {"label":"PrtSc", "x":14, "y":0}, {"label":"Pause", "x":15, "y":0}, {"label":"M", "x":0, "y":1}, {"label":"~", "x":1, "y":1}, {"label":"!", "x":2, "y":1}, {"label":"@", "x":3, "y":1}, {"label":"#", "x":4, "y":1}, {"label":"$", "x":5, "y":1}, {"label":"%", "x":6, "y":1}, {"label":"^", "x":7, "y":1}, {"label":"&", "x":8, "y":1}, {"label":"*", "x":9, "y":1}, {"label":"(", "x":10, "y":1}, {"label":")", "x":11, "y":1}, {"label":"_", "x":12, "y":1}, {"label":"+", "x":13, "y":1}, {"label":"Bksp", "x":14, "y":1, "w":2}, {"label":"Home", "x":16, "y":1}, {"label":"M", "x":0, "y":2}, {"label":"Tab", "x":1, "y":2, "w":1.5}, {"label":"Q", "x":2.5, "y":2}, {"label":"W", "x":3.5, "y":2}, {"label":"E", "x":4.5, "y":2}, {"label":"R", "x":5.5, "y":2}, {"label":"T", "x":6.5, "y":2}, {"label":"Y", "x":7.5, "y":2}, {"label":"U", "x":8.5, "y":2}, {"label":"I", "x":9.5, "y":2}, {"label":"O", "x":10.5, "y":2}, {"label":"P", "x":11.5, "y":2}, {"label":"{", "x":12.5, "y":2}, {"label":"}", "x":13.5, "y":2}, {"label":"Enter", "x":14.75, "y":2, "w":1.25, "h":2}, {"label":"End", "x":16, "y":2}, {"label":"M", "x":0, "y":3}, {"label":"Caps Lock", "x":1, "y":3, "w":1.75}, {"label":"A", "x":2.75, "y":3}, {"label":"S", "x":3.75, "y":3}, {"label":"D", "x":4.75, "y":3}, {"label":"F", "x":5.75, "y":3}, {"label":"G", "x":6.75, "y":3}, {"label":"H", "x":7.75, "y":3}, {"label":"J", "x":8.75, "y":3}, {"label":"K", "x":9.75, "y":3}, {"label":"L", "x":10.75, "y":3}, {"label":":", "x":11.75, "y":3}, {"label":"\"", "x":12.75, "y":3}, {"label":"\"", "x":13.75, "y":3}, {"label":"Page Up", "x":16, "y":3}, {"label":"M", "x":0, "y":4}, {"label":"Shift", "x":1, "y":4, "w":1.25}, {"label":"#", "x":2.25, "y":4}, {"label":"Z", "x":3.25, "y":4}, {"label":"X", "x":4.25, "y":4}, {"label":"C", "x":5.25, "y":4}, {"label":"V", "x":6.25, "y":4}, {"label":"B", "x":7.25, "y":4}, {"label":"N", "x":8.25, "y":4}, {"label":"M", "x":9.25, "y":4}, {"label":"<", "x":10.25, "y":4}, {"label":">", "x":11.25, "y":4}, {"label":"?", "x":12.25, "y":4}, {"label":"Shift", "x":13.25, "y":4, "w":1.75}, {"label":"\u2191", "x":15, "y":4}, {"label":"Page Down", "x":16, "y":4}, {"label":"M", "x":0, "y":5}, {"label":"Ctrl", "x":1, "y":5, "w":1.25}, {"label":"Win", "x":2.25, "y":5, "w":1.25}, {"label":"Alt", "x":3.5, "y":5, "w":1.25}, {"label":"Fn", "x":4.75, "y":5, "w":1.25}, {"label":"Space", "x":6, "y":5, "w":2.25}, {"label":"Space", "x":8.25, "y":5, "w":2.75}, {"label":"Alt", "x":11, "y":5}, {"label":"Fn", "x":12, "y":5}, {"label":"Ctrl", "x":13, "y":5}, {"label":"\u2190", "x":14, "y":5}, {"label":"\u2193", "x":15, "y":5}, {"label":"\u2192", "x":16, "y":5}]
        }
    }
}

A keyboards/nullbitsco/snap/keymaps/bongo_reactive/bongo.h => keyboards/nullbitsco/snap/keymaps/bongo_reactive/bongo.h +121 -0
@@ 0,0 1,121 @@
/* Copyright 2021 Chris Tanaka <https://github.com/christanaka>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bongo_graphics.h"
#include QMK_KEYBOARD_H

#define _IDLE_FRAMES         5
#define _PREP_FRAMES         1
#define _TAP_FRAMES          2
#define _ANIM_BYTES          512   // Number of bytes in array (max is 1024)
#define _IDLE_FRAME_DURATION 175
#define _TAP_FRAME_DURATION  75
#define _PREP_TIMEOUT        750

enum anim_states
{
    Idle,
    Prep,
    Tap
};

static uint8_t anim_state = Idle;
static uint8_t anim_duration = _IDLE_FRAME_DURATION;
static uint32_t anim_timer = 0;

static uint8_t idle_frame = 0;
static uint8_t tap_frame = 0;

static uint32_t prep_timer = 0;

// Decompress and write a precompressed bitmap frame to the OLED.
// Documentation and python compression script available at:
// https://github.com/nullbitsco/squeez-o
#ifdef USE_OLED_BITMAP_COMPRESSION
static void oled_write_compressed_P(const char* input_block_map, const char* input_block_list) {
    uint16_t block_index = 0;
    for (uint16_t i = 0; i < NUM_OLED_BYTES; i++) {
        uint8_t bit          = i % 8;
        uint8_t map_index    = i / 8;
        uint8_t _block_map   = (uint8_t)pgm_read_byte_near(input_block_map + map_index);
        uint8_t nonzero_byte = (_block_map & (1 << bit));
        if (nonzero_byte) {
            const char data = (const char)pgm_read_byte_near(input_block_list + block_index++);
            oled_write_raw_byte(data, i);
        } else {
            const char data = (const char)0x00;
            oled_write_raw_byte(data, i);
        }
    }
}
#endif

static void animate(uint8_t x, uint8_t y) {
  oled_set_cursor(x, y);

  // Update frame
  switch (anim_state) {
    case Idle:
      idle_frame = (idle_frame + 1) % _IDLE_FRAMES;
      #ifdef USE_OLED_BITMAP_COMPRESSION
          oled_write_compressed_P(idle_block_map[abs(1 - idle_frame)], idle[abs(1 - idle_frame)]);
      #else
          oled_write_raw_P(idle[abs(1 - idle_frame)], sizeof(idle[abs(1 - idle_frame)]));
      #endif
      break;
    case Prep:
      #ifdef USE_OLED_BITMAP_COMPRESSION
          oled_write_compressed_P(prep_block_map[0], prep[0]);
      #else
          oled_write_raw_P(prep[0], sizeof(prep[0]));
      #endif
      break;
    case Tap:
      tap_frame = (tap_frame + 1) % _TAP_FRAMES;
      #ifdef USE_OLED_BITMAP_COMPRESSION
          oled_write_compressed_P(tap_block_map[abs(1 - tap_frame)], tap[abs(1 - tap_frame)]);
      #else
          oled_write_raw_P(tap[abs(1 - tap_frame)], sizeof(tap[abs(1 - tap_frame)]));
      #endif
      break;
    default:
      break;
  }
}

void bongo_render(uint8_t x, uint8_t y) {
  if (timer_elapsed32(anim_timer) > anim_duration) {
    anim_timer = timer_read32();
    animate(x, y);
  }

  if (anim_state == Prep && timer_elapsed32(prep_timer) > _PREP_TIMEOUT) {
    anim_state = Idle;
    anim_duration = _IDLE_FRAME_DURATION;
  }
}

void bongo_process_record(keyrecord_t *record) {
  if (record->event.pressed) {
    anim_state = Tap;
    anim_duration = _TAP_FRAME_DURATION;
  } else {
    if (anim_state == Tap) {
      anim_state = Prep;
      prep_timer = timer_read32();
    }
  }
}

A keyboards/nullbitsco/snap/keymaps/bongo_reactive/bongo_graphics.h => keyboards/nullbitsco/snap/keymaps/bongo_reactive/bongo_graphics.h +262 -0
@@ 0,0 1,262 @@
/* Copyright 2022 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#define _IDLE_FRAMES         5
#define _PREP_FRAMES         1
#define _TAP_FRAMES          2
#define _ANIM_BYTES          512

#define NUM_OLED_BYTES 512
#define USE_OLED_BITMAP_COMPRESSION

#ifdef USE_OLED_BITMAP_COMPRESSION
static const char PROGMEM idle_block_map[_IDLE_FRAMES][64] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x48, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x48, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x79, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM idle[_IDLE_FRAMES][164] =
{
    {
        0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x04, 0x02, 0x01, 0x02, 0x04,
        0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04,
        0x04, 0x04, 0x02, 0x02, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02, 0x04, 0x04,
        0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20,
        0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02,
        0x02, 0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40,
        0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04,
        0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40,
        0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04,
        0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x01,
        0x01, 0x01
    },
    {
        0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
        0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01,
        0x01, 0x01, 0x80, 0x80, 0x60, 0x60, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20,
        0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10,
        0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
        0x01, 0xc0, 0x30, 0x0c, 0x03, 0x80, 0x86, 0x86, 0x40, 0x40, 0x40, 0x40, 0x21, 0x22, 0x22, 0x20,
        0x11, 0x11, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40,
        0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20,
        0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04,
        0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x01, 0x01, 0x01
    },
    {
        0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
        0x80, 0x80, 0x7e, 0x82, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x01,
        0x01, 0x80, 0x80, 0x60, 0x60, 0x01, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20,
        0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10,
        0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
        0x01, 0xc0, 0x30, 0x0c, 0x03, 0x80, 0x86, 0x86, 0x40, 0x40, 0x40, 0x40, 0x21, 0x22, 0x22, 0x20,
        0x11, 0x11, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40,
        0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20,
        0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04,
        0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x01, 0x01, 0x01
    },
    {
        0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
        0x80, 0x80, 0x1c, 0x34, 0xc4, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02,
        0x01, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04,
        0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20,
        0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02,
        0x02, 0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40,
        0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04,
        0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40,
        0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04,
        0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x01,
        0x01, 0x01
    },
    {
        0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x04, 0x02, 0x01, 0x02, 0x04,
        0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x06, 0x0d, 0x31, 0xc1, 0x01, 0x01, 0x01, 0x02,
        0x02, 0x02, 0x04, 0x04, 0x02, 0x02, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02,
        0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20,
        0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02,
        0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x83, 0x83, 0x40, 0x40,
        0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04,
        0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80,
        0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08,
        0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24,
        0x18, 0x01, 0x01, 0x01
    }
};

static const char PROGMEM prep_block_map[_PREP_FRAMES][64] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xbb, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM prep[_PREP_FRAMES][158] =
{
    {
        0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20,
        0x20, 0x40, 0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x84, 0x44, 0x44, 0x42,
        0x82, 0x01, 0x01, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02, 0x64, 0x18, 0x04,
        0x12, 0xc2, 0xca, 0x24, 0x88, 0xf0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20,
        0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02,
        0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x0c, 0x03, 0x02, 0x18, 0x19, 0x05, 0xfe, 0x80,
        0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08,
        0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x80, 0x80,
        0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f,
        0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01
    }
};

static const char PROGMEM tap_block_map[_TAP_FRAMES][64] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xbb, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM tap[_TAP_FRAMES][179] =
{
    {
        0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20,
        0x20, 0x40, 0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02,
        0x02, 0x01, 0x01, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02, 0x64, 0x18, 0x04,
        0x12, 0xc2, 0xca, 0x24, 0x88, 0xf0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20,
        0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02,
        0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20,
        0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02,
        0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20,
        0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02,
        0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x98, 0xc0, 0x88, 0x88, 0x8c,
        0x9c, 0x1c, 0x1e, 0x0e, 0x06
    },
    {
        0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20,
        0x20, 0x40, 0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x84, 0x44, 0x44, 0x42,
        0x82, 0x01, 0x01, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02, 0x04, 0x04, 0x08,
        0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20,
        0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02,
        0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x0c, 0x03, 0x02, 0x18, 0x19, 0x05, 0xfe, 0x80,
        0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08,
        0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x01, 0x86, 0x98, 0x60,
        0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10,
        0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x06, 0x0f, 0x0f, 0x07, 0x03, 0x03, 0x61, 0xf0, 0xf8, 0xfc, 0x60, 0x01, 0x01, 0x01, 0x3c, 0x78,
        0xf8, 0xf0, 0x70
    }
};

#else
static const char PROGMEM idle[_IDLE_FRAMES][_ANIM_BYTES] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x86, 0x86, 0x40, 0x40, 0x40, 0x40, 0x21, 0x22, 0x22, 0x20, 0x11, 0x11, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x82, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x60, 0x60, 0x00, 0x01, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x86, 0x86, 0x40, 0x40, 0x40, 0x40, 0x21, 0x22, 0x22, 0x20, 0x11, 0x11, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x34, 0xc4, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x31, 0xc1, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x04, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM prep[_PREP_FRAMES][_ANIM_BYTES] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x84, 0x44, 0x44, 0x42, 0x82, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x64, 0x18, 0x04, 0x12, 0xc2, 0xca, 0x24, 0x88, 0xf0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x02, 0x18, 0x19, 0x00, 0x05, 0xfe, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM tap[_TAP_FRAMES][_ANIM_BYTES] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x64, 0x18, 0x04, 0x12, 0xc2, 0xca, 0x24, 0x88, 0xf0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x98, 0xc0, 0x88, 0x88, 0x8c, 0x9c, 0x1c, 0x1e, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x84, 0x44, 0x44, 0x42, 0x82, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x02, 0x18, 0x19, 0x00, 0x05, 0xfe, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0f, 0x0f, 0x07, 0x03, 0x03, 0x61, 0xf0, 0xf8, 0xfc, 0x60, 0x01, 0x01, 0x01, 0x3c, 0x78, 0xf8, 0xf0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    }
};
#endif

A keyboards/nullbitsco/snap/keymaps/bongo_reactive/config.h => keyboards/nullbitsco/snap/keymaps/bongo_reactive/config.h +35 -0
@@ 0,0 1,35 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

/* space savers */
#define DYNAMIC_KEYMAP_LAYER_COUNT 3
#define NO_ACTION_TAPPING
#define NO_ACTION_ONESHOT
#define TAPPING_FORCE_HOLD

#define OLED_BRIGHTNESS 128
#define OLED_TIMEOUT 30000

// Selectively undefine to save space
// VIA support won't fit otherwise
#ifdef RGBLIGHT_ENABLE
#undef RGBLIGHT_EFFECT_TWINKLE
#endif //RGB LIGHT_ENABLE

// Split Options
#define SPLIT_TRANSPORT_MIRROR

A keyboards/nullbitsco/snap/keymaps/bongo_reactive/keymap.c => keyboards/nullbitsco/snap/keymaps/bongo_reactive/keymap.c +133 -0
@@ 0,0 1,133 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include QMK_KEYBOARD_H
#include "bongo.h"

// NOTE:
// In order to get the slave oled to receive keypresses:
// See: https://zenn.dev/teppeis/articles/2021-05-qmk-fire-process-record-in-slave

// clang-format off
enum layers {
    _BASE,
    _VIA1,
    _VIA2
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = LAYOUT_all(
             KC_ESC,   KC_F1,   KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,    KC_F7,  KC_F8,  KC_F9,   KC_F10,    KC_F11,    KC_F12,   KC_PSCR,  KC_PAUS,
    KC_F13,  KC_GRV,   KC_1,    KC_2,   KC_3,   KC_4,   KC_5,   KC_6,     KC_7,   KC_8,   KC_9,    KC_0,      KC_MINS,   KC_EQL,   KC_BSPC,  KC_DEL,   KC_HOME,
    KC_F14,  KC_TAB,   KC_Q,    KC_W,   KC_E,   KC_R,           KC_T,     KC_Y,   KC_U,   KC_I,    KC_O,      KC_P,      KC_LBRC,  KC_RBRC,  KC_BSLS,  KC_END,  
    KC_F15,  KC_CAPS,  KC_A,    KC_S,   KC_D,   KC_F,           KC_G,     KC_H,   KC_J,   KC_K,    KC_L,      KC_SCLN,   KC_QUOT,  KC_ENT,             KC_PGUP,
    KC_F16,  KC_LSFT,  KC_NUHS, KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,     KC_N,   KC_M,   KC_COMM, KC_DOT,    KC_SLSH,   KC_RSFT,            KC_UP,    KC_PGDN,
    KC_F17,  KC_LCTL,  KC_LGUI, KC_LALT,     MO(_VIA1),         KC_SPC,   KC_SPC,                  MO(_VIA1), KC_RALT,   KC_RCTL,  KC_LEFT,  KC_DOWN,  KC_RGHT
  ),
    [_VIA1] = LAYOUT_all(
            QK_BOOT,KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  ),
    [_VIA2] = LAYOUT_all(
            KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  )
};
// clang-format on

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
    [_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU), ENCODER_CCW_CW(KC_MPRV, KC_MNXT) },
    [_VIA1] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) },
    [_VIA2] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) }
};
#endif

oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    if (is_keyboard_left())
        return OLED_ROTATION_0;
    else
        return OLED_ROTATION_180;
}

static void render_status(void) {
    oled_set_cursor(0, 0);
    oled_write_P(PSTR("SNAP75 "), false);
    oled_write_P(PSTR("Layer "), false);
    switch (get_highest_layer(layer_state)) {
        case _VIA1:
            oled_write_P(PSTR("FN1 "), false);
            break;
        case _VIA2:
            oled_write_P(PSTR("FN2 "), false);
            break;
        default: // use BASE case as default
            oled_write_P(PSTR("Base"), false);
    }

    // Host Keyboard LED Status
    oled_set_cursor(0, 1);
    static uint8_t persistent_led_state = 0;
    uint8_t led_usb_state = host_keyboard_leds();

    // Only update if the LED state has changed
    // Otherwise, the OLED will not turn off if an LED is on.
    if (persistent_led_state != led_usb_state) {
        persistent_led_state = led_usb_state;
        
        oled_write_ln_P(PSTR(""), false);

        if (IS_LED_ON(led_usb_state, USB_LED_CAPS_LOCK)) {
            oled_set_cursor(0, 1);
            oled_write_P(PSTR("CAPS"), false);
        }

        if (IS_LED_ON(led_usb_state, USB_LED_NUM_LOCK)) {
            oled_set_cursor(5, 1);
            oled_write_P(PSTR("NUM"), true);
        }

        if (IS_LED_ON(led_usb_state, USB_LED_SCROLL_LOCK)) {
            oled_set_cursor(9, 1);
            oled_write_P(PSTR("SCR"), false);
        }
    }
}

bool oled_task_user(void) {
    if (is_keyboard_master()) {
        render_status();
    } else {
        bongo_render(0, 0);
    }
    return true;
}

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    bongo_process_record(record);
    return true;
}

bool should_process_keypress(void) {
    return true;
}

A keyboards/nullbitsco/snap/keymaps/bongo_reactive/rules.mk => keyboards/nullbitsco/snap/keymaps/bongo_reactive/rules.mk +4 -0
@@ 0,0 1,4 @@
OLED_ENABLE = yes
OLED_DRIVER = SSD1306
VIA_ENABLE = yes
ENCODER_MAP_ENABLE = yes

A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/bongo.h => keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/bongo.h +121 -0
@@ 0,0 1,121 @@
/* Copyright 2021 Chris Tanaka <https://github.com/christanaka>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bongo_graphics.h"
#include QMK_KEYBOARD_H

#define _IDLE_FRAMES         5
#define _PREP_FRAMES         1
#define _TAP_FRAMES          2
#define _ANIM_BYTES          512   // Number of bytes in array (max is 1024)
#define _IDLE_FRAME_DURATION 175
#define _TAP_FRAME_DURATION  75
#define _PREP_TIMEOUT        750

enum anim_states
{
    Idle,
    Prep,
    Tap
};

static uint8_t anim_state = Idle;
static uint8_t anim_duration = _IDLE_FRAME_DURATION;
static uint32_t anim_timer = 0;

static uint8_t idle_frame = 0;
static uint8_t tap_frame = 0;

static uint32_t prep_timer = 0;

// Decompress and write a precompressed bitmap frame to the OLED.
// Documentation and python compression script available at:
// https://github.com/nullbitsco/squeez-o
#ifdef USE_OLED_BITMAP_COMPRESSION
static void oled_write_compressed_P(const char* input_block_map, const char* input_block_list) {
    uint16_t block_index = 0;
    for (uint16_t i = 0; i < NUM_OLED_BYTES; i++) {
        uint8_t bit          = i % 8;
        uint8_t map_index    = i / 8;
        uint8_t _block_map   = (uint8_t)pgm_read_byte_near(input_block_map + map_index);
        uint8_t nonzero_byte = (_block_map & (1 << bit));
        if (nonzero_byte) {
            const char data = (const char)pgm_read_byte_near(input_block_list + block_index++);
            oled_write_raw_byte(data, i);
        } else {
            const char data = (const char)0x00;
            oled_write_raw_byte(data, i);
        }
    }
}
#endif

static void animate(uint8_t x, uint8_t y) {
  oled_set_cursor(x, y);

  // Update frame
  switch (anim_state) {
    case Idle:
      idle_frame = (idle_frame + 1) % _IDLE_FRAMES;
      #ifdef USE_OLED_BITMAP_COMPRESSION
          oled_write_compressed_P(idle_block_map[abs(1 - idle_frame)], idle[abs(1 - idle_frame)]);
      #else
          oled_write_raw_P(idle[abs(1 - idle_frame)], sizeof(idle[abs(1 - idle_frame)]));
      #endif
      break;
    case Prep:
      #ifdef USE_OLED_BITMAP_COMPRESSION
          oled_write_compressed_P(prep_block_map[0], prep[0]);
      #else
          oled_write_raw_P(prep[0], sizeof(prep[0]));
      #endif
      break;
    case Tap:
      tap_frame = (tap_frame + 1) % _TAP_FRAMES;
      #ifdef USE_OLED_BITMAP_COMPRESSION
          oled_write_compressed_P(tap_block_map[abs(1 - tap_frame)], tap[abs(1 - tap_frame)]);
      #else
          oled_write_raw_P(tap[abs(1 - tap_frame)], sizeof(tap[abs(1 - tap_frame)]));
      #endif
      break;
    default:
      break;
  }
}

void bongo_render(uint8_t x, uint8_t y) {
  if (timer_elapsed32(anim_timer) > anim_duration) {
    anim_timer = timer_read32();
    animate(x, y);
  }

  if (anim_state == Prep && timer_elapsed32(prep_timer) > _PREP_TIMEOUT) {
    anim_state = Idle;
    anim_duration = _IDLE_FRAME_DURATION;
  }
}

void bongo_process_record(keyrecord_t *record) {
  if (record->event.pressed) {
    anim_state = Tap;
    anim_duration = _TAP_FRAME_DURATION;
  } else {
    if (anim_state == Tap) {
      anim_state = Prep;
      prep_timer = timer_read32();
    }
  }
}

A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/bongo_graphics.h => keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/bongo_graphics.h +262 -0
@@ 0,0 1,262 @@
/* Copyright 2022 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#define _IDLE_FRAMES         5
#define _PREP_FRAMES         1
#define _TAP_FRAMES          2
#define _ANIM_BYTES          512

#define NUM_OLED_BYTES 512
#define USE_OLED_BITMAP_COMPRESSION

#ifdef USE_OLED_BITMAP_COMPRESSION
static const char PROGMEM idle_block_map[_IDLE_FRAMES][64] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x48, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x48, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x79, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM idle[_IDLE_FRAMES][164] =
{
    {
        0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x04, 0x02, 0x01, 0x02, 0x04,
        0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04,
        0x04, 0x04, 0x02, 0x02, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02, 0x04, 0x04,
        0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20,
        0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02,
        0x02, 0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40,
        0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04,
        0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40,
        0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04,
        0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x01,
        0x01, 0x01
    },
    {
        0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
        0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01,
        0x01, 0x01, 0x80, 0x80, 0x60, 0x60, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20,
        0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10,
        0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
        0x01, 0xc0, 0x30, 0x0c, 0x03, 0x80, 0x86, 0x86, 0x40, 0x40, 0x40, 0x40, 0x21, 0x22, 0x22, 0x20,
        0x11, 0x11, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40,
        0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20,
        0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04,
        0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x01, 0x01, 0x01
    },
    {
        0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
        0x80, 0x80, 0x7e, 0x82, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x01,
        0x01, 0x80, 0x80, 0x60, 0x60, 0x01, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20,
        0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10,
        0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
        0x01, 0xc0, 0x30, 0x0c, 0x03, 0x80, 0x86, 0x86, 0x40, 0x40, 0x40, 0x40, 0x21, 0x22, 0x22, 0x20,
        0x11, 0x11, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40,
        0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20,
        0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04,
        0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x01, 0x01, 0x01
    },
    {
        0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
        0x80, 0x80, 0x1c, 0x34, 0xc4, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02,
        0x01, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04,
        0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20,
        0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02,
        0x02, 0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40,
        0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04,
        0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40,
        0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04,
        0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x01,
        0x01, 0x01
    },
    {
        0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x04, 0x02, 0x01, 0x02, 0x04,
        0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x06, 0x0d, 0x31, 0xc1, 0x01, 0x01, 0x01, 0x02,
        0x02, 0x02, 0x04, 0x04, 0x02, 0x02, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02,
        0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20,
        0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02,
        0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x83, 0x83, 0x40, 0x40,
        0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04,
        0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x01, 0x86, 0x98, 0x60, 0x80, 0x80, 0x80, 0x80,
        0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08,
        0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24,
        0x18, 0x01, 0x01, 0x01
    }
};

static const char PROGMEM prep_block_map[_PREP_FRAMES][64] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xbb, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM prep[_PREP_FRAMES][158] =
{
    {
        0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20,
        0x20, 0x40, 0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x84, 0x44, 0x44, 0x42,
        0x82, 0x01, 0x01, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02, 0x64, 0x18, 0x04,
        0x12, 0xc2, 0xca, 0x24, 0x88, 0xf0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20,
        0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02,
        0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x0c, 0x03, 0x02, 0x18, 0x19, 0x05, 0xfe, 0x80,
        0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08,
        0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x80, 0x80,
        0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f,
        0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01
    }
};

static const char PROGMEM tap_block_map[_TAP_FRAMES][64] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x79, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xbb, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM tap[_TAP_FRAMES][179] =
{
    {
        0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20,
        0x20, 0x40, 0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02,
        0x02, 0x01, 0x01, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02, 0x64, 0x18, 0x04,
        0x12, 0xc2, 0xca, 0x24, 0x88, 0xf0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20,
        0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02,
        0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20,
        0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02,
        0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20,
        0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02,
        0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x98, 0xc0, 0x88, 0x88, 0x8c,
        0x9c, 0x1c, 0x1e, 0x0e, 0x06
    },
    {
        0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20,
        0x20, 0x40, 0x40, 0x80, 0x80, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x84, 0x44, 0x44, 0x42,
        0x82, 0x01, 0x01, 0x01, 0x80, 0x40, 0x80, 0x80, 0x40, 0x30, 0x30, 0x01, 0x02, 0x04, 0x04, 0x08,
        0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20,
        0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02,
        0x01, 0x01, 0x01, 0x01, 0xe0, 0x18, 0x06, 0x01, 0x0c, 0x03, 0x02, 0x18, 0x19, 0x05, 0xfe, 0x80,
        0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08,
        0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x01, 0x86, 0x98, 0x60,
        0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10,
        0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x06, 0x0f, 0x0f, 0x07, 0x03, 0x03, 0x61, 0xf0, 0xf8, 0xfc, 0x60, 0x01, 0x01, 0x01, 0x3c, 0x78,
        0xf8, 0xf0, 0x70
    }
};

#else
static const char PROGMEM idle[_IDLE_FRAMES][_ANIM_BYTES] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x86, 0x86, 0x40, 0x40, 0x40, 0x40, 0x21, 0x22, 0x22, 0x20, 0x11, 0x11, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x82, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x60, 0x60, 0x00, 0x01, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x86, 0x86, 0x40, 0x40, 0x40, 0x40, 0x21, 0x22, 0x22, 0x20, 0x11, 0x11, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x34, 0xc4, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x18, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x31, 0xc1, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x04, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM prep[_PREP_FRAMES][_ANIM_BYTES] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x84, 0x44, 0x44, 0x42, 0x82, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x64, 0x18, 0x04, 0x12, 0xc2, 0xca, 0x24, 0x88, 0xf0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x02, 0x18, 0x19, 0x00, 0x05, 0xfe, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    }
};

static const char PROGMEM tap[_TAP_FRAMES][_ANIM_BYTES] =
{
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x64, 0x18, 0x04, 0x12, 0xc2, 0xca, 0x24, 0x88, 0xf0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x41, 0x42, 0x24, 0x98, 0xc0, 0x88, 0x88, 0x8c, 0x9c, 0x1c, 0x1e, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    },
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc1, 0x01, 0x01, 0x02, 0x02, 0x04, 0x84, 0x44, 0x44, 0x42, 0x82, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x80, 0x80, 0x40, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x06, 0x01, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x02, 0x18, 0x19, 0x00, 0x05, 0xfe, 0x80, 0x83, 0x83, 0x40, 0x40, 0x40, 0x40, 0x20, 0x21, 0x21, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0x00, 0x00, 0x01, 0x86, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x0f, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0f, 0x0f, 0x07, 0x03, 0x03, 0x61, 0xf0, 0xf8, 0xfc, 0x60, 0x01, 0x01, 0x01, 0x3c, 0x78, 0xf8, 0xf0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    }
};
#endif

A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/config.h => keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/config.h +29 -0
@@ 0,0 1,29 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#define OLED_BRIGHTNESS 128
#define OLED_TIMEOUT 30000

/* space savers */
#define DYNAMIC_KEYMAP_LAYER_COUNT 3
#define NO_ACTION_TAPPING
#define NO_ACTION_ONESHOT
#define TAPPING_FORCE_HOLD

// Split Options
#define SPLIT_TRANSPORT_MIRROR

A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/keymap.c => keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/keymap.c +87 -0
@@ 0,0 1,87 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include QMK_KEYBOARD_H
#include "bongo.h"

// NOTE:
// In order to get the slave oled to receive keypresses:
// See: https://zenn.dev/teppeis/articles/2021-05-qmk-fire-process-record-in-slave

// clang-format off
enum layers {
    _BASE,
    _VIA1,
    _VIA2
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = LAYOUT_all(
             KC_ESC,   KC_F1,   KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,    KC_F7,  KC_F8,  KC_F9,   KC_F10,    KC_F11,    KC_F12,   KC_PSCR,  KC_PAUS,
    KC_F13,  KC_GRV,   KC_1,    KC_2,   KC_3,   KC_4,   KC_5,   KC_6,     KC_7,   KC_8,   KC_9,    KC_0,      KC_MINS,   KC_EQL,   KC_BSPC,  KC_DEL,   KC_HOME,
    KC_F14,  KC_TAB,   KC_Q,    KC_W,   KC_E,   KC_R,           KC_T,     KC_Y,   KC_U,   KC_I,    KC_O,      KC_P,      KC_LBRC,  KC_RBRC,  KC_BSLS,  KC_END,  
    KC_F15,  KC_CAPS,  KC_A,    KC_S,   KC_D,   KC_F,           KC_G,     KC_H,   KC_J,   KC_K,    KC_L,      KC_SCLN,   KC_QUOT,  KC_ENT,             KC_PGUP,
    KC_F16,  KC_LSFT,  KC_NUHS, KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,     KC_N,   KC_M,   KC_COMM, KC_DOT,    KC_SLSH,   KC_RSFT,            KC_UP,    KC_PGDN,
    KC_F17,  KC_LCTL,  KC_LGUI, KC_LALT,     MO(_VIA1),         KC_SPC,   KC_SPC,                  MO(_VIA1), KC_RALT,   KC_RCTL,  KC_LEFT,  KC_DOWN,  KC_RGHT
  ),
    [_VIA1] = LAYOUT_all(
            QK_BOOT,KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  ),
    [_VIA2] = LAYOUT_all(
            KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  )
};
// clang-format on

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
    [_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU), ENCODER_CCW_CW(KC_MPRV, KC_MNXT) },
    [_VIA1] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) },
    [_VIA2] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) }
};
#endif

oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    if (is_keyboard_left())
        return OLED_ROTATION_0;
    else
        return OLED_ROTATION_180;
}

bool oled_task_user(void) {
    if (is_keyboard_master()) {
        bongo_render(0, 0);
    }
    return true;
}

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    bongo_process_record(record);
    return true;
}

bool should_process_keypress(void) {
    return true;
}

A keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/rules.mk => keyboards/nullbitsco/snap/keymaps/bongo_reactive_single_oled/rules.mk +5 -0
@@ 0,0 1,5 @@
OLED_ENABLE = yes
OLED_DRIVER = SSD1306
WPM_ENABLE = yes
VIA_ENABLE = yes
ENCODER_MAP_ENABLE = yes

A keyboards/nullbitsco/snap/keymaps/default/keymap.c => keyboards/nullbitsco/snap/keymaps/default/keymap.c +105 -0
@@ 0,0 1,105 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include QMK_KEYBOARD_H
#include "common/remote_kb.h"

// clang-format off
enum layers {
    _BASE = 0,
    _FUNC
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = LAYOUT_ansi(
             KC_ESC,   KC_F1,   KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,    KC_F7,  KC_F8,  KC_F9,   KC_F10,    KC_F11,   KC_F12,   KC_PSCR,  KC_PAUS,
    KC_F13,  KC_GRV,   KC_1,    KC_2,   KC_3,   KC_4,   KC_5,   KC_6,     KC_7,   KC_8,   KC_9,    KC_0,      KC_MINS,  KC_EQL,        KC_BSPC,       KC_HOME,
    KC_F14,  KC_TAB,   KC_Q,    KC_W,   KC_E,   KC_R,           KC_T,     KC_Y,   KC_U,   KC_I,    KC_O,      KC_P,     KC_LBRC,  KC_RBRC,  KC_BSLS,  KC_END,
    KC_F15,  KC_CAPS,  KC_A,    KC_S,   KC_D,   KC_F,           KC_G,     KC_H,   KC_J,   KC_K,    KC_L,      KC_SCLN,  KC_QUOT,  KC_ENT,             KC_PGUP,
    KC_F16,       KC_LSFT,      KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,     KC_N,   KC_M,   KC_COMM, KC_DOT,    KC_SLSH,  KC_RSFT,            KC_UP,    KC_PGDN,
    KC_F17,  KC_LCTL,  KC_LGUI, KC_LALT,        MO(_FUNC),     KC_SPC,   KC_BSPC,                  MO(_FUNC), KC_RALT,  KC_RCTL,  KC_LEFT,  KC_DOWN,  KC_RGHT
  ),
    [_FUNC] = LAYOUT_ansi(
             QK_BOOT,  _____,   _____,  _____,  _____,  _____,  _____,    _____,  _____,  _____,   _____,     _____,    _____,    _____,    _____,
    RGB_TOG, _____,    _____,   _____,  _____,  _____,  _____,  _____,    _____,  _____,  _____,   _____,     _____,    _____,         _____,         _____,
    _____,   _____,    _____,   _____,  _____,  _____,          _____,    _____,  _____,  _____,   _____,     _____,    _____,    _____,    _____,    _____,
    _____,   _____,    _____,   _____,  _____,  _____,          _____,    _____,  _____,  _____,   _____,     _____,    _____,    _____,              _____,
    _____,        _____,        _____,  _____,  _____,  _____,  _____,    _____,  _____,  _____,   _____,     _____,    _____,              _____,    _____,
    _____,   _____,    _____,   _____,          _____,          _____,    _____,                   _____,     _____,    _____,    KC_MPRV,  KC_MPLY,  KC_MNXT
  ),
};
// clang-format on

// RGB config, for changing RGB settings on non-VIA firmware
#ifdef RGBLIGHT_ENABLE
void change_RGB(bool clockwise) {
    bool shift = get_mods() & MOD_MASK_SHIFT;
    bool alt   = get_mods() & MOD_MASK_ALT;
    bool ctrl  = get_mods() & MOD_MASK_CTRL;

#ifdef CONSOLE_ENABLE
    dprintf("Mods: %u\n", get_mods());
#endif

    if (clockwise) {
        if (alt) {
            rgblight_increase_hue();
        } else if (ctrl) {
            rgblight_increase_val();
        } else if (shift) {
            rgblight_increase_sat();
        } else {
            rgblight_step();
        }

    } else {
        if (alt) {
            rgblight_decrease_hue();
        } else if (ctrl) {
            rgblight_decrease_val();
        } else if (shift) {
            rgblight_decrease_sat();
        } else {
            rgblight_step_reverse();
        }
    }
}
#endif

bool encoder_update_user(uint8_t index, bool clockwise) {
    // change RGB settings and don't do anything else
    if (!layer_state_is(_BASE)) {
        #ifdef RGBLIGHT_ENABLE
        change_RGB(clockwise);
        #endif
        return false;
    }
    /* Left encoder */
    if (index == 0) {
        if (clockwise) {
            tap_code_delay(KC_VOLU, 10);
        } else {
            tap_code_delay(KC_VOLD, 10);
        }
    /* Right encoder */
    } else if (index == 1) {
        if (clockwise) {
            tap_code_delay(KC_MNXT, 10);
        } else {
            tap_code_delay(KC_MPRV, 10);
        }
    }
    return true;
}

A keyboards/nullbitsco/snap/keymaps/iso/keymap.c => keyboards/nullbitsco/snap/keymaps/iso/keymap.c +104 -0
@@ 0,0 1,104 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include QMK_KEYBOARD_H

// clang-format off
enum layers {
    _BASE = 0,
    _FUNC
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = LAYOUT_iso(
             KC_ESC,   KC_F1,   KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,    KC_F7,  KC_F8,  KC_F9,   KC_F10,    KC_F11,   KC_F12,   KC_PSCR,  KC_PAUS,
    KC_F13,  KC_GRV,   KC_1,    KC_2,   KC_3,   KC_4,   KC_5,   KC_6,     KC_7,   KC_8,   KC_9,    KC_0,      KC_MINS,  KC_EQL,        KC_BSPC,       KC_HOME,
    KC_F14,  KC_TAB,   KC_Q,    KC_W,   KC_E,   KC_R,           KC_T,     KC_Y,   KC_U,   KC_I,    KC_O,      KC_P,     KC_LBRC,  KC_RBRC,  KC_ENT,   KC_END,
    KC_F15,  KC_CAPS,  KC_A,    KC_S,   KC_D,   KC_F,           KC_G,     KC_H,   KC_J,   KC_K,    KC_L,      KC_SCLN,  KC_QUOT,  KC_BSLS,            KC_PGUP,
    KC_F16,  KC_LSFT,  KC_NUHS, KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,     KC_N,   KC_M,   KC_COMM, KC_DOT,    KC_SLSH,  KC_RSFT,            KC_UP,    KC_PGDN,
    KC_F17,  KC_LCTL,  KC_LGUI, KC_LALT,        MO(_FUNC),     KC_SPC,   KC_SPC,                   MO(_FUNC), KC_RALT,  KC_RCTL,  KC_LEFT,  KC_DOWN,  KC_RGHT
  ),
    [_FUNC] = LAYOUT_iso(
             QK_BOOT, _____,  _____,  _____,  _____,  _____,    _____,  _____,  _____,   _____,     _____,    _____,    _____,    _____,    _____,
    RGB_TOG, _____,   _____,  _____,  _____,  _____,  _____,    _____,  _____,  _____,   _____,     _____,    _____,    _____,         _____,        _____,
    _____,   _____,   _____,   _____,  _____,  _____,          _____,    _____,  _____,  _____,   _____,     _____,    _____,    _____,    _____,    _____,
    _____,   _____,   _____,   _____,  _____,  _____,          _____,    _____,  _____,  _____,   _____,     _____,    _____,    _____,              _____,
    _____,   _____,   _____,   _____,  _____,  _____,  _____,  _____,    _____,  _____,  _____,   _____,     _____,    _____,              _____,    _____,
    _____,   _____,   _____,   _____,          _____,          _____,    _____,                   _____,     _____,    _____,    KC_MPRV,  KC_MPLY,  KC_MNXT
  ),
};
// clang-format on

// RGB config, for changing RGB settings on non-VIA firmwares
#ifdef RGBLIGHT_ENABLE
void change_RGB(bool clockwise) {
    bool shift = get_mods() & MOD_MASK_SHIFT;
    bool alt   = get_mods() & MOD_MASK_ALT;
    bool ctrl  = get_mods() & MOD_MASK_CTRL;

#ifdef CONSOLE_ENABLE
    dprintf("Mods: %u\n", get_mods());
#endif

    if (clockwise) {
        if (alt) {
            rgblight_increase_hue();
        } else if (ctrl) {
            rgblight_increase_val();
        } else if (shift) {
            rgblight_increase_sat();
        } else {
            rgblight_step();
        }

    } else {
        if (alt) {
            rgblight_decrease_hue();
        } else if (ctrl) {
            rgblight_decrease_val();
        } else if (shift) {
            rgblight_decrease_sat();
        } else {
            rgblight_step_reverse();
        }
    }
}
#endif

bool encoder_update_user(uint8_t index, bool clockwise) {
    if (layer_state_is(1)) {
        // change RGB settings
        #ifdef RGBLIGHT_ENABLE
        change_RGB(clockwise);
        #endif
    } else {
        if (index == 0) {
            // Left encoder: Volume control
            if (clockwise) {
                tap_code(KC_VOLU);
            } else {
                tap_code(KC_VOLD);
            }
        } else if (index == 1) {
            // Right encoder: skip forward/back
            if (clockwise) {
                tap_code(KC_MNXT);
            } else {
                tap_code(KC_MPRV);
            }
        }
    }
    return true;
}

A keyboards/nullbitsco/snap/keymaps/oled/config.h => keyboards/nullbitsco/snap/keymaps/oled/config.h +27 -0
@@ 0,0 1,27 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

/* space savers */
#define DYNAMIC_KEYMAP_LAYER_COUNT 3
#define NO_ACTION_TAPPING
#define NO_ACTION_ONESHOT
#define TAPPING_FORCE_HOLD

#define OLED_BRIGHTNESS 128
#define OLED_TIMEOUT 30000
#define OLED_UPDATE_INTERVAL 250

A keyboards/nullbitsco/snap/keymaps/oled/keymap.c => keyboards/nullbitsco/snap/keymaps/oled/keymap.c +163 -0
@@ 0,0 1,163 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include QMK_KEYBOARD_H
#include "oled_graphics.h"

// clang-format off
enum layers {
    _BASE,
    _VIA1,
    _VIA2
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = LAYOUT_all(
             KC_ESC,   KC_F1,   KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,    KC_F7,  KC_F8,  KC_F9,   KC_F10,    KC_F11,    KC_F12,   KC_PSCR,  KC_PAUS,
    KC_F13,  KC_GRV,   KC_1,    KC_2,   KC_3,   KC_4,   KC_5,   KC_6,     KC_7,   KC_8,   KC_9,    KC_0,      KC_MINS,   KC_EQL,   KC_BSPC,  KC_DEL,   KC_HOME,
    KC_F14,  KC_TAB,   KC_Q,    KC_W,   KC_E,   KC_R,           KC_T,     KC_Y,   KC_U,   KC_I,    KC_O,      KC_P,      KC_LBRC,  KC_RBRC,  KC_BSLS,  KC_END,  
    KC_F15,  KC_CAPS,  KC_A,    KC_S,   KC_D,   KC_F,           KC_G,     KC_H,   KC_J,   KC_K,    KC_L,      KC_SCLN,   KC_QUOT,  KC_ENT,             KC_PGUP,
    KC_F16,  KC_LSFT,  KC_NUHS, KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,     KC_N,   KC_M,   KC_COMM, KC_DOT,    KC_SLSH,   KC_RSFT,            KC_UP,    KC_PGDN,
    KC_F17,  KC_LCTL,  KC_LGUI, KC_LALT,     MO(_VIA1),         KC_SPC,   KC_SPC,                  MO(_VIA1), KC_RALT,   KC_RCTL,  KC_LEFT,  KC_DOWN,  KC_RGHT
  ),
    [_VIA1] = LAYOUT_all(
            QK_BOOT,KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  ),
    [_VIA2] = LAYOUT_all(
            KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  )
};
// clang-format on

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
    [_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU), ENCODER_CCW_CW(KC_MPRV, KC_MNXT) },
    [_VIA1] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) },
    [_VIA2] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) }
};
#endif


// Decompress and write a precompressed bitmap frame to the OLED.
// Documentation and python compression script available at:
// https://github.com/nullbitsco/squeez-o
#ifdef USE_OLED_BITMAP_COMPRESSION
static void oled_write_compressed_P(const char* input_block_map, const char* input_block_list) {
    uint16_t block_index = 0;
    for (uint16_t i = 0; i < NUM_OLED_BYTES; i++) {
        uint8_t bit          = i % 8;
        uint8_t map_index    = i / 8;
        uint8_t _block_map   = (uint8_t)pgm_read_byte_near(input_block_map + map_index);
        uint8_t nonzero_byte = (_block_map & (1 << bit));
        if (nonzero_byte) {
            const char data = (const char)pgm_read_byte_near(input_block_list + block_index++);
            oled_write_raw_byte(data, i);
        } else {
            const char data = (const char)0x00;
            oled_write_raw_byte(data, i);
        }
    }
}
#endif

oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    if (is_keyboard_left())
        return OLED_ROTATION_0;
    else
        return OLED_ROTATION_180;
}

static void render_nullbits_logo(void) {
#ifdef USE_OLED_BITMAP_COMPRESSION
    oled_write_compressed_P(nullbits_logo_block_map, nullbits_logo_bmp);
#else
    oled_write_raw_P(nullbits_logo, sizeof(nullbits_logo));
#endif
}

static void render_status(void) {
    oled_set_cursor(0, 0);
    oled_write_P(PSTR("SNAP75 "), false);
    oled_write_P(PSTR("Layer "), false);
    switch (get_highest_layer(layer_state)) {
        case _VIA1:
            oled_write_P(PSTR("FN1 "), false);
            break;
        case _VIA2:
            oled_write_P(PSTR("FN2 "), false);
            break;
        default: // use BASE case as default
            oled_write_P(PSTR("Base"), false);
    }

    // Host Keyboard LED Status
    oled_set_cursor(0, 1);
    static uint8_t persistent_led_state = 0;
    uint8_t led_usb_state = host_keyboard_leds();

    // Only update if the LED state has changed
    // Otherwise, the OLED will not turn off if an LED is on.
    if (persistent_led_state != led_usb_state) {
        persistent_led_state = led_usb_state;
        
        oled_write_ln_P(PSTR(""), false);

        if (IS_LED_ON(led_usb_state, USB_LED_CAPS_LOCK)) {
            oled_set_cursor(0, 1);
            oled_write_P(PSTR("CAPS"), false);
        }

        if (IS_LED_ON(led_usb_state, USB_LED_NUM_LOCK)) {
            oled_set_cursor(5, 1);
            oled_write_P(PSTR("NUM"), true);
        }

        if (IS_LED_ON(led_usb_state, USB_LED_SCROLL_LOCK)) {
            oled_set_cursor(9, 1);
            oled_write_P(PSTR("SCR"), false);
        }
    }

    // WPM and max WPM
    oled_set_cursor(0, 2);
    oled_write_P(PSTR("WPM "), false);
    uint8_t current_wpm = get_current_wpm();
    oled_write(get_u8_str(current_wpm, '0'), true);

    oled_set_cursor(8, 2);
    oled_write_P(PSTR("MAX "), false);
    static uint8_t max_wpm;
    max_wpm = MAX(max_wpm, current_wpm);
    oled_write(get_u8_str(max_wpm, '0'), true);
}

bool oled_task_user(void) {
    if (is_keyboard_master()) {
        render_status();
    } else {
        render_nullbits_logo();
    }
    return true;
}

A keyboards/nullbitsco/snap/keymaps/oled/oled_graphics.h => keyboards/nullbitsco/snap/keymaps/oled/oled_graphics.h +82 -0
@@ 0,0 1,82 @@
/* Copyright 2022 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#define NUM_OLED_BYTES 512
#define USE_OLED_BITMAP_COMPRESSION

#ifdef USE_OLED_BITMAP_COMPRESSION
static const char PROGMEM nullbits_logo_block_map[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7c, 0x78, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x80, 0xf7, 0x0f, 0x1e, 0x3c, 0x3c, 0x7c, 0xf8, 0x3f, 0xf0, 0xf9, 0x3f, 0xff, 0x0f, 0x00,
    0x00, 0x80, 0xf7, 0x1f, 0x1e, 0x3c, 0x3c, 0x7c, 0xf8, 0xff, 0xe1, 0xf9, 0xbf, 0xff, 0x0f, 0x00,
    0x00, 0x80, 0x07, 0x1e, 0xfe, 0x3f, 0x3c, 0x7c, 0xf8, 0xff, 0xe1, 0xc1, 0x83, 0xff, 0x0f, 0x00
};

static const char PROGMEM nullbits_logo_bmp[] = {
    0xf6, 0xff, 0xff, 0xfe, 0xe4, 0xfe, 0xff, 0xfe, 0xf4, 0xfe, 0xff, 0xfe, 0xfe, 0xc0, 0xe0, 0xe0,
    0xe0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0xe0,
    0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0x80, 0x01, 0xc3, 0xe3, 0xe3, 0xc3, 0xc0,
    0xe0, 0xe0, 0xfe, 0xfe, 0xff, 0xfe, 0xe0, 0xe0, 0xe0, 0xc0, 0x80, 0x80, 0xc0, 0xc0, 0xe0, 0xe0,
    0xe0, 0xe0, 0xc0, 0xe0, 0xe0, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x03, 0x03, 0xff,
    0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x03, 0x03, 0x07, 0x0f, 0xff, 0xff,
    0xfe, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01,
    0x01, 0x1e, 0x3f, 0x7f, 0xff, 0xfb, 0xf3, 0xf1, 0xe1, 0xe1, 0xe1, 0xc1, 0x81, 0x01, 0x7f, 0xff,
    0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x0f, 0x3f, 0x7f, 0xff, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xff,
    0x7f, 0x3f, 0x1f, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0xff, 0xff, 0x7f,
    0xf0, 0xf0, 0xf0, 0xf8, 0x78, 0x7e, 0x3f, 0x3f, 0x1f, 0x07, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0xff,
    0xff, 0xff, 0x70, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xfb, 0x7f, 0x7f, 0x3f, 0x1f
};

#else
static const char PROGMEM nullbits_logo[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0xf6, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xfe, 0xff, 0xfe, 0xf4, 0x00,
    0x00, 0x00, 0x00, 0xfe, 0xff, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
    0xe0, 0xe0, 0xe0, 0x00, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
    0x00, 0xc0, 0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xe0, 0xe0, 0x00, 0x00,
    0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
    0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x01, 0xc3, 0xe3, 0xe3, 0xc3, 0x00, 0x00, 0xc0, 0xe0, 0xe0, 0xfe, 0xfe,
    0xff, 0xfe, 0xe0, 0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0,
    0xc0, 0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
    0xff, 0xff, 0xff, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00,
    0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00,
    0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
    0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x03, 0x03, 0x07, 0x0f, 0xff, 0xff, 0xfe,
    0xfc, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x01, 0x01, 0xff, 0xff,
    0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0x00, 0x1e, 0x3f, 0x7f, 0xff, 0xfb, 0xf3, 0xf1, 0xe1, 0xe1,
    0xe1, 0xc1, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
    0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
    0x00, 0x0f, 0x3f, 0x7f, 0xff, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0x7f, 0x3f, 0x1f, 0x00, 0x00,
    0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0x00,
    0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x7f, 0xf0, 0xf0, 0xf0, 0xf8, 0x78, 0x7e, 0x3f, 0x3f, 0x1f,
    0x07, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff,
    0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xfb,
    0x7f, 0x7f, 0x3f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif

A keyboards/nullbitsco/snap/keymaps/oled/rules.mk => keyboards/nullbitsco/snap/keymaps/oled/rules.mk +5 -0
@@ 0,0 1,5 @@
OLED_ENABLE = yes
OLED_DRIVER = SSD1306
WPM_ENABLE = yes
VIA_ENABLE = yes
ENCODER_MAP_ENABLE = yes

A keyboards/nullbitsco/snap/keymaps/typehud/config.h => keyboards/nullbitsco/snap/keymaps/typehud/config.h +46 -0
@@ 0,0 1,46 @@
/* Copyright 2022 Chris Tanaka <https://github.com/christanaka>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

/* space savers */
#define DYNAMIC_KEYMAP_LAYER_COUNT 3
#define NO_ACTION_TAPPING
#define NO_ACTION_ONESHOT
#define TAPPING_FORCE_HOLD

// Old configuration
#define OLED_BRIGHTNESS 128
#define OLED_TIMEOUT 30000
#define OLED_UPDATE_INTERVAL 200

// Selectively undefine to save space
// VIA support won't fit otherwise
#ifdef RGBLIGHT_ENABLE
#undef RGBLIGHT_EFFECT_TWINKLE
#endif //RGB LIGHT_ENABLE

// Split configuration
#define SPLIT_TRANSPORT_MIRROR
#define SPLIT_WPM_ENABLE

// Typehud configuration
#define TYPEHUD_FILLGRAPH
#define TYPEHUD_MATRIX_COLS 16
// #define TYPEHUD_MASTER
// #define TYPEHUD_MATRIX_ROTATE_90
// #define TYPEHUD_MATRIX_ROTATE_180
// #define TYPEHUD_MATRIX_ROTATE_270

A keyboards/nullbitsco/snap/keymaps/typehud/keymap.c => keyboards/nullbitsco/snap/keymaps/typehud/keymap.c +157 -0
@@ 0,0 1,157 @@
/* Copyright 2022 Chris Tanaka <https://github.com/christanaka>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include QMK_KEYBOARD_H
#include "typehud.h"

// clang-format off
enum layers {
    _BASE,
    _VIA1,
    _VIA2
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = LAYOUT_all(
             KC_ESC,   KC_F1,   KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,    KC_F7,  KC_F8,  KC_F9,   KC_F10,    KC_F11,    KC_F12,   KC_PSCR,  KC_PAUS,
    KC_F13,  KC_GRV,   KC_1,    KC_2,   KC_3,   KC_4,   KC_5,   KC_6,     KC_7,   KC_8,   KC_9,    KC_0,      KC_MINS,   KC_EQL,   KC_BSPC,  KC_DEL,   KC_HOME,
    KC_F14,  KC_TAB,   KC_Q,    KC_W,   KC_E,   KC_R,           KC_T,     KC_Y,   KC_U,   KC_I,    KC_O,      KC_P,      KC_LBRC,  KC_RBRC,  KC_BSLS,  KC_END,  
    KC_F15,  KC_CAPS,  KC_A,    KC_S,   KC_D,   KC_F,           KC_G,     KC_H,   KC_J,   KC_K,    KC_L,      KC_SCLN,   KC_QUOT,  KC_ENT,             KC_PGUP,
    KC_F16,  KC_LSFT,  KC_NUHS, KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,     KC_N,   KC_M,   KC_COMM, KC_DOT,    KC_SLSH,   KC_RSFT,            KC_UP,    KC_PGDN,
    KC_F17,  KC_LCTL,  KC_LGUI, KC_LALT,     MO(_VIA1),         KC_SPC,   KC_SPC,                  MO(_VIA1), KC_RALT,   KC_RCTL,  KC_LEFT,  KC_DOWN,  KC_RGHT
  ),
    [_VIA1] = LAYOUT_all(
            QK_BOOT,KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  ),
    [_VIA2] = LAYOUT_all(
            KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  )
};
// clang-format on

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
    [_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU), ENCODER_CCW_CW(KC_MPRV, KC_MNXT) },
    [_VIA1] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) },
    [_VIA2] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) }
};
#endif

oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    oled_clear();

#ifdef TYPEHUD_MASTER
    if (is_keyboard_master()) {
#else
    if (!is_keyboard_master()) {
#endif
        typehud_init();
    }

    if (is_keyboard_left())
        return OLED_ROTATION_0;
    else
        return OLED_ROTATION_180;
}

static void render_status(void) {
    oled_set_cursor(0, 0);
    oled_write_P(PSTR("SNAP75 "), false);
    oled_write_P(PSTR("Layer "), false);
    switch (get_highest_layer(layer_state)) {
        case _VIA1:
            oled_write_P(PSTR("FN1 "), false);
            break;
        case _VIA2:
            oled_write_P(PSTR("FN2 "), false);
            break;
        default: // use BASE case as default
            oled_write_P(PSTR("Base"), false);
    }

    // Host Keyboard LED Status
    oled_set_cursor(0, 1);
    static uint8_t persistent_led_state = 0;
    uint8_t        led_usb_state        = host_keyboard_leds();

    // Only update if the LED state has changed
    // Otherwise, the OLED will not turn off if an LED is on.
    if (persistent_led_state != led_usb_state) {
        persistent_led_state = led_usb_state;

        oled_write_ln_P(PSTR("            "), false);

        if (IS_LED_ON(led_usb_state, USB_LED_CAPS_LOCK)) {
            oled_set_cursor(0, 1);
            oled_write_P(PSTR("CAPS"), false);
        }

        if (IS_LED_ON(led_usb_state, USB_LED_NUM_LOCK)) {
            oled_set_cursor(5, 1);
            oled_write_P(PSTR("NUM"), true);
        }

        if (IS_LED_ON(led_usb_state, USB_LED_SCROLL_LOCK)) {
            oled_set_cursor(9, 1);
            oled_write_P(PSTR("SCR"), false);
        }
    }

    // WPM and max WPM
    oled_set_cursor(0, 2);
    oled_write_P(PSTR("WPM "), false);
    uint8_t current_wpm = get_current_wpm();
    oled_write(get_u8_str(current_wpm, '0'), true);

    oled_set_cursor(8, 2);
    oled_write_P(PSTR("MAX "), false);
    static uint8_t max_wpm;
    max_wpm = MAX(max_wpm, current_wpm);
    oled_write(get_u8_str(max_wpm, '0'), true);
}

bool oled_task_user(void) {
#ifdef TYPEHUD_MASTER
    if (is_keyboard_master()) {
#else
    if (!is_keyboard_master()) {
#endif
        typehud_render();
    } else {
        render_status();
    }

    return true;
}

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    typehud_process_record(record);
    return true;
}

bool should_process_keypress(void) {
    return true;
}

A keyboards/nullbitsco/snap/keymaps/typehud/readme.md => keyboards/nullbitsco/snap/keymaps/typehud/readme.md +51 -0
@@ 0,0 1,51 @@
# Typehud Keymap

VIA compatible keymap that displays a live wpm HUD on your OLED.

<https://nullbits.co/static/file/snap-typehud.webp>

## Configuration

Configuration options (other than the keymap itself) can be found in `typehud/config.h`.

### Graph Type

By default the graph is filled. For a non-filled graph remove or comment out the following line:

```c
#define TYPEHUD_FILLGRAPH
```

### Keyboard Matrix Orientation

To change the keyboard matrix orientation add one of the following:

- `TYPEHUD_MATRIX_ROTATE_90`
- `TYPEHUD_MATRIX_ROTATE_180`
- `TYPEHUD_MATRIX_ROTATE_270`

### Keyboard Matrix Key Overrides

If the number of physical keys doesn't match the keyboard matrix rows/columns you can override it:

```c
#define TYPEHUD_MATRIX_ROWS 6
#define TYPEHUD_MATRIX_COLS 16
```

In addition if the position of the physical keys doesn't match the matrix you can override it. Negative numbers will shift the keys left/up and positive numbers will shift the keys right/down:

```c
#define TYPEHUD_MATRIX_ROW_SHIFT -1
#define TYPEHUD_MATRIX_COL_SHIFT -2
```

### Split Keyboard Side

For split keyboards, the keymap assumes it will be rendered to the slave side.

To render to master instead, add the following configuration line:

```c
#define TYPEHUD_MASTER
```

A keyboards/nullbitsco/snap/keymaps/typehud/rules.mk => keyboards/nullbitsco/snap/keymaps/typehud/rules.mk +7 -0
@@ 0,0 1,7 @@
OLED_ENABLE = yes
OLED_DRIVER = SSD1306
WPM_ENABLE = yes
VIA_ENABLE = yes
ENCODER_MAP_ENABLE = yes

SRC += typehud.c

A keyboards/nullbitsco/snap/keymaps/typehud/typehud.c => keyboards/nullbitsco/snap/keymaps/typehud/typehud.c +349 -0
@@ 0,0 1,349 @@
/* Copyright 2023 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "typehud.h"

static bool     is_initialized;
static uint16_t timer;
static int8_t   bar_height;
static uint8_t  wpm_arr[_GRAPH_WIDTH];
static uint8_t  point_arr[_GRAPH_WIDTH];


static void 
    render_graph(uint8_t wpm),
    render_caret(void),
    render_axis(void),
    render_bar(void),
    render_init(void);

/*
 * Renders the wpm counter.
 */
static void render_wpm(uint8_t wpm) {
    oled_set_cursor(0, 0);
    oled_write("WPM", false);
    oled_set_cursor(0, 1);
    oled_write(get_u8_str(wpm, '0'), false);
}

/*
 * Renders the keyboard matrix.
 */
static void render_matrix(keyrecord_t *record) {
    uint8_t x      = _MATRIX_X;
    uint8_t y      = _MATRIX_Y;
    uint8_t width  = _MATRIX_WIDTH;
    uint8_t height = _MATRIX_HEIGHT;
#ifdef SPLIT_KEYBOARD
    uint8_t rows = _NML_MATRIX_ROWS;
    uint8_t cols = _NML_MATRIX_COLS;
#endif

    // On initial render draw the matrix outline
    if (!is_initialized) {
        for (uint8_t i = 1; i <= width - 2; i++) {
            oled_write_pixel(x + i, y, true);
            oled_write_pixel(x + i, y + height - 1, true);
        }
        for (uint8_t j = 1; j <= height - 2; j++) {
            oled_write_pixel(x, y + j, true);
            oled_write_pixel(x + width - 1, y + j, true);
        }
        return;
    }

    // Determine position based on matrix rotation
    // For split keyboards the keys on the right half get appended as additional rows and
    // have their columns reset at 0
#ifdef SPLIT_KEYBOARD
    uint8_t row = (record->event.key.row % rows);
    uint8_t col = record->event.key.col;
    if (record->event.key.row >= rows) {
        col += (cols / 2);
    }
#else
    uint8_t row = record->event.key.row;
    uint8_t col = record->event.key.col;
#endif

#ifdef TYPEHUD_MATRIX_ROW_SHIFT
    row += TYPEHUD_MATRIX_ROW_SHIFT;
#endif
#ifdef TYPEHUD_MATRIX_COL_SHIFT
    col += TYPEHUD_MATRIX_COL_SHIFT;
#endif

    // Scale position to key size
    uint8_t size = _MATRIX_SIZE;
    row *= size;
    col *= size;

    // Render key in matrix
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
#if defined(TYPEHUD_MATRIX_ROTATE_90)
            uint8_t key_x = x + width - 1 - size - row;
            uint8_t key_y = y + 1 + col;
#elif defined(TYPEHUD_MATRIX_ROTATE_180)
            uint8_t key_x = x + width - 1 - size - col;
            uint8_t key_y = y + height - 1 - size - row;
#elif defined(TYPEHUD_MATRIX_ROTATE_270)
            uint8_t key_x = x + 1 + row;
            uint8_t key_y = y + height - 1 - size - col;
#else
            uint8_t key_x = x + 1 + col;
            uint8_t key_y = y + 1 + row;
#endif
            oled_write_pixel(key_x + i, key_y + j, record->event.pressed);
        }
    }
}

/*
 * Renders the graph.
 */
static void render_graph(uint8_t wpm) {
    uint8_t x      = _GRAPH_X;
    uint8_t y      = _GRAPH_Y + _GRAPH_HEIGHT;
    uint8_t width  = _GRAPH_WIDTH;
    uint8_t height = _GRAPH_HEIGHT;

    // Handle intial graph render
    if (!is_initialized) {
        for (uint8_t i = 0; i < width; i++) {
            oled_write_pixel(x + i, y, true);
        }
        return;
    }

    uint8_t i = 0;

    // Shift all graph points except last to the left and re-render
    for (; i < width - 1; i++) {
        int8_t point_delta = point_arr[i + 1] - point_arr[i];

#ifdef TYPEHUD_FILLGRAPH
        if (point_delta < 0) {
#else
        if (point_delta != 0) {
#endif
            oled_write_pixel(x + i, y - point_arr[i], false);
        }

        wpm_arr[i]   = wpm_arr[i + 1];
        point_arr[i] = point_arr[i + 1];

        if (point_delta != 0) {
            oled_write_pixel(x + i, y - point_arr[i], true);
        }
    }

    // Clear last graph point
    if (wpm > wpm_arr[i] && point_arr[i] + 1 <= height) {
#ifndef TYPEHUD_FILLGRAPH
        oled_write_pixel(x + i, y - point_arr[i], false);
#endif
        point_arr[i] = point_arr[i] + 1;
    } else if ((wpm < wpm_arr[i] && point_arr[i] - 1 >= 0) || (wpm <= 0 && point_arr[i] > 0)) {
        oled_write_pixel(x + i, y - point_arr[i], false);
        point_arr[i] = point_arr[i] - 1;
    }

    // Render last graph point
    wpm_arr[i] = wpm;

    if (point_arr[i] != point_arr[i - 1]) {
        oled_write_pixel(x + i, y - point_arr[i], true);
    }
}

/*
 * Renders the caret.
 */
static void render_caret(void) {
    uint8_t x        = _GRAPH_X + _GRAPH_WIDTH + _GRAPH_RPAD + _CARET_WIDTH;
    uint8_t y        = 0;
    uint8_t width    = _CARET_WIDTH;
    uint8_t height   = _CARET_HEIGHT;
    uint8_t g_width  = _GRAPH_WIDTH;
    uint8_t g_height = _GRAPH_HEIGHT;

    // Handle initial caret render
    if (!is_initialized) {
        y = g_height - point_arr[g_width - 1];

        for (uint8_t i = 0; i < width; i++) {
            for (uint8_t j = i; j < height - i; j++) {
                oled_write_pixel(x - i, y - j, true);
            }
        }
        return;
    }

    // Handle caret updates and re-render
    int8_t point_delta = point_arr[g_width - 1] - point_arr[g_width - 2];
    if (point_delta > 0) {
        y = g_height - point_arr[g_width - 2];
        if (y - height + 1 > 0) {
            for (uint8_t i = 0; i < width; i++) {
                oled_write_pixel(x - i, y - i, false);
                oled_write_pixel(x - i, y - height + i, true);
            }
        }
    } else if (point_delta < 0) {
        y = g_height - point_arr[g_width - 1];
        if (y - height + 1 > 0) {
            for (uint8_t i = 0; i < width; i++) {
                oled_write_pixel(x - i, y - height + i, false);
                oled_write_pixel(x - i, y - i, true);
            }
        }
    }
}

/*
 * Renders the axis.
 */
static void render_axis(void) {
    uint8_t x             = _AXIS_X;
    uint8_t y             = _AXIS_HEIGHT;
    uint8_t width         = _AXIS_WIDTH;
    uint8_t height        = _AXIS_HEIGHT;
    uint8_t tick_width    = _AXIS_TICK_WIDTH;
    uint8_t subtick_width = _AXIS_SUBTICK_WIDTH;
    uint8_t interval      = _AXIS_INTERVAL;
    uint8_t tick_interval = _AXIS_TICK_INTERVAL;

    for (uint8_t j = 0; j <= height; j += interval) {
        uint8_t curr_tick_width = 0;

        // Determine tick width and draw extra point if at interval
        if (j % tick_interval == 0) {
            curr_tick_width = tick_width;
            oled_write_pixel(x, y - j, true);
        } else {
            curr_tick_width = subtick_width;
        }

        // Draw tick
        for (uint8_t i = 0; i < curr_tick_width; i++) {
            oled_write_pixel(x + width - i, y - j, true);
        }
    }
}

/*
 * Renders the input bar.
 */
static void render_bar(void) {
    uint8_t x      = _BAR_X;
    uint8_t width  = _BAR_WIDTH;
    uint8_t height = _BAR_HEIGHT;

    // Increment bar height
    bar_height = (bar_height + 1) % height;

    // When bar resets back to 0, clear bar pixels
    if (bar_height % height == 0) {
        for (uint8_t i = 0; i < width; i++) {
            for (uint8_t j = 0; j < height; j++) {
                oled_write_pixel(x + i, j, false);
            }
        }
    }

    // Draw new bar pixels
    for (uint8_t i = 0; i < width; i++) {
        oled_write_pixel(x + i, height - bar_height, true);
    }
}

/*
 * Renders the initial frame for all components.
 */
static void render_init(void) {
    render_graph(0);
    render_caret();
    render_matrix(NULL);
    render_axis();
}

/*
 * Initializes and resets the typehud.
 */
void typehud_init(void) {
    // Reset variables
    is_initialized = false;
    timer          = 0;
    bar_height     = -1;

    for (uint8_t i = 0; i < _GRAPH_WIDTH; i++) {
        wpm_arr[i]   = 0;
        point_arr[i] = 0;
    }

    // Draw the initial graph
    for (uint8_t i = 0; i < _GRAPH_WIDTH; i++) {
        oled_write_pixel(_GRAPH_X + i, _GRAPH_HEIGHT, true);
    }
}

/*
 * Renders the typehud.
 */
void typehud_render(void) {
    uint8_t wpm = get_current_wpm();

    // Run initial rendering once
    if (!is_initialized) {
        render_init();
        is_initialized = true;
    }

    // Render wpm
    render_wpm(wpm);

    // Render next graph and caret frame when timer reaches refresh rate
    if (timer_elapsed(timer) > _GRAPH_REFRESH) {
        render_graph(wpm);
        render_caret();
        timer = timer_read();
    }
}

/*
 * Handles keypresses for the typehud.
 */
void typehud_process_record(keyrecord_t *record) {
    // For split keyboards, only draw on correct side
#ifdef SPLIT_KEYBOARD
#    ifdef TYPEHUD_MASTER
    if (!is_keyboard_master()) {
#    else
    if (is_keyboard_master()) {
#    endif
        return;
    }
#endif
    // Render/update matrix
    render_matrix(record);

    // Render/update input bar on keypress
    if (record->event.pressed) {
        render_bar();
    }
}

A keyboards/nullbitsco/snap/keymaps/typehud/typehud.h => keyboards/nullbitsco/snap/keymaps/typehud/typehud.h +87 -0
@@ 0,0 1,87 @@
/* Copyright 2022 Chris Tanaka <https://github.com/christanaka>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include QMK_KEYBOARD_H

// clang-format off
#define _OLED_WIDTH         (OLED_DISPLAY_WIDTH - 1)
#define _OLED_HEIGHT        (OLED_DISPLAY_HEIGHT - 1)

#ifdef SPLIT_KEYBOARD
#define _PHYSICAL_PARTS 2
#else
#define _PHYSICAL_PARTS 1
#endif

#ifdef TYPEHUD_MATRIX_ROWS
#define _NML_MATRIX_ROWS TYPEHUD_MATRIX_ROWS
#else
#    ifdef SPLIT_KEYBOARD
#define _NML_MATRIX_ROWS (MATRIX_ROWS / 2)
#    else
#define _NML_MATRIX_ROWS MATRIX_ROWS
#    endif
#endif

#ifdef TYPEHUD_MATRIX_COLS
#define _NML_MATRIX_COLS TYPEHUD_MATRIX_COLS
#else
#define _NML_MATRIX_COLS (MATRIX_COLS * _PHYSICAL_PARTS)
#endif

#define _MATRIX_SIZE        2
#if defined(TYPEHUD_MATRIX_ROTATE_90) || defined(TYPEHUD_MATRIX_ROTATE_270)
#define _MATRIX_WIDTH       (_NML_MATRIX_ROWS * _MATRIX_SIZE + 2)
#define _MATRIX_HEIGHT      (_NML_MATRIX_COLS * _MATRIX_SIZE + 2)
#else
#define _MATRIX_WIDTH       (_NML_MATRIX_COLS * _MATRIX_SIZE + 2)
#define _MATRIX_HEIGHT      (_NML_MATRIX_ROWS * _MATRIX_SIZE + 2)
#endif
#define _MATRIX_X           0
#define _MATRIX_Y           (_OLED_HEIGHT - _MATRIX_HEIGHT + 1)
#define _MATRIX_RPAD        2
#define _MATRIX_PAD_WIDTH   (_MATRIX_WIDTH + _MATRIX_RPAD)

#define _BAR_WIDTH          3
#define _BAR_HEIGHT         _OLED_HEIGHT
#define _BAR_X              (_OLED_WIDTH - _BAR_WIDTH)

#define _AXIS_WIDTH         5
#define _AXIS_HEIGHT        _OLED_HEIGHT
#define _AXIS_TICK_WIDTH    3
#define _AXIS_SUBTICK_WIDTH 2
#define _AXIS_INTERVAL      3
#define _AXIS_TICK_INTERVAL 15
#define _AXIS_RPAD          2
#define _AXIS_PAD_WIDTH     (_AXIS_WIDTH + _AXIS_RPAD)
#define _AXIS_X             (_OLED_WIDTH - _BAR_WIDTH - _AXIS_PAD_WIDTH)

#define _CARET_WIDTH        3
#define _CARET_HEIGHT       5

#define _GRAPH_RPAD         2
#define _GRAPH_MAX_WIDTH    (_OLED_WIDTH - _BAR_WIDTH - _AXIS_PAD_WIDTH - _CARET_WIDTH - _GRAPH_RPAD - _MATRIX_PAD_WIDTH)
#define _GRAPH_WIDTH        (_GRAPH_MAX_WIDTH - 4)
#define _GRAPH_HEIGHT       31
#define _GRAPH_REFRESH      300
#define _GRAPH_X            (_MATRIX_WIDTH + _MATRIX_RPAD)
#define _GRAPH_Y            0
// clang-format on

void 
    typehud_init(void),
    typehud_render(void),
    typehud_process_record(keyrecord_t *record);

A keyboards/nullbitsco/snap/keymaps/via/config.h => keyboards/nullbitsco/snap/keymaps/via/config.h +20 -0
@@ 0,0 1,20 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
// clang-format off
#pragma once

/* space savers */
#define DYNAMIC_KEYMAP_LAYER_COUNT 3

A keyboards/nullbitsco/snap/keymaps/via/keymap.c => keyboards/nullbitsco/snap/keymaps/via/keymap.c +59 -0
@@ 0,0 1,59 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include QMK_KEYBOARD_H

// clang-format off
enum layers {
    _BASE,
    _VIA1,
    _VIA2
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = LAYOUT_all(
             KC_ESC,   KC_F1,   KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,    KC_F7,  KC_F8,  KC_F9,   KC_F10,    KC_F11,    KC_F12,   KC_PSCR,  KC_PAUS,
    KC_F13,  KC_GRV,   KC_1,    KC_2,   KC_3,   KC_4,   KC_5,   KC_6,     KC_7,   KC_8,   KC_9,    KC_0,      KC_MINS,   KC_EQL,   KC_BSPC,  KC_DEL,   KC_HOME,
    KC_F14,  KC_TAB,   KC_Q,    KC_W,   KC_E,   KC_R,           KC_T,     KC_Y,   KC_U,   KC_I,    KC_O,      KC_P,      KC_LBRC,  KC_RBRC,  KC_BSLS,  KC_END,  
    KC_F15,  KC_CAPS,  KC_A,    KC_S,   KC_D,   KC_F,           KC_G,     KC_H,   KC_J,   KC_K,    KC_L,      KC_SCLN,   KC_QUOT,  KC_ENT,             KC_PGUP,
    KC_F16,  KC_LSFT,  KC_NUHS, KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,     KC_N,   KC_M,   KC_COMM, KC_DOT,    KC_SLSH,   KC_RSFT,            KC_UP,    KC_PGDN,
    KC_F17,  KC_LCTL,  KC_LGUI, KC_LALT,     MO(_VIA1),         KC_SPC,   KC_SPC,                  MO(_VIA1), KC_RALT,   KC_RCTL,  KC_LEFT,  KC_DOWN,  KC_RGHT
  ),
    [_VIA1] = LAYOUT_all(
            QK_BOOT,KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  ),
    [_VIA2] = LAYOUT_all(
            KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,    KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,  KC_NO,
    KC_NO,  KC_NO,  KC_NO,  KC_NO,          KC_NO,          KC_NO,    KC_NO,                  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO,  KC_NO
  )
};
// clang-format on

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
    [_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU), ENCODER_CCW_CW(KC_MPRV, KC_MNXT) },
    [_VIA1] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) },
    [_VIA2] = { ENCODER_CCW_CW(KC_NO, KC_NO),     ENCODER_CCW_CW(KC_NO, KC_NO) }
};
#endif

A keyboards/nullbitsco/snap/keymaps/via/rules.mk => keyboards/nullbitsco/snap/keymaps/via/rules.mk +2 -0
@@ 0,0 1,2 @@
VIA_ENABLE = yes
ENCODER_MAP_ENABLE = yes

A keyboards/nullbitsco/snap/matrix.c => keyboards/nullbitsco/snap/matrix.c +126 -0
@@ 0,0 1,126 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "util.h"
#include "matrix.h"
#include "split_util.h"
#include "quantum.h"

#define VIRT_COLS_PER_HAND 1
#define PHYS_COLS_PER_HAND (MATRIX_COLS - VIRT_COLS_PER_HAND)
#define ROWS_PER_HAND (MATRIX_ROWS / 2)
#define COL_SHIFTER ((uint32_t)1)
#define EXT_PIN_ROW 2
#define EXT_PIN_COL 8

// Row & column pins
static uint8_t  row_pins_left[MATRIX_ROWS]      = MATRIX_ROW_PINS;
static uint8_t  col_pins_left[MATRIX_MUX_COLS]  = MATRIX_COL_MUX_PINS;
static uint8_t  row_pins_right[MATRIX_ROWS]     = MATRIX_ROW_PINS_RIGHT;
static uint8_t  col_pins_right[MATRIX_MUX_COLS] = MATRIX_COL_MUX_PINS_RIGHT;
static uint8_t* row_pins                        = row_pins_left;
static uint8_t* col_pins                        = col_pins_left;

// Internal functions
static void init_pins(void) {
    // Set cols to outputs, low
    for (uint8_t pin = 0; pin < MATRIX_MUX_COLS; pin++) {
        setPinOutput(col_pins[pin]);
    }

    // Unselect cols
    for (uint8_t bit = 0; bit < MATRIX_MUX_COLS; bit++) {
        writePinLow(col_pins[bit]);
    }

    // Set rows to input, pullup
    for (uint8_t pin = 0; pin < ROWS_PER_HAND; pin++) {
        setPinInputHigh(row_pins[pin]);
    }

    // Set extended pin (only on right side)
    if (!isLeftHand) {
        // Set extended pin to input, pullup
        setPinInputHigh(MATRIX_EXT_PIN_RIGHT);
    }
}

static void select_col(uint8_t col) {
    // Drive demux with correct column address
    for (uint8_t bit = 0; bit < MATRIX_MUX_COLS; bit++) {
        uint8_t state = (col & (0b1 << bit)) >> bit;
        writePin(col_pins[bit], !state);
    }
}

static void read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
    select_col(current_col % PHYS_COLS_PER_HAND);
    wait_us(5);

    // Read each row sequentially
    for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
        if (readPin(row_pins[row_index]) == 0) {
            current_matrix[row_index] |= (COL_SHIFTER << current_col);
        } else {
            current_matrix[row_index] &= ~(COL_SHIFTER << current_col);
        }
    }
}

static void read_ext_pin(matrix_row_t current_matrix[]) {
    // Read the state of the extended matrix pin
    if (!isLeftHand) {
        if (readPin(MATRIX_EXT_PIN_RIGHT) == 0) {
            current_matrix[EXT_PIN_ROW] |= (COL_SHIFTER << EXT_PIN_COL);
        } else {
            current_matrix[EXT_PIN_ROW] &= ~(COL_SHIFTER << EXT_PIN_COL);
        }
    }
}

void matrix_init_custom(void) {
    if (!isLeftHand) {
        row_pins = row_pins_right;
        col_pins = col_pins_right;
    }

    init_pins();
}

bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    matrix_row_t last_matrix[MATRIX_ROWS];
    memcpy(last_matrix, current_matrix, sizeof(last_matrix));

    #ifdef DEBUG_SLOW_MATRIX
    // Slow for debugging
    wait_ms(1000);
    #endif

    // Set col, read rows
    for (uint8_t current_col = 0; current_col < PHYS_COLS_PER_HAND; current_col++) {
        read_rows_on_col(current_matrix, current_col);
    }

    // Read extended pin and store in matrix
    read_ext_pin(current_matrix);

    // Check if the matrix changed
    bool changed = memcmp(last_matrix, current_matrix, sizeof(last_matrix)) != 0;

    return changed;
}

A keyboards/nullbitsco/snap/readme.md => keyboards/nullbitsco/snap/readme.md +26 -0
@@ 0,0 1,26 @@
# SNAP

![SNAP](https://nullbits.co/static/img/snap10.jpg)

A unique, tweakable split 75% keyboard kit built by nullbits. [More info at nullbits.co](https://nullbits.co/snap/)

* Keyboard Maintainer: [Jay Greco](https://github.com/jaygreco)
* Hardware Supported: SNAP Rev1, Pro Micro comaptible MCUs.
* Hardware Availability: [nullbits.co](https://nullbits.co/)

Note: If you are seeing issues with MacOS and keyboard hangs after sleep, make sure `NO_USB_STARTUP_CHECK = yes` is set in your rules.mk.

Adds experimental "Remote Keyboard" functionality, which forwards keystrokes from an external macropad, keyboard, or numpad over UART/TRRS, removing the need for an additional USB connection. 

Make example for this keyboard (after setting up your build environment):

    make nullbitsco/snap:default

## Bootloader

Enter the bootloader in 2 ways:

* **Physical reset button**: Briefly press the reset button located near the MCU on the the PCB
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

A keyboards/nullbitsco/snap/rules.mk => keyboards/nullbitsco/snap/rules.mk +23 -0
@@ 0,0 1,23 @@
# Build Options
#   change yes to no to disable
#
BOOTMAGIC_ENABLE = no      # Enable Bootmagic Lite
MOUSEKEY_ENABLE = no       # Mouse keys
EXTRAKEY_ENABLE = yes      # Audio control and System control
CONSOLE_ENABLE = no        # Console for debug
COMMAND_ENABLE = no        # Commands for debug and configuration
NKRO_ENABLE = no           # Enable N-Key Rollover
BACKLIGHT_ENABLE = no      # Enable keyboard backlight functionality
AUDIO_ENABLE = no          # Audio output
SPLIT_KEYBOARD = yes       # Split common
LTO_ENABLE = yes           # Use Link Time Optimization
ENCODER_ENABLE = yes       # Enables the use of one or more encoders
SPACE_CADET_ENABLE = no    # Enables the use of Space Cadet
RGBLIGHT_ENABLE = yes      # Enable keyboard RGB underglow
CUSTOM_MATRIX = lite       # Split custom matrix

# Project specific files
SRC +=  common/bitc_led.c \
        common/remote_kb.c \
        matrix.c \
        uart.c

A keyboards/nullbitsco/snap/snap.c => keyboards/nullbitsco/snap/snap.c +127 -0
@@ 0,0 1,127 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include QMK_KEYBOARD_H

// Macro variables
bool is_alt_tab_active = false;
uint16_t alt_tab_timer = 0;
bool muted = false;

void matrix_init_kb(void) {
    set_bitc_LED(LED_OFF);
    matrix_init_remote_kb();
    matrix_init_user();
}

void keyboard_post_init_kb(void) {
    #ifdef CONSOLE_ENABLE
    debug_enable = true;
    debug_matrix = true;
    #endif
    keyboard_post_init_user();
}

void matrix_scan_kb(void) {
    matrix_scan_remote_kb();
    matrix_scan_user();

    if (is_alt_tab_active) {
        if (timer_elapsed(alt_tab_timer) > 1000) {
            unregister_code(KC_LALT);
            is_alt_tab_active = false;
        }
    }
}

// Use Bit-C LED to show CAPS LOCK and NUM LOCK status
void led_update_ports(led_t led_state) {
    set_bitc_LED(led_state.caps_lock ? LED_DIM : LED_OFF);
}

bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
    // If console is enabled, it will print the matrix position and status of each key pressed
    #ifdef CONSOLE_ENABLE
    dprintf("kc: 0x%04X, col: %u, row: %u, pressed: %b, time: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed, record->event.time);
    #endif

    process_record_remote_kb(keycode, record);
    if (!process_record_user(keycode, record)) return false;

    switch (keycode) {
        case QK_BOOT:
            if (record->event.pressed) {
                set_bitc_LED(LED_DIM);
                #ifdef RGBLIGHT_ENABLE
                rgblight_disable_noeeprom();
                #endif
                #ifdef OLED_ENABLE
                oled_off();
                #endif
                bootloader_jump();  // jump to bootloader
            }
            return false;

        case DISC_MUTE:
            if (record->event.pressed) {
                tap_code(KC_F23);
                #ifdef RGBLIGHT_ENABLE
                if (!rgblight_is_enabled()) break;

                if (muted) {
                    rgblight_enable_noeeprom();
                } else {
                    rgblight_timer_disable();
                    uint8_t val = rgblight_get_val();
                    rgblight_sethsv_range(255, 255, val, 1, 5);
                }
                #endif
                muted = !muted;
            }
            break;

        case SUPER_ALT_TAB:
            if (record->event.pressed) {
                if (!is_alt_tab_active) {
                    is_alt_tab_active = true;
                    register_code(KC_LALT);
                }
                alt_tab_timer = timer_read();
                register_code(KC_TAB);
            } else {
                unregister_code(KC_TAB);
            }
            break;

        default:
            break;
    }

    return true;
}

#ifdef ENCODER_ENABLE
bool encoder_update_kb(uint8_t index, bool clockwise) {
    if (!encoder_update_user(index, clockwise)) { return false; }
    if (index == 0) {
        if (clockwise) {
            tap_code_delay(KC_VOLU, 10);
        } else {
            tap_code_delay(KC_VOLD, 10);
        }
    }
    return true;
}
#endif

A keyboards/nullbitsco/snap/snap.h => keyboards/nullbitsco/snap/snap.h +106 -0
@@ 0,0 1,106 @@
/* Copyright 2021 Jay Greco
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#pragma once

#define _____ KC_NO

#include "quantum.h"
#include "common/remote_kb.h"
#include "common/bitc_led.h"

#ifdef VIA_ENABLE
enum custom_keycodes {
    DISC_MUTE = QK_USER_0,
    SUPER_ALT_TAB
};
#else
enum custom_keycodes {
    DISC_MUTE = SAFE_RANGE,
    SUPER_ALT_TAB
};
#endif

// clang-format off
#define LAYOUT_all( \
       R1C7L, R1C6L, R1C5L, R1C4L, R1C3L, R1C2L, R1C1L,    R1C8R, R1C7R, R1C6R, R1C5R, R1C4R, R1C3R, R1C2R, R1C1R,        \
R2C8L, R2C7L, R2C6L, R2C5L, R2C4L, R2C3L, R2C2L, R2C1L,    R2C8R, R2C7R, R2C6R, R2C5R, R2C4R, R2C3R, R2C2R, R2C1R, R3CXR, \
R3C8L, R3C7L, R3C6L, R3C5L, R3C4L, R3C3L,        R3C1L,    R3C8R, R3C7R, R3C6R, R3C5R, R3C4R, R3C3R, R3C2R, R4C1R, R3C1R, \
R4C8L, R4C7L, R4C6L, R4C5L, R4C4L, R4C3L,        R4C1L,    R4C8R, R4C7R, R4C6R, R4C5R, R4C4R, R4C3R, R4C2R,        R5C1R, \
R5C8L, R5C7L, R5C6L, R5C5L, R5C4L, R5C3L, R5C2L, R5C1L,    R5C8R, R5C7R, R5C6R, R5C5R, R5C4R, R5C3R,        R5C2R, R6C1R, \
R6C8L, R6C7L, R6C6L, R6C5L,        R6C3L,        R6C1L,    R6C8R,               R6C7R, R6C6R, R6C5R, R6C4R, R6C3R, R6C2R  \
) { \
   /* Left */ \
   {_____, R1C7L, R1C6L, R1C5L, R1C4L, R1C3L, R1C2L, R1C1L, _____}, \
   {R2C8L, R2C7L, R2C6L, R2C5L, R2C4L, R2C3L, R2C2L, R2C1L, _____}, \
   {R3C8L, R3C7L, R3C6L, R3C5L, R3C4L, R3C3L, _____, R3C1L, _____}, \
   {R4C8L, R4C7L, R4C6L, R4C5L, R4C4L, R4C3L, _____, R4C1L, _____}, \
   {R5C8L, R5C7L, R5C6L, R5C5L, R5C4L, R5C3L, R5C2L, R5C1L, _____}, \
   {R6C8L, R6C7L, R6C6L, R6C5L, _____, R6C3L, _____, R6C1L, _____}, \
   /* Right */ \
   {R1C8R, R1C7R, R1C6R, R1C5R, R1C4R, R1C3R, R1C2R, R1C1R, _____}, \
   {R2C8R, R2C7R, R2C6R, R2C5R, R2C4R, R2C3R, R2C2R, R2C1R, _____}, \
   {R3C8R, R3C7R, R3C6R, R3C5R, R3C4R, R3C3R, R3C2R, R3C1R, R3CXR}, \
   {R4C8R, R4C7R, R4C6R, R4C5R, R4C4R, R4C3R, R4C2R, R4C1R, _____}, \
   {R5C8R, R5C7R, R5C6R, R5C5R, R5C4R, R5C3R, R5C2R, R5C1R, _____}, \
   {R6C8R, R6C7R, R6C6R, R6C5R, R6C4R, R6C3R, R6C2R, R6C1R, _____}  \
}

#define LAYOUT_iso( \
       R1C7L, R1C6L, R1C5L, R1C4L, R1C3L, R1C2L, R1C1L,    R1C8R, R1C7R, R1C6R, R1C5R, R1C4R, R1C3R, R1C2R, R1C1R,        \
R2C8L, R2C7L, R2C6L, R2C5L, R2C4L, R2C3L, R2C2L, R2C1L,    R2C8R, R2C7R, R2C6R, R2C5R, R2C4R, R2C3R,     R2C2R,    R3CXR, \
R3C8L, R3C7L, R3C6L, R3C5L, R3C4L, R3C3L,        R3C1L,    R3C8R, R3C7R, R3C6R, R3C5R, R3C4R, R3C3R, R3C2R, R4C1R, R3C1R, \
R4C8L, R4C7L, R4C6L, R4C5L, R4C4L, R4C3L,        R4C1L,    R4C8R, R4C7R, R4C6R, R4C5R, R4C4R, R4C3R, R4C2R,        R5C1R, \
R5C8L, R5C7L, R5C6L, R5C5L, R5C4L, R5C3L, R5C2L, R5C1L,    R5C8R, R5C7R, R5C6R, R5C5R, R5C4R, R5C3R,        R5C2R, R6C1R, \
R6C8L, R6C7L, R6C6L, R6C5L,        R6C3L,        R6C1L,    R6C8R,               R6C7R, R6C6R, R6C5R, R6C4R, R6C3R, R6C2R  \
) { /* Left */ \
   {_____, R1C7L, R1C6L, R1C5L, R1C4L, R1C3L, R1C2L, R1C1L, _____}, \
   {R2C8L, R2C7L, R2C6L, R2C5L, R2C4L, R2C3L, R2C2L, R2C1L, _____}, \
   {R3C8L, R3C7L, R3C6L, R3C5L, R3C4L, R3C3L, _____, R3C1L, _____}, \
   {R4C8L, R4C7L, R4C6L, R4C5L, R4C4L, R4C3L, _____, R4C1L, _____}, \
   {R5C8L, R5C7L, R5C6L, R5C5L, R5C4L, R5C3L, R5C2L, R5C1L ,_____}, \
   {R6C8L, R6C7L, R6C6L, R6C5L, _____, R6C3L, _____, R6C1L, _____}, \
   /* Right */ \
   {R1C8R, R1C7R, R1C6R, R1C5R, R1C4R, R1C3R, R1C2R, R1C1R, _____}, \
   {R2C8R, R2C7R, R2C6R, R2C5R, R2C4R, R2C3R, R2C2R, _____, _____}, \
   {R3C8R, R3C7R, R3C6R, R3C5R, R3C4R, R3C3R, R3C2R, R3C1R, R3CXR}, \
   {R4C8R, R4C7R, R4C6R, R4C5R, R4C4R, R4C3R, R4C2R, R4C1R, _____}, \
   {R5C8R, R5C7R, R5C6R, R5C5R, R5C4R, R5C3R, R5C2R, R5C1R, _____}, \
   {R6C8R, R6C7R, R6C6R, R6C5R, R6C4R, R6C3R, R6C2R, R6C1R, _____}  \
}

#define LAYOUT_ansi( \
       R1C7L, R1C6L, R1C5L, R1C4L, R1C3L, R1C2L, R1C1L,    R1C8R, R1C7R, R1C6R, R1C5R, R1C4R, R1C3R, R1C2R, R1C1R,        \
R2C8L, R2C7L, R2C6L, R2C5L, R2C4L, R2C3L, R2C2L, R2C1L,    R2C8R, R2C7R, R2C6R, R2C5R, R2C4R, R2C3R,     R2C2R,    R3CXR, \
R3C8L, R3C7L, R3C6L, R3C5L, R3C4L, R3C3L,        R3C1L,    R3C8R, R3C7R, R3C6R, R3C5R, R3C4R, R3C3R, R3C2R, R4C1R, R3C1R, \
R4C8L, R4C7L, R4C6L, R4C5L, R4C4L, R4C3L,        R4C1L,    R4C8R, R4C7R, R4C6R, R4C5R, R4C4R, R4C3R, R4C2R,        R5C1R, \
R5C8L,     R5C7L,    R5C5L, R5C4L, R5C3L, R5C2L, R5C1L,    R5C8R, R5C7R, R5C6R, R5C5R, R5C4R, R5C3R,        R5C2R, R6C1R, \
R6C8L, R6C7L, R6C6L, R6C5L,        R6C3L,        R6C1L,    R6C8R,               R6C7R, R6C6R, R6C5R, R6C4R, R6C3R, R6C2R  \
) { /* Left */ \
   {_____, R1C7L, R1C6L, R1C5L, R1C4L, R1C3L, R1C2L, R1C1L, _____}, \
   {R2C8L, R2C7L, R2C6L, R2C5L, R2C4L, R2C3L, R2C2L, R2C1L, _____}, \
   {R3C8L, R3C7L, R3C6L, R3C5L, R3C4L, R3C3L, _____, R3C1L, _____}, \
   {R4C8L, R4C7L, R4C6L, R4C5L, R4C4L, R4C3L, _____, R4C1L, _____}, \
   {R5C8L, R5C7L, _____, R5C5L, R5C4L, R5C3L, R5C2L, R5C1L, _____}, \
   {R6C8L, R6C7L, R6C6L, R6C5L, _____, R6C3L, _____, R6C1L, _____}, \
   /* Right */ \
   {R1C8R, R1C7R, R1C6R, R1C5R, R1C4R, R1C3R, R1C2R, R1C1R, _____}, \
   {R2C8R, R2C7R, R2C6R, R2C5R, R2C4R, R2C3R, R2C2R, _____, _____}, \
   {R3C8R, R3C7R, R3C6R, R3C5R, R3C4R, R3C3R, R3C2R, R3C1R, R3CXR}, \
   {R4C8R, R4C7R, R4C6R, R4C5R, R4C4R, R4C3R, R4C2R, R4C1R, _____}, \
   {R5C8R, R5C7R, R5C6R, R5C5R, R5C4R, R5C3R, R5C2R, R5C1R, _____}, \
   {R6C8R, R6C7R, R6C6R, R6C5R, R6C4R, R6C3R, R6C2R, R6C1R, _____}  \
}
// clang-format on

A keyboards/rkg68/info.json => keyboards/rkg68/info.json +105 -0
@@ 0,0 1,105 @@
{
	"manufacturer": "Royal Kludge",
	"keyboard_name": "rkg68",
	"maintainer": "Thomaz-Peres",
	"bootloader": "atmel-dfu",
	"processor": "atmega32u4",
	"diode_direction": "COL2ROW",
	"features": {
		"bootmagic": true,
		"extrakey": true,
		"mousekey": true
	},
	"matrix_pins": {
		"cols": [ "F0", "F1", "E6", "C7", "C6", "B6", "D4", "B1", "B7", "B5", "B4", "D7", "D6", "B3", "F4" ],
		"rows": [ "D0", "D1", "D2", "D3", "D5" ]
	},
	"rgblight": {
		"animations": {
			"knight": true,
			"rainbow_swirl": true
		},
		"led_count": 4,
		"pin": "B3"
	},
	"url": "http://en.rkgaming.com/",
	"usb": {
		"device_version": "1.0.0",
		"pid": "0x0049",
		"vid": "0x0049"
	},
	"layouts": {
		"LAYOUT": {
			"layout": [
				{"matrix": [0, 0], "x": 0, "y": 0},
				{"matrix": [0, 1], "x": 1, "y": 0},
				{"matrix": [0, 2], "x": 2, "y": 0},
				{"matrix": [0, 3], "x": 3, "y": 0},
				{"matrix": [0, 4], "x": 4, "y": 0},
				{"matrix": [0, 5], "x": 5, "y": 0},
				{"matrix": [0, 6], "x": 6, "y": 0},
				{"matrix": [0, 7], "x": 7, "y": 0},
				{"matrix": [0, 8], "x": 8, "y": 0},
				{"matrix": [0, 9], "x": 9, "y": 0},
				{"matrix": [0, 10], "x": 10, "y": 0},
				{"matrix": [0, 11], "x": 11, "y": 0},
				{"matrix": [0, 12], "x": 12, "y": 0},
				{"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
				{"matrix": [0, 14], "x": 15, "y": 0},
				{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
				{"matrix": [1, 1], "x": 1.5, "y": 1},
				{"matrix": [1, 2], "x": 2.5, "y": 1},
				{"matrix": [1, 3], "x": 3.5, "y": 1},
				{"matrix": [1, 4], "x": 4.5, "y": 1},
				{"matrix": [1, 5], "x": 5.5, "y": 1},
				{"matrix": [1, 6], "x": 6.5, "y": 1},
				{"matrix": [1, 7], "x": 7.5, "y": 1},
				{"matrix": [1, 8], "x": 8.5, "y": 1},
				{"matrix": [1, 9], "x": 9.5, "y": 1},
				{"matrix": [1, 10], "x": 10.5, "y": 1},
				{"matrix": [1, 11], "x": 11.5, "y": 1},
				{"matrix": [1, 12], "x": 12.5, "y": 1},
				{"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
				{"matrix": [1, 14], "x": 15, "y": 1},
				{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
				{"matrix": [2, 1], "x": 1.75, "y": 2},
				{"matrix": [2, 2], "x": 2.75, "y": 2},
				{"matrix": [2, 3], "x": 3.75, "y": 2},
				{"matrix": [2, 4], "x": 4.75, "y": 2},
				{"matrix": [2, 5], "x": 5.75, "y": 2},
				{"matrix": [2, 6], "x": 6.75, "y": 2},
				{"matrix": [2, 7], "x": 7.75, "y": 2},
				{"matrix": [2, 8], "x": 8.75, "y": 2},
				{"matrix": [2, 9], "x": 9.75, "y": 2},
				{"matrix": [2, 10], "x": 10.75, "y": 2},
				{"matrix": [2, 11], "x": 11.75, "y": 2},
				{"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
				{"matrix": [2, 14], "x": 15, "y": 2},
				{"matrix": [3, 1], "x": 0, "y": 3, "w": 2.25},
				{"matrix": [3, 2], "x": 2.25, "y": 3},
				{"matrix": [3, 3], "x": 3.25, "y": 3},
				{"matrix": [3, 4], "x": 4.25, "y": 3},
				{"matrix": [3, 5], "x": 5.25, "y": 3},
				{"matrix": [3, 6], "x": 6.25, "y": 3},
				{"matrix": [3, 7], "x": 7.25, "y": 3},
				{"matrix": [3, 8], "x": 8.25, "y": 3},
				{"matrix": [3, 9], "x": 9.25, "y": 3},
				{"matrix": [3, 10], "x": 10.25, "y": 3},
				{"matrix": [3, 11], "x": 11.25, "y": 3},
				{"matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
				{"matrix": [3, 13], "x": 14, "y": 3},
				{"matrix": [3, 14], "x": 15, "y": 3},
				{"matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
				{"matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
				{"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
				{"matrix": [4, 6], "x": 3.75, "y": 4, "w": 6.25},
				{"matrix": [4, 9], "x": 10, "y": 4},
				{"matrix": [4, 10], "x": 11, "y": 4},
				{"matrix": [4, 11], "x": 12, "y": 4},
				{"matrix": [4, 12], "x": 13, "y": 4},
				{"matrix": [4, 13], "x": 14, "y": 4},
				{"matrix": [4, 14], "x": 15, "y": 4}
			]
		}
	}
}
\ No newline at end of file

A keyboards/rkg68/keymaps/default/keymap.c => keyboards/rkg68/keymaps/default/keymap.c +34 -0
@@ 0,0 1,34 @@
/* Copyright 2022 DeskDaily
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include QMK_KEYBOARD_H

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [0] = LAYOUT(
        KC_ESC,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_MINS, KC_EQL,  KC_BSPC, KC_GRV,
        KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL,
        KC_CAPS, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT,          KC_ENT,  KC_PGUP,
        KC_LSFT,          KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_RSFT, KC_UP,   KC_PGDN,
        KC_LCTL, KC_LGUI, KC_LALT,                            KC_SPC,                    KC_RALT, MO(1),   KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
    ),
    [1] = LAYOUT(
        KC_TRNS, KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  KC_TRNS, KC_PSCR,
        KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME, KC_END,  RGB_MOD, KC_INS,
        KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS,  KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,          KC_TRNS, KC_BRK,
        KC_TRNS,          KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RGB_VAI, KC_SCRL,
        QK_BOOT,   KC_TRNS, KC_TRNS,                            KC_TRNS,                   KC_TRNS, KC_TRNS, KC_TRNS, RGB_SPI, RGB_VAD, RGB_SPD
    )
};
\ No newline at end of file

A keyboards/rkg68/keymaps/via/keymap.c => keyboards/rkg68/keymaps/via/keymap.c +34 -0
@@ 0,0 1,34 @@
/* Copyright 2022 DeskDaily
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include QMK_KEYBOARD_H

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [0] = LAYOUT(
        KC_ESC,  KC_1,    KC_2,    KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,    KC_MINS, KC_EQL,  KC_BSPC, KC_GRV,
        KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL,
        KC_CAPS, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT,          KC_ENT,  KC_PGUP,
        KC_LSFT,          KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_RSFT, KC_UP,   KC_PGDN,
        KC_LCTL, KC_LGUI, KC_LALT,                            KC_SPC,                    KC_RALT, MO(1),   KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
    ),
    [1] = LAYOUT(
        KC_TRNS, KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  KC_TRNS, KC_PSCR,
        KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME, KC_END,  RGB_MOD, KC_INS,
        KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS,  KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,          KC_TRNS, KC_BRK,
        KC_TRNS,          KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RGB_VAI, KC_SCRL,
        QK_BOOT,   KC_TRNS, KC_TRNS,                            KC_TRNS,                   KC_TRNS, KC_TRNS, KC_TRNS, RGB_SPI, RGB_VAD, RGB_SPD
    )
};
\ No newline at end of file

A keyboards/rkg68/keymaps/via/rules.mk => keyboards/rkg68/keymaps/via/rules.mk +1 -0
@@ 0,0 1,1 @@
VIA_ENABLE = yes
\ No newline at end of file

A keyboards/rkg68/readme.md => keyboards/rkg68/readme.md +31 -0
@@ 0,0 1,31 @@
# RK G68

![Keyboard picture](https://imgur.com/UnOJPZrh.jpg)

* Keyboard Maintainer: [Royal Kludge](https://rkgamingstore.com/)
* Hardware Supported: Royal Kludge RK G68
* Hardware Availability: [RKG 68](http://en.rkgaming.com/download/1/)

After setting up your build environment, you can compile the  default keymap by using:

    make rkg68:default

Flashing example for this keyboard:

    make rkg68:default:flash

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

## Bootloader

Enter the bootloader in 3 ways:

- **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
- **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
- **Keycode in layout**: Press the key `FN` and `Left CTRL`.

## Layouts

- ANSI layout;

![Imgur](https://i.imgur.com/l7ka1gkh.png)

A keyboards/rkg68/rules.mk => keyboards/rkg68/rules.mk +1 -0
@@ 0,0 1,1 @@
# This file intentionally left blank
\ No newline at end of file