summaryrefslogtreecommitdiffstats
path: root/keyboards/lily58/keymaps/druotoni
diff options
context:
space:
mode:
authordruotoni <89318351+druotoni@users.noreply.github.com>2022-01-13 20:00:35 +0100
committerGitHub <noreply@github.com>2022-01-13 11:00:35 -0800
commitb3c0548ed3cdb31c47d1a9e06c446c0804d6e1b6 (patch)
tree87ba1062ffd5d3c77e7ea95fe537d32c3337da94 /keyboards/lily58/keymaps/druotoni
parent8a6da095d22d66c0ba36ce8731c9d821ca4262e9 (diff)
[Keymap] Lily58 : HELL0 NAVI. Interface (#15469)
Co-authored-by: Drashna Jaelre <drashna@live.com> Co-authored-by: Joel Challis <git@zvecr.com>
Diffstat (limited to 'keyboards/lily58/keymaps/druotoni')
-rw-r--r--keyboards/lily58/keymaps/druotoni/boot.c309
-rw-r--r--keyboards/lily58/keymaps/druotoni/boot.h9
-rw-r--r--keyboards/lily58/keymaps/druotoni/burst.c252
-rw-r--r--keyboards/lily58/keymaps/druotoni/burst.h24
-rw-r--r--keyboards/lily58/keymaps/druotoni/config.h55
-rw-r--r--keyboards/lily58/keymaps/druotoni/draw_helper.c768
-rw-r--r--keyboards/lily58/keymaps/druotoni/draw_helper.h47
-rw-r--r--keyboards/lily58/keymaps/druotoni/fast_random.c17
-rw-r--r--keyboards/lily58/keymaps/druotoni/fast_random.h7
-rw-r--r--keyboards/lily58/keymaps/druotoni/gui_state.c71
-rw-r--r--keyboards/lily58/keymaps/druotoni/gui_state.h18
-rw-r--r--keyboards/lily58/keymaps/druotoni/keymap.c253
-rw-r--r--keyboards/lily58/keymaps/druotoni/layer_frame.c105
-rw-r--r--keyboards/lily58/keymaps/druotoni/layer_frame.h15
-rw-r--r--keyboards/lily58/keymaps/druotoni/navi_font.c139
-rw-r--r--keyboards/lily58/keymaps/druotoni/navi_logo.c117
-rw-r--r--keyboards/lily58/keymaps/druotoni/navi_logo.h7
-rw-r--r--keyboards/lily58/keymaps/druotoni/readme.md133
-rw-r--r--keyboards/lily58/keymaps/druotoni/ring.c494
-rw-r--r--keyboards/lily58/keymaps/druotoni/ring.h11
-rw-r--r--keyboards/lily58/keymaps/druotoni/rules.mk28
21 files changed, 2879 insertions, 0 deletions
diff --git a/keyboards/lily58/keymaps/druotoni/boot.c b/keyboards/lily58/keymaps/druotoni/boot.c
new file mode 100644
index 0000000000..ba46f8e361
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/boot.c
@@ -0,0 +1,309 @@
+// Copyright 2021 Nicolas Druoton (druotoni)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+#include "boot.h"
+#include "fast_random.h"
+#include "draw_helper.h"
+#include "gui_state.h"
+
+// boot
+#define ANIM_BOOT_FRAME_DURATION 8
+uint16_t anim_boot_timer = 0;
+uint8_t anim_boot_current_frame = 0;
+
+#define NAVI_DURATION 55
+
+// terminal stuff
+#define TERMINAL_DURATION 25
+#define TERMINAL_LINE_NUMBER 19
+#define TERMINAL_LINE_MAX 14
+
+#define LILY_DURATION 50
+
+// halt
+#define ANIM_HALT_FRAME_DURATION 55
+uint16_t anim_halt_timer = 0;
+
+void reset_boot(void) {
+ // frame zero
+ anim_boot_current_frame = 0;
+}
+
+static void draw_lily_key(uint8_t x, uint8_t y, uint8_t *key_number, unsigned long key_state, uint8_t color) {
+ uint8_t v = *key_number;
+ unsigned long mask = 1;
+ mask = mask << v;
+
+ // ligth the key according to the mask
+ if (((key_state & mask) == mask)) {
+ color = !color;
+ }
+
+ draw_rectangle_fill(x, y, 3, 3, color);
+ *key_number = v + 1;
+}
+
+static void draw_lily_key_row(uint8_t x, uint8_t y, int w, uint8_t *key_number, unsigned long key_state, uint8_t color) {
+ // row of rectangle
+ for (uint8_t i = 0; i < w; i++) {
+ draw_lily_key(x + (i * 4), y, key_number, key_state, color);
+ }
+}
+
+static void draw_lily_render(unsigned long key_state) {
+ // different orientation base on side
+#if IS_LEFT
+
+ uint8_t x = 0;
+ uint8_t y = 56;
+ uint8_t x_ref = 10 + x;
+ uint8_t y_ref = 2 + y;
+ uint8_t i_key_number = 0;
+
+ for (uint8_t i = 0; i < 4; i++) {
+ draw_lily_key_row(x_ref, y_ref + (i * 4), 4, &i_key_number, key_state, true);
+ draw_lily_key_row(x_ref - 8, y_ref + 2 + (i * 4), 2, &i_key_number, key_state, true);
+ }
+
+ draw_lily_key_row(x_ref + 2, y_ref + (4 * 4), 3, &i_key_number, key_state, true);
+
+ uint8_t x_side = x_ref + (4 * 4);
+
+ draw_lily_key(x_side, y_ref + (2 * 4) + 2, &i_key_number, key_state, true);
+ draw_lily_key(x_side, y_ref + (4 * 4), &i_key_number, key_state, true);
+
+ // screen
+ draw_rectangle(x_side, y_ref, 4, 8, true);
+
+ // frame
+ drawline_hr(x + 1, y + 2, 8, true);
+ oled_write_pixel(x + 8, y + 1, true);
+ drawline_hr(x + 8, y, 23, true);
+
+ drawline_hr(x + 1, y + 20, 10, true);
+ oled_write_pixel(x + 10, y + 21, true);
+ drawline_hr(x + 10, y + 22, 16, true);
+
+ drawline_vb(x, y + 3, 17, true);
+ drawline_vb(x + 31, y + 1, 20, true);
+ oled_write_pixel(x + 30, y + 21, true);
+ oled_write_pixel(x + 29, y + 22, true);
+ oled_write_pixel(x + 28, y + 23, true);
+ oled_write_pixel(x + 27, y + 24, true);
+ oled_write_pixel(x + 26, y + 23, true);
+#endif
+
+#if IS_RIGHT
+ uint8_t i_key_number = 0;
+
+ for (uint8_t i = 0; i < 4; i++) {
+ draw_lily_key_row(7, 58 + (i * 4), 4, &i_key_number, key_state, true);
+ draw_lily_key_row(23, 60 + (i * 4), 2, &i_key_number, key_state, true);
+ }
+
+ draw_lily_key_row(9, 74, 3, &i_key_number, key_state, true);
+
+ draw_lily_key(3, 68, &i_key_number, key_state, true);
+ draw_lily_key(3, 74, &i_key_number, key_state, true);
+
+ // screen
+ draw_rectangle(2, 58, 4, 8, true);
+
+ // frame
+ drawline_hr(23, 58, 8, true);
+ oled_write_pixel(23, 57, true);
+ drawline_hr(1, 56, 23, true);
+
+ drawline_hr(21, 76, 10, true);
+ oled_write_pixel(21, 77, true);
+ drawline_hr(6, 78, 16, true);
+
+ drawline_vb(31, 59, 17, true);
+ drawline_vb(0, 57, 20, true);
+ oled_write_pixel(1, 77, true);
+ oled_write_pixel(2, 78, true);
+ oled_write_pixel(3, 79, true);
+ oled_write_pixel(4, 80, true);
+ oled_write_pixel(5, 79, true);
+#endif
+}
+
+static void draw_lily(uint8_t f) {
+ // frame for the events
+ uint8_t tres_stroke = 10;
+ uint8_t tres_boom = 30;
+ uint8_t y_start = 56;
+
+ if (f == 0 || f == tres_stroke || f == tres_boom) {
+ // clean screen
+ oled_clear();
+ }
+
+ // simple lily58 with all the keys
+ if (f < tres_stroke) {
+ draw_lily_render(0);
+ }
+
+ // increase number of random keys pressed
+ if (f >= tres_stroke && f < tres_boom) {
+ int inter_f = interpo_pourcent(tres_stroke, tres_boom, f);
+
+ unsigned long key_state = fastrand_long();
+ for (int r = 100 - inter_f; r > 0; r = r - 10) {
+ key_state &= fastrand_long();
+ }
+ draw_lily_render(key_state);
+ }
+
+ // statir explosion
+ if (f >= tres_boom) {
+ oled_clear();
+ uint8_t density = (f - tres_boom);
+ if (density > 4) density = 4;
+ draw_static(0, y_start - 8, 32, 32, true, density);
+ }
+}
+
+static void draw_startup_navi(uint8_t f) {
+ // text
+ oled_write_cursor(0, 5, "HELL0", false);
+ oled_write_cursor(0, 7, "NAVI.", false);
+
+ // prompt
+ if ((f % 8) > 4) {
+ oled_write_cursor(0, 12, "> ", false);
+ } else {
+ oled_write_cursor(0, 12, ">_", false);
+ }
+
+ // frame threshold
+ uint8_t tres_shell = 15;
+ uint8_t tres_load = 35;
+
+ // rand text to init display
+ if (f > tres_shell) {
+ int inter_f = interpo_pourcent(tres_shell, tres_load, f);
+
+ draw_random_char(1, 12, 'i', 60 + inter_f, 0);
+ draw_random_char(2, 12, 'n', 20 + inter_f, 0);
+ draw_random_char(3, 12, 'i', inter_f, 0);
+ draw_random_char(4, 12, 't', 20 + inter_f, 0);
+ }
+
+ // loading propress bar
+ if (f > tres_load) {
+ int inter_f = interpo_pourcent(tres_load, 50, f);
+
+ // ease
+ float fv = inter_f / 100.00;
+ fv = fv * fv * fv * fv;
+ inter_f = fv * 100;
+
+ draw_rectangle(0, (15 * 8), 32, 8, 1);
+ draw_progress(0 + 3, (15 * 8) + 3, 26, 2, inter_f, 0, 1);
+ }
+}
+
+// text dispayed on terminal
+static char *boot_ref[TERMINAL_LINE_NUMBER] = {"LT:", "RT:", "M :", " ", "cnx:", "A0:", "B0:", " ", "0x40", "0x60", "0x85", "0x0F", " ", "> run", "x ", "y ", " 100%", " ", "> key"};
+
+// prompt style for char in the font
+char scan_font[5] = {'>', 1, 1, 1, 1};
+
+static char *get_terminal_line(uint8_t i) {
+ // display text
+ if (i < TERMINAL_LINE_NUMBER) {
+ return boot_ref[i];
+ }
+
+ // blank line every 3 lines
+ if (i % 3 == 0) {
+ return " ";
+ }
+
+ // display consecutive chars in the font
+ i = (i - TERMINAL_LINE_NUMBER) * 4;
+
+ scan_font[1] = i;
+ scan_font[2] = i + 1;
+ scan_font[3] = i + 2;
+ scan_font[4] = i + 3;
+
+ return scan_font;
+}
+
+static void draw_startup_terminal(uint8_t f) {
+ // ease for printing on screen
+ f = f * 2;
+ f += (f / 5);
+
+ // scroll text
+ uint8_t i_start = 0;
+ uint8_t i_nb_char = f;
+
+ if (f > TERMINAL_LINE_MAX) {
+ i_start = f - TERMINAL_LINE_MAX;
+ i_nb_char = TERMINAL_LINE_MAX;
+ }
+
+ // display lines
+ oled_clear();
+ for (uint8_t i = 0; i < i_nb_char; i++) {
+ char *s = get_terminal_line(i + i_start);
+ oled_write_cursor(0, i, s, false);
+ }
+}
+
+bool render_boot(void) {
+ // end of the boot sequence
+ if (anim_boot_current_frame >= NAVI_DURATION + TERMINAL_DURATION + LILY_DURATION) {
+ anim_boot_current_frame = 0;
+ oled_clear();
+ return true;
+ }
+
+ if (timer_elapsed(anim_boot_timer) > ANIM_BOOT_FRAME_DURATION) {
+ anim_boot_timer = timer_read();
+ if (anim_boot_current_frame < NAVI_DURATION) {
+ // 55 frames
+ draw_startup_navi(anim_boot_current_frame);
+ } else {
+ if (anim_boot_current_frame >= NAVI_DURATION && anim_boot_current_frame < NAVI_DURATION + TERMINAL_DURATION) {
+ // 25
+ draw_startup_terminal(anim_boot_current_frame - NAVI_DURATION);
+ } else {
+ if (anim_boot_current_frame >= NAVI_DURATION + TERMINAL_DURATION) {
+ // 25
+ draw_lily(anim_boot_current_frame - NAVI_DURATION - TERMINAL_DURATION);
+ }
+ }
+ }
+
+ anim_boot_current_frame++;
+ }
+ return false;
+}
+
+void render_halt(void) {
+ if (timer_elapsed(anim_halt_timer) > ANIM_HALT_FRAME_DURATION) {
+ anim_halt_timer = timer_read();
+
+ // comb glitch for all the screen
+ draw_glitch_comb(0, 0, 32, 128, 3, true);
+
+ // random moving blocks of pixels
+ for (uint8_t i = 0; i < 6; i++) {
+ int r = fastrand();
+ int rr = fastrand();
+ uint8_t x = 4 + r % 28;
+ uint8_t y = rr % 128;
+
+ uint8_t w = 7 + r % 20;
+ uint8_t h = 3 + rr % 10;
+ int s = (fastrand() % 20) - 10;
+ move_block(x, y, w, h, s);
+ }
+ }
+}
diff --git a/keyboards/lily58/keymaps/druotoni/boot.h b/keyboards/lily58/keymaps/druotoni/boot.h
new file mode 100644
index 0000000000..7897e17923
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/boot.h
@@ -0,0 +1,9 @@
+// Copyright 2021 Nicolas Druoton (druotoni)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+bool render_boot(void);
+void render_halt(void);
+
+void reset_boot(void); \ No newline at end of file
diff --git a/keyboards/lily58/keymaps/druotoni/burst.c b/keyboards/lily58/keymaps/druotoni/burst.c
new file mode 100644
index 0000000000..6dd6579e73
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/burst.c
@@ -0,0 +1,252 @@
+// Copyright 2021 Nicolas Druoton (druotoni)
+// Copyright 2020 Richard Sutherland (rich@brickbots.com)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+#include "gui_state.h"
+#include "fast_random.h"
+#include "burst.h"
+#include "draw_helper.h"
+
+// burst stuff
+static int current_burst = 0;
+static uint16_t burst_timer = 0;
+
+// WPM stuff
+static int current_wpm = 0;
+static uint16_t wpm_timer = 0;
+
+// This smoothing is 40 keystrokes
+static const float wpm_smoothing = WPM_SMOOTHING;
+
+// store values
+uint8_t burst_scope[SIZE_SCOPE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+uint8_t wpm_scope[SIZE_SCOPE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+// current max wpm
+int max_wpm = MAX_WPM_INIT;
+
+// scope animation stuff
+#define ANIM_SCOPE_FRAME_DURATION 40
+#define ANIM_SLEEP_SCOPE_FRAME_NUMBER 10
+
+uint16_t anim_scope_timer = 0;
+uint16_t anim_scope_idle_timer = 0;
+uint16_t anim_sleep_scope_timer = 0;
+
+uint8_t anim_sleep_scope_duration[ANIM_SLEEP_SCOPE_FRAME_NUMBER] = {30, 30, 30, 30, 20, 20, 30, 30, 32, 35};
+uint8_t current_sleep_scope_frame = 0;
+uint8_t sleep_scope_frame_destination = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1;
+
+// glitch animation
+int current_glitch_scope_time = 150;
+uint32_t glitch_scope_timer = 0;
+uint8_t current_glitch_scope_index = 0;
+
+static void update_wpm(void) {
+ if (wpm_timer > 0) {
+ current_wpm += ((60000 / timer_elapsed(wpm_timer) / WPM_ESTIMATED_WORD_SIZE) - current_wpm) * wpm_smoothing;
+ if (current_wpm > LIMIT_MAX_WPM) {
+ current_wpm = LIMIT_MAX_WPM;
+ }
+ }
+ wpm_timer = timer_read();
+}
+
+void update_scope(void) {
+ update_wpm();
+
+ uint16_t temps_ecoule = timer_elapsed(burst_timer);
+
+ if (temps_ecoule > BURST_FENETRE) {
+ // 1er frappe après longtemps
+ current_burst = 40;
+ } else {
+ int time_pourcent = ((100 * (temps_ecoule)) / (BURST_FENETRE));
+ current_burst = 100 - time_pourcent;
+ }
+ burst_timer = timer_read();
+}
+
+static void update_scope_array(void) {
+ // shift array
+ for (uint8_t i = 0; i < SIZE_SCOPE - 1; i++) {
+ burst_scope[i] = burst_scope[i + 1];
+ wpm_scope[i] = wpm_scope[i + 1];
+ }
+
+ int burst = current_burst;
+ int wpm = current_wpm;
+
+ // compute max wpm
+ max_wpm = (wpm == 0) ? MAX_WPM_INIT : ((wpm > max_wpm) ? wpm : max_wpm);
+
+ // current wpm ratio VS max
+ wpm = (100 * wpm) / max_wpm;
+ if (wpm > 100) wpm = 100;
+
+ // update last slot of the arrays
+ burst_scope[SIZE_SCOPE - 1] = burst;
+ wpm_scope[SIZE_SCOPE - 1] = wpm;
+
+ // apply decay to burst chart
+ uint8_t pBaisse = 0;
+ for (uint8_t i = 0; i < SIZE_SCOPE - (SIZE_SCOPE / 4); i++) {
+ pBaisse = 2 + ((SIZE_SCOPE - 1 - i)) / 2;
+ burst_scope[i] -= ((burst_scope[i] * pBaisse) / 100);
+ }
+}
+
+static void RenderScopeBlack(void) {
+ // clean central zone
+ draw_rectangle_fill(3, 82, 28, 120, false);
+
+ // redraw some parts of the frame
+ drawline_hr(1, SCOPE_Y_BOTTOM, 32, 1);
+ drawline_vt(0, SCOPE_Y_BOTTOM - 1, 42, 1);
+ drawline_vt(31, SCOPE_Y_BOTTOM - 1, 47, 1);
+}
+
+static void render_scope_white(void) {
+ static const char PROGMEM raw_logo[] = {
+ 240, 8, 4, 226, 241, 248, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 127, 128, 128, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 128, 128, 127,
+ };
+ oled_write_raw_P_cursor(0, 10, raw_logo, sizeof(raw_logo));
+}
+
+static void render_scope_chart(void) {
+ // clean the frame
+ render_scope_white();
+
+ uint8_t y_offset = SCOPE_Y_BOTTOM - 3;
+
+ for (uint8_t i = 0; i < SIZE_SCOPE; i++) {
+ // offset
+ uint8_t x = 3 + i;
+
+ // new black vertical line for burst
+ uint8_t iCurrentBurst = burst_scope[i];
+ drawline_vt(x, y_offset, (iCurrentBurst * 4) / 10, 0);
+
+ // new black point for wpm, white if it's on the burst line
+ uint8_t iCurrentWpm = wpm_scope[i];
+ uint8_t yWpm = y_offset - ((iCurrentWpm * 4) / 10);
+ oled_write_pixel(x, yWpm, !(iCurrentWpm > iCurrentBurst));
+ }
+}
+
+void reset_scope(void) {
+ // scope need wakeup
+ anim_sleep_scope_timer = timer_read();
+ current_sleep_scope_frame = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1;
+
+ sleep_scope_frame_destination = 0;
+}
+
+static void render_glitch_square(void) {
+ if (timer_elapsed(anim_scope_idle_timer) > 60) {
+ anim_scope_idle_timer = timer_read();
+ RenderScopeBlack();
+
+ uint8_t color = 0;
+ uint8_t size = 0;
+ for (uint8_t i = 0; i < 4; i++) {
+ size = 4 + (fastrand() % 6);
+
+ draw_gradient(3 + (fastrand() % 19), 85 + (fastrand() % 20), size, size, 255, 255, 4);
+
+ size = (fastrand() % 6);
+ color = 100 + (fastrand() % 100);
+ draw_gradient(3 + (fastrand() % 19), 100 + (fastrand() % 20), size, size, color, color, 4);
+ }
+ }
+}
+
+void render_scope_idle(void) {
+ uint8_t glitch_prob = get_glitch_probability();
+ get_glitch_index(&glitch_scope_timer, &current_glitch_scope_time, &current_glitch_scope_index, 150, 350, glitch_prob, 2);
+
+ switch (current_glitch_scope_index) {
+ case 0:
+ RenderScopeBlack();
+ return;
+ case 1:
+ render_glitch_square();
+ return;
+ }
+}
+
+static void RenderScopeSleep(void) {
+ if (current_sleep_scope_frame == sleep_scope_frame_destination) {
+ // animation finished
+ render_scope_idle();
+ return;
+ }
+
+ if (timer_elapsed(anim_sleep_scope_timer) > anim_sleep_scope_duration[current_sleep_scope_frame]) {
+ anim_sleep_scope_timer = timer_read();
+
+ // clean scope
+ RenderScopeBlack();
+
+ // render animation
+ render_tv_animation(current_sleep_scope_frame, 3, 80, 25, 48);
+
+ // update frame number
+ if (sleep_scope_frame_destination > current_sleep_scope_frame) {
+ current_sleep_scope_frame++;
+ } else {
+ current_sleep_scope_frame--;
+ }
+ }
+}
+
+void render_scope(gui_state_t t) {
+ if (timer_elapsed(anim_scope_timer) > ANIM_SCOPE_FRAME_DURATION) {
+ anim_scope_timer = timer_read();
+
+ // shift arrays
+ update_scope_array();
+
+ // oled_set_cursor(0, 10);
+
+ if (t == _WAKINGUP) {
+ RenderScopeSleep();
+ return;
+ }
+
+ if (t == _IDLE) {
+ sleep_scope_frame_destination = ANIM_SLEEP_SCOPE_FRAME_NUMBER - 1;
+ RenderScopeSleep();
+ return;
+ }
+
+ render_scope_chart();
+ }
+}
+
+static void decay_burst(void) {
+ uint16_t temps_ecoule = timer_elapsed(burst_timer);
+
+ int poucentageEcoule = 100;
+
+ if (temps_ecoule <= BURST_FENETRE * 4) {
+ poucentageEcoule = ((100 * (temps_ecoule)) / (BURST_FENETRE * 4));
+ }
+
+ current_burst = current_burst - poucentageEcoule;
+ if (current_burst <= 0) current_burst = 0;
+}
+
+static void decay_wpm(void) {
+ if (timer_elapsed(wpm_timer) > 1000) {
+ wpm_timer = timer_read();
+ current_wpm += (-current_wpm) * wpm_smoothing;
+ }
+}
+
+void decay_scope(void) {
+ decay_burst();
+ decay_wpm();
+}
diff --git a/keyboards/lily58/keymaps/druotoni/burst.h b/keyboards/lily58/keymaps/druotoni/burst.h
new file mode 100644
index 0000000000..8bc8153508
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/burst.h
@@ -0,0 +1,24 @@
+// Copyright 2021 Nicolas Druoton (druotoni)
+// Copyright 2020 Richard Sutherland (rich@brickbots.com)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+// burst
+#define MAX_WPM_INIT 40
+#define BURST_FENETRE 500
+
+// wpm
+#define LIMIT_MAX_WPM 150
+#define WPM_ESTIMATED_WORD_SIZE 5
+#define WPM_SMOOTHING 0.0487
+
+// scope
+#define SIZE_SCOPE 26
+#define SCOPE_Y_BOTTOM 127
+
+void update_scope(void);
+void render_scope(gui_state_t t);
+
+void reset_scope(void);
+void decay_scope(void);
diff --git a/keyboards/lily58/keymaps/druotoni/config.h b/keyboards/lily58/keymaps/druotoni/config.h
new file mode 100644
index 0000000000..37124fcaaf
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/config.h
@@ -0,0 +1,55 @@
+// Copyright 2021 Nicolas Druoton (druotoni)
+// Copyright 2012 Jun Wako <wakojun@gmail.com>
+// Copyright 2015 Jack Humbert
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define MASTER_LEFT
+#define OLED_DRIVER_ENABLE
+
+// tapping toggle for my layers
+#define TAPPING_TOGGLE 2
+
+// choose IS_LEFT or IS_RIGHT for compilation and flash firmware
+#define IS_LEFT 1
+//#define IS_RIGHT 1
+
+// logo glitch
+#define WITH_GLITCH
+// boot sequence
+#define WITH_BOOT
+
+// custom transport for displaying on both side
+#define SPLIT_TRANSACTION_IDS_USER USER_SYNC_A
+
+// custom font
+#ifdef OLED_FONT_H
+# undef OLED_FONT_H
+#endif
+#define OLED_FONT_H "navi_font.c"
+#undef OLED_FONT_END
+#define OLED_FONT_END 125
+
+// more space
+#define NO_ACTION_MACRO
+#define NO_ACTION_FUNCTION
+#define NO_ACTION_ONESHOT
+#define DISABLE_LEADER
+
+// ???
+#undef LOCKING_SUPPORT_ENABLE
+#undef LOCKING_RESYNC_ENABLE
+
+// small layer state
+#define LAYER_STATE_8BIT
+
+// no debug or trace
+#ifndef NO_DEBUG
+# define NO_DEBUG
+#endif
+#if !defined(NO_PRINT) && !defined(CONSOLE_ENABLE)
+# define NO_PRINT
+#endif
+
+
diff --git a/keyboards/lily58/keymaps/druotoni/draw_helper.c b/keyboards/lily58/keymaps/druotoni/draw_helper.c
new file mode 100644
index 0000000000..c6761d725f
--- /dev/null
+++ b/keyboards/lily58/keymaps/druotoni/draw_helper.c
@@ -0,0 +1,768 @@
+// Copyright 2021 Nicolas Druoton (druotoni)
+// Copyright 2021 ugfx
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+#include "draw_helper.h"
+#include "fast_random.h"
+
+void drawline(uint8_t x, uint8_t y, uint8_t width, bool bHorizontal, bool bPositiveDirection, bool color) {
+ if (width <= 0) return;
+ uint8_t yPlus = 0;
+ uint8_t yMois = 0;
+ uint8_t nbtour = 0;
+
+ if (!bPositiveDirection) {
+ if (bHorizontal) {
+ x -= width;
+ } else {
+ y -= width;
+ }
+ }
+
+ yMois = (width / 2) - 1 + (width % 2);
+
+ yPlus = (width / 2);
+ nbtour = (width / 4) + 1;
+
+ bool bWhite = color;
+
+ if (bHorizontal) {
+ for (uint8_t i = 0; i < nbtour; i++) {
+ oled_write_pixel(x + yPlus + i, y, bWhite);
+ oled_write_pixel(x + yMois - i, y, bWhite);
+
+ oled_write_pixel(x + i, y, bWhite);
+ oled_write_pixel(x + width - 1 - i, y, bWhite);
+ }
+ } else {
+ for (uint8_t i = 0; i < nbtour; i++) {
+ oled_write_pixel(x, y + yPlus + i, bWhite);
+ oled_write_pixel(x, y + yMois - i, bWhite);
+
+ oled_write_pixel(x, y + i, bWhite);
+
+ oled_write_pixel(x, y + width - 1 - i, bWhite);
+ }
+ }
+}
+
+void drawline_vb(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, false, true, color); }
+
+void drawline_vt(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, false, false, color); }
+
+void drawline_hr(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, true, true, color); }
+
+void drawline_hl(uint8_t x, uint8_t y, uint8_t width, bool color) { drawline(x, y, width, true, false, color); }
+
+void draw_rectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) {
+ drawline_hr(x, y, width, color);
+ drawline_hr(x, y + heigth - 1, width, color);
+ drawline_vb(x, y, heigth, color);
+ drawline_vb(x + width - 1, y, heigth, color);
+}
+
+void draw_rectangle_fill(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) {
+ for (uint8_t i = 0; i < heigth; i++) {
+ drawline_hr(x, y + i, width, color);
+ }
+}
+
+void drawline_hr_heigth(uint8_t x, uint8_t y, uint8_t width, uint8_t heigth, bool color) {
+ for (int i = 0; i < heigth; i++) {
+ drawline_hr(x, y - i, width, color);
+ drawline_hr(x, y + i, width, color);
+ }
+}
+
+void drawline_point_hr(short x, short y, short x1, bool color) {
+ if (y < 0 || y > 127) return;
+
+ if (x1 < x) {
+ short iTemp = x;
+ x = x1;
+ x1 = iTemp;
+ }
+
+ if (x1 > 31) x1 = 31;
+ if (x < 0) x = 0;
+ if (x > 31) x = 31;
+
+ drawline(x, y, x1 - x, true, true, color);
+}
+
+void flip_flap_x(short px, short py, uint8_t val, bool color) {
+ oled_write_pixel(px + val, py, color);
+ oled_write_pixel(px - val, py, color);
+}
+
+void draw_circle(uint8_t x, uint8_t y, uint8_t radius, bool color) {
+ short a, b, P;
+
+ // Calculate intermediates
+ a = 1;
+ b = radius;
+ P = 4 - radius;
+
+ short py, px;
+
+ // Away we go using Bresenham's circle algorithm
+ // Optimized to prevent double drawing
+ px = x;
+ py = y + b;
+ oled_write_pixel(px, py, color);
+ px = x;
+ py = y - b;
+ oled_write_pixel(px, py, color);
+
+ flip_flap_x(x, y, b, color);
+
+ do {
+ flip_flap_x(x, y + b, a, color);
+ flip_flap_x(x, y - b, a, color);
+ flip_flap_x(x, y + a, b, color);
+ flip_flap_x(x, y - a, b, color);
+
+ if (P < 0)
+ P += 3 + 2 * a++;
+ else
+ P += 5 + 2 * (a++ - b--);
+ } while (a < b);
+
+ flip_flap_x(x, y + b, a, color);
+ flip_flap_x(x, y - b, a, color);
+}
+
+void draw_ellipse(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color) {
+ int dx, dy;
+ int a2, b2;
+ int err, e2;
+
+ // short py, px;
+ // Calculate intermediates
+ dx = 0;
+ dy = b;
+ a2 = a * a;
+ b2 = b * b;
+ err = b2 - (2 * b - 1) * a2;
+
+ // Away we go using Bresenham's ellipse algorithm
+ do {
+ flip_flap_x(x, y + dy, dx, color);
+ flip_flap_x(x, y - dy, dx, color);
+
+ e2 = 2 * err;
+ if (e2 < (2 * dx + 1) * b2) {
+ dx++;
+ err += (2 * dx + 1) * b2;
+ }
+ if (e2 > -(2 * dy - 1) * a2) {
+ dy--;
+ err -= (2 * dy - 1) * a2;
+ }
+ } while (dy >= 0);
+}
+
+void draw_ellipse_fill(uint8_t x, uint8_t y, uint8_t a, uint8_t b, bool color) { return; }
+// void draw_ellipse_fill(uint8_t x, uint8_t y, uint8_t a, uint8_t b, uint8_t color) {
+// int dx, dy;
+// int a2, b2;
+// int err, e2;
+
+// // Calculate intermediates
+// dx = 0;
+// dy = b;
+// a2 = a * a;
+// b2 = b * b;
+// err = b2 - (2 * b - 1) * a2;
+
+// short py, px, px1;
+
+// // Away we go using Bresenham's ellipse algorithm
+// // This is optimized to prevent overdrawing by drawing a line only when a y is about to change value
+// do {
+// e2 = 2 * err;
+// if (e2 < (2 * dx + 1) * b2) {
+// dx++;
+// err += (2 * dx + 1) * b2;
+// }
+// if (e2 > -(2 * dy - 1) * a2) {
+// py = y + dy;
+// px = x - dx;
+// px1 = x + dx;
+// drawline_point_hr(px, py, px1, color);
+// if (y) {
+// py = y - dy;
+// px = x - dx;
+// px1 = x + dx;
+// drawline_point_hr(px, py, px1, color);
+// }
+// dy--;
+// err -= (2 * dy - 1) * a2;
+// }
+// } while (dy >= 0);
+// }
+
+bool test_limit(short x, short y) { return !(y < 0 || y > 127 || x < 0 || x > 31); }
+
+void flip_flap_y_point(short px, short py, short px1, uint8_t val, bool color) {
+ // firmware size optimisation : one fonction for 2 lines of code
+ drawline_point_hr(px, py + val, px1, color);
+ drawline_point_hr(px, py - val, px1, color);
+}
+
+void draw_fill_circle(short x, short y, uint8_t radius, bool color) {
+ short a, b, P;
+
+ // Calculate intermediates
+ a = 1;
+ b = radius;
+ P = 4 - radius;
+
+ // Away we go using Bresenham's circle algorithm
+ // This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value
+ short py, px, px1;
+
+ py = y;
+ px = x - b;
+ px1 = x + b;
+ drawline_point_hr(px, py, px1, color);
+
+ py = y + b;
+ px = x;
+ if (test_limit(px, py)) oled_write_pixel(px, py, color);
+ py = y - b;
+ px = x;
+ if (test_limit(px, py)) oled_write_pixel(px, py, color);
+ do {
+ flip_flap_y_point(x - b, y, x + b, a, color);
+
+ if (P < 0) {
+ P += 3 + 2 * a++;
+ } else {
+ flip_flap_y_point(x - a, y, x + a, b, color);
+
+ P += 5 + 2 * (a++ - b--);
+ }
+ } while (a < b);
+
+ flip_flap_y_point(x - b, y, x + b, a, color);
+}
+
+bool apres_moitie(int a, int b) { return (a > b / 2); }
+bool arrive_moitie(int a, int b) { return (a > b / 2); }
+bool avant_moitie(int a, int b) { return (a <= b / 2 && !apres_moitie(a, b)); }
+
+void draw_arc_sector(uint8_t x, uint8_t y, uint8_t radius, unsigned char sectors, unsigned char half, bool color) {
+ short a, b, P;
+ short py, px;
+ // Calculate intermediates
+ a = 1; // x in many explanations
+ b = radius; // y in many explanations
+ P = 4 - radius;
+
+ if (half != 2) {