From 6413633c4392a5050ae823793306fba75df45439 Mon Sep 17 00:00:00 2001
From: Serge Bazanski <q3k@q3k.org>
Date: Mon, 12 Jun 2023 13:00:32 +0200
Subject: [PATCH] *: pipelined gfx stack

This is an annoyingly large change, but the gist of it is that we:

1. Move ctx into components/ctx
2. Move uctx into usermodule/mp_uctx.c
3. Split out uctx config into ctx_config.h and share it with the
   simulator.
4. Delete a bunch of unused ctx files
5. Flip some ctx bits for speed.
6. Draw the rest of the owl, ie. implement a dedicated rasterizer task
   in components/st3m.
---
 components/badge23/CMakeLists.txt             |   1 -
 components/badge23/display.c                  | 110 ----
 components/badge23/espan.c                    |  12 +-
 components/badge23/include/badge23/display.h  |  14 -
 components/badge23/include/badge23/espan.h    |   1 +
 .../uctx => components/ctx}/.gitignore        |   0
 components/ctx/CMakeLists.txt                 |   7 +
 {usermodule/uctx => components/ctx}/LICENSE   |   0
 components/ctx/ctx.c                          |   3 +
 .../uctx/uctx => components/ctx}/ctx.h        |   0
 {sim/wasm => components/ctx}/ctx_config.h     |  16 +-
 .../ctx}/fonts/Arimo-Bold.h                   |   0
 .../ctx}/fonts/Arimo-BoldItalic.h             |   0
 .../ctx}/fonts/Arimo-Italic.h                 |   0
 .../ctx}/fonts/Arimo-Regular.h                |   0
 .../ctx}/fonts/Cousine-Bold.h                 |   0
 .../ctx}/fonts/Cousine-Regular.h              |   0
 .../ctx}/fonts/Roboto-Bold.h                  |   0
 .../ctx}/fonts/Roboto-BoldItalic.h            |   0
 .../ctx}/fonts/Roboto-Italic.h                |   0
 .../ctx}/fonts/Roboto-Regular.h               |   0
 .../ctx}/fonts/Tinos-Bold.h                   |   0
 .../ctx}/fonts/Tinos-Regular.h                |   0
 components/flow3r_bsp/flow3r_bsp_gc9a01.c     |  10 +-
 components/st3m/CMakeLists.txt                |   2 +
 components/st3m/st3m_gfx.c                    | 214 +++++++-
 components/st3m/st3m_gfx.h                    |  43 +-
 main/CMakeLists.txt                           |   5 +-
 micropython/ports/esp32/main.c                |   4 +-
 usermodule/micropython.cmake                  |   8 +-
 usermodule/mp_hardware.c                      |  56 +-
 usermodule/{uctx/uctx/uctx.c => mp_uctx.c}    | 465 +----------------
 usermodule/uctx/examples/332pal.py            |  27 -
 usermodule/uctx/examples/Calculator.py        | 242 ---------
 usermodule/uctx/examples/canvas.py            | 300 -----------
 usermodule/uctx/examples/fonts.py             |  48 --
 usermodule/uctx/examples/ililcd.py            | 183 -------
 usermodule/uctx/examples/lcd13.py             | 146 ------
 usermodule/uctx/examples/menu.py              | 365 -------------
 usermodule/uctx/examples/rectangles.py        |  58 ---
 usermodule/uctx/examples/simple.py            |  60 ---
 usermodule/uctx/examples/st7789py.py          | 403 --------------
 usermodule/uctx/examples/uimui.py             | 492 ------------------
 usermodule/uctx/uctx/micropython.cmake        |  12 -
 usermodule/uctx/uctx/micropython.mk           |   6 -
 45 files changed, 326 insertions(+), 2987 deletions(-)
 delete mode 100644 components/badge23/display.c
 delete mode 100644 components/badge23/include/badge23/display.h
 rename {usermodule/uctx => components/ctx}/.gitignore (100%)
 create mode 100644 components/ctx/CMakeLists.txt
 rename {usermodule/uctx => components/ctx}/LICENSE (100%)
 create mode 100644 components/ctx/ctx.c
 rename {usermodule/uctx/uctx => components/ctx}/ctx.h (100%)
 rename {sim/wasm => components/ctx}/ctx_config.h (90%)
 rename {usermodule/uctx => components/ctx}/fonts/Arimo-Bold.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Arimo-BoldItalic.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Arimo-Italic.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Arimo-Regular.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Cousine-Bold.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Cousine-Regular.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Roboto-Bold.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Roboto-BoldItalic.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Roboto-Italic.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Roboto-Regular.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Tinos-Bold.h (100%)
 rename {usermodule/uctx => components/ctx}/fonts/Tinos-Regular.h (100%)
 rename usermodule/{uctx/uctx/uctx.c => mp_uctx.c} (73%)
 delete mode 100755 usermodule/uctx/examples/332pal.py
 delete mode 100755 usermodule/uctx/examples/Calculator.py
 delete mode 100755 usermodule/uctx/examples/canvas.py
 delete mode 100755 usermodule/uctx/examples/fonts.py
 delete mode 100644 usermodule/uctx/examples/ililcd.py
 delete mode 100644 usermodule/uctx/examples/lcd13.py
 delete mode 100755 usermodule/uctx/examples/menu.py
 delete mode 100755 usermodule/uctx/examples/rectangles.py
 delete mode 100755 usermodule/uctx/examples/simple.py
 delete mode 100644 usermodule/uctx/examples/st7789py.py
 delete mode 100755 usermodule/uctx/examples/uimui.py
 delete mode 100644 usermodule/uctx/uctx/micropython.cmake
 delete mode 100644 usermodule/uctx/uctx/micropython.mk

diff --git a/components/badge23/CMakeLists.txt b/components/badge23/CMakeLists.txt
index 90a2355b75..4c394395e8 100644
--- a/components/badge23/CMakeLists.txt
+++ b/components/badge23/CMakeLists.txt
@@ -3,7 +3,6 @@ idf_component_register(
         apa102LEDStrip.c
         audio.c
         captouch.c
-        display.c
         espan.c
         leds.c
         scope.c
diff --git a/components/badge23/display.c b/components/badge23/display.c
deleted file mode 100644
index 3a8629f096..0000000000
--- a/components/badge23/display.c
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "badge23/display.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#include "esp_log.h"
-#include "esp_system.h"
-#include "freertos/FreeRTOS.h"
-
-
-#include "../../usermodule/uctx/uctx/ctx.h"
-
-#include "flow3r_bsp.h"
-#include "st3m_gfx.h"
-
-
-typedef struct {
-    Ctx *ctx;
-    st3m_framebuffer_desc_t *desc;
-} ctx_target_t;
-
-static void new_ctx_target(ctx_target_t *target, st3m_framebuffer_desc_t *desc) {
-    Ctx *ctx = ctx_new_for_framebuffer(
-        desc->buffer,
-        FLOW3R_BSP_DISPLAY_WIDTH,
-        FLOW3R_BSP_DISPLAY_HEIGHT,
-        FLOW3R_BSP_DISPLAY_WIDTH * 2,
-        CTX_FORMAT_RGB565_BYTESWAPPED
-    );
-    assert(ctx != NULL);
-
-	int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2;
-	int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2;
-    // rotate by 180 deg and translate x and y by 120 px to have (0,0) at the center of the screen
-    ctx_apply_transform(ctx,-1,0,offset_x,0,-1,offset_y,0,0,1);
-
-    target->ctx = ctx;
-    target->desc = desc;
-}
-
-static ctx_target_t targets[ST3M_GFX_NBUFFERS];
-
-static void display_loading_splash(ctx_target_t *target) {
-    ctx_rgb(target->ctx, 0.157, 0.129, 0.167);
-    ctx_rectangle(target->ctx, -120, -120, 240, 240);
-    ctx_fill(target->ctx);
-    
-    ctx_move_to(target->ctx, 0, 0);
-    ctx_rgb(target->ctx, 0.9, 0.9, 0.9);
-    ctx_text_align(target->ctx, CTX_TEXT_ALIGN_CENTER);
-    ctx_text_baseline(target->ctx, CTX_TEXT_BASELINE_ALPHABETIC);
-    ctx_text(target->ctx, "Loading...");
-}
-
-static ctx_target_t *next_target(void) {
-    st3m_framebuffer_desc_t *desc = st3m_gfx_framebuffer_get(portMAX_DELAY);
-    if (targets[desc->num].ctx == NULL) {
-        new_ctx_target(&targets[desc->num], desc);
-    }
-
-    return &targets[desc->num];
-}
-
-static bool initialized = false;
-static ctx_target_t *sync_target = NULL;
-
-void display_init() {
-    // HACK: needed until we have new async gfx api.
-    assert(ST3M_GFX_NBUFFERS == 1);
-
-    st3m_gfx_init();
-    for (int i = 0; i < ST3M_GFX_NBUFFERS; i++) {
-        targets[i].ctx = NULL;
-        targets[i].desc = NULL;
-    }
-
-	ctx_target_t *tgt = next_target();
-    display_loading_splash(tgt);
-    st3m_gfx_framebuffer_queue(tgt->desc);
-
-	sync_target = next_target();
-    flow3r_bsp_display_set_backlight(100);
-    initialized = true;
-}
-
-
-void display_update(){
-    if (!initialized) {
-        return;
-    }
-
-    st3m_gfx_framebuffer_queue(sync_target->desc);
-    ctx_target_t *tgt = next_target();
-    assert(tgt == sync_target);
-}
-
-void display_set_backlight(uint8_t percent) {
-    if (!initialized) {
-        return;
-    }
-    flow3r_bsp_display_set_backlight(percent);
-}
-
-Ctx *display_global_ctx(void) {
-    if (!initialized) {
-        return NULL;
-    }
-    return sync_target->ctx;
-}
\ No newline at end of file
diff --git a/components/badge23/espan.c b/components/badge23/espan.c
index a2aa2ff754..26e2921304 100644
--- a/components/badge23/espan.c
+++ b/components/badge23/espan.c
@@ -1,16 +1,16 @@
 #include "badge23/captouch.h"
 #include "badge23/audio.h"
 #include "badge23/leds.h"
-#include "badge23/display.h"
 #include "badge23/spio.h"
 #include "badge23/lock.h"
 
 #include "flow3r_bsp.h"
+#include "st3m_gfx.h"
 
 #include "esp_log.h"
 #include "driver/i2c.h"
 #include "driver/spi_master.h"
-#include <freertos/timers.h>
+#include "freertos/timers.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -92,11 +92,13 @@ void locks_init(){
     mutex_LED = xSemaphoreCreateMutex();
 }
 
-void os_app_main(void)
-{
+void os_app_early_init(void) {
     // Initialize display first as that gives us a nice splash screen.
-    display_init();
+    st3m_gfx_init();
+}
 
+void os_app_main(void)
+{
     locks_init();
     ESP_LOGI(TAG, "Starting on %s...", flow3r_bsp_hw_name);
     ESP_ERROR_CHECK(i2c_master_init());
diff --git a/components/badge23/include/badge23/display.h b/components/badge23/include/badge23/display.h
deleted file mode 100644
index ed043c27de..0000000000
--- a/components/badge23/include/badge23/display.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-#include <stdint.h>
-#include "../../usermodule/uctx/uctx/ctx.h"
-
-void display_init();
-void display_set_backlight(uint8_t percent);
-
-// Transitional functionality operating on global framebuffer and global ctx.
-// Will get replaced with 'real' ctx rendering system.
-void display_ctx_init();
-void display_update();
-Ctx *display_global_ctx(void);
diff --git a/components/badge23/include/badge23/espan.h b/components/badge23/include/badge23/espan.h
index 7915f33e09..b118335d69 100644
--- a/components/badge23/include/badge23/espan.h
+++ b/components/badge23/include/badge23/espan.h
@@ -1,4 +1,5 @@
 #pragma once
 #include <stdint.h>
+void os_app_early_init(void);
 void os_app_main(void);
 uint8_t hardware_is_initialized(void);
diff --git a/usermodule/uctx/.gitignore b/components/ctx/.gitignore
similarity index 100%
rename from usermodule/uctx/.gitignore
rename to components/ctx/.gitignore
diff --git a/components/ctx/CMakeLists.txt b/components/ctx/CMakeLists.txt
new file mode 100644
index 0000000000..e368ff48f1
--- /dev/null
+++ b/components/ctx/CMakeLists.txt
@@ -0,0 +1,7 @@
+idf_component_register(
+    SRCS
+        ctx.c
+    INCLUDE_DIRS
+        .
+        ./fonts/
+)
\ No newline at end of file
diff --git a/usermodule/uctx/LICENSE b/components/ctx/LICENSE
similarity index 100%
rename from usermodule/uctx/LICENSE
rename to components/ctx/LICENSE
diff --git a/components/ctx/ctx.c b/components/ctx/ctx.c
new file mode 100644
index 0000000000..6edde39a15
--- /dev/null
+++ b/components/ctx/ctx.c
@@ -0,0 +1,3 @@
+#include "ctx_config.h"
+#define CTX_IMPLEMENTATION
+#include "ctx.h"
\ No newline at end of file
diff --git a/usermodule/uctx/uctx/ctx.h b/components/ctx/ctx.h
similarity index 100%
rename from usermodule/uctx/uctx/ctx.h
rename to components/ctx/ctx.h
diff --git a/sim/wasm/ctx_config.h b/components/ctx/ctx_config.h
similarity index 90%
rename from sim/wasm/ctx_config.h
rename to components/ctx/ctx_config.h
index 9e70abc56c..a466619655 100644
--- a/sim/wasm/ctx_config.h
+++ b/components/ctx/ctx_config.h
@@ -1,6 +1,6 @@
 #pragma once
 
-// Keep in sync with defines in usermodule/uctx/uctx.c.
+#include <stdint.h>
 
 #define CTX_TINYVG    1
 #define CTX_TVG_STDIO 0
@@ -13,10 +13,10 @@
 #define CTX_ENABLE_FLOAT              0
 #define CTX_32BIT_SEGMENTS            0
 #define CTX_ENABLE_RGBA8              1
-#define CTX_ENABLE_RGB332             1
-#define CTX_ENABLE_GRAY1              1
-#define CTX_ENABLE_GRAY2              1
-#define CTX_ENABLE_GRAY4              1
+#define CTX_ENABLE_RGB332             0
+#define CTX_ENABLE_GRAY1              0
+#define CTX_ENABLE_GRAY2              0
+#define CTX_ENABLE_GRAY4              0
 #define CTX_ENABLE_RGB565             1
 #define CTX_ENABLE_RGB565_BYTESWAPPED 1
 #define CTX_ENABLE_CBRLE              0
@@ -35,8 +35,8 @@
 #define CTX_MAX_DASHES          10
 #define CTX_MAX_GRADIENT_STOPS  10
 #define CTX_CM                  0
-#define CTX_SHAPE_CACHE         0
-#define CTX_SHAPE_CACHE_DEFAULT 0
+#define CTX_SHAPE_CACHE         1
+#define CTX_SHAPE_CACHE_DEFAULT 1
 #define CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS 128
 #define CTX_NATIVE_GRAYA8       0
 #define CTX_ENABLE_SHADOW_BLUR  0
@@ -64,7 +64,7 @@
 
 #define CTX_BAREMETAL              1
 
-#define CTX_EVENTS                 1
+#define CTX_EVENTS                 0
 #define CTX_MAX_DEVICES            1
 #define CTX_MAX_KEYBINDINGS       16
 #define CTX_RASTERIZER             1
diff --git a/usermodule/uctx/fonts/Arimo-Bold.h b/components/ctx/fonts/Arimo-Bold.h
similarity index 100%
rename from usermodule/uctx/fonts/Arimo-Bold.h
rename to components/ctx/fonts/Arimo-Bold.h
diff --git a/usermodule/uctx/fonts/Arimo-BoldItalic.h b/components/ctx/fonts/Arimo-BoldItalic.h
similarity index 100%
rename from usermodule/uctx/fonts/Arimo-BoldItalic.h
rename to components/ctx/fonts/Arimo-BoldItalic.h
diff --git a/usermodule/uctx/fonts/Arimo-Italic.h b/components/ctx/fonts/Arimo-Italic.h
similarity index 100%
rename from usermodule/uctx/fonts/Arimo-Italic.h
rename to components/ctx/fonts/Arimo-Italic.h
diff --git a/usermodule/uctx/fonts/Arimo-Regular.h b/components/ctx/fonts/Arimo-Regular.h
similarity index 100%
rename from usermodule/uctx/fonts/Arimo-Regular.h
rename to components/ctx/fonts/Arimo-Regular.h
diff --git a/usermodule/uctx/fonts/Cousine-Bold.h b/components/ctx/fonts/Cousine-Bold.h
similarity index 100%
rename from usermodule/uctx/fonts/Cousine-Bold.h
rename to components/ctx/fonts/Cousine-Bold.h
diff --git a/usermodule/uctx/fonts/Cousine-Regular.h b/components/ctx/fonts/Cousine-Regular.h
similarity index 100%
rename from usermodule/uctx/fonts/Cousine-Regular.h
rename to components/ctx/fonts/Cousine-Regular.h
diff --git a/usermodule/uctx/fonts/Roboto-Bold.h b/components/ctx/fonts/Roboto-Bold.h
similarity index 100%
rename from usermodule/uctx/fonts/Roboto-Bold.h
rename to components/ctx/fonts/Roboto-Bold.h
diff --git a/usermodule/uctx/fonts/Roboto-BoldItalic.h b/components/ctx/fonts/Roboto-BoldItalic.h
similarity index 100%
rename from usermodule/uctx/fonts/Roboto-BoldItalic.h
rename to components/ctx/fonts/Roboto-BoldItalic.h
diff --git a/usermodule/uctx/fonts/Roboto-Italic.h b/components/ctx/fonts/Roboto-Italic.h
similarity index 100%
rename from usermodule/uctx/fonts/Roboto-Italic.h
rename to components/ctx/fonts/Roboto-Italic.h
diff --git a/usermodule/uctx/fonts/Roboto-Regular.h b/components/ctx/fonts/Roboto-Regular.h
similarity index 100%
rename from usermodule/uctx/fonts/Roboto-Regular.h
rename to components/ctx/fonts/Roboto-Regular.h
diff --git a/usermodule/uctx/fonts/Tinos-Bold.h b/components/ctx/fonts/Tinos-Bold.h
similarity index 100%
rename from usermodule/uctx/fonts/Tinos-Bold.h
rename to components/ctx/fonts/Tinos-Bold.h
diff --git a/usermodule/uctx/fonts/Tinos-Regular.h b/components/ctx/fonts/Tinos-Regular.h
similarity index 100%
rename from usermodule/uctx/fonts/Tinos-Regular.h
rename to components/ctx/fonts/Tinos-Regular.h
diff --git a/components/flow3r_bsp/flow3r_bsp_gc9a01.c b/components/flow3r_bsp/flow3r_bsp_gc9a01.c
index 0c7f51e98a..400bc53903 100644
--- a/components/flow3r_bsp/flow3r_bsp_gc9a01.c
+++ b/components/flow3r_bsp/flow3r_bsp_gc9a01.c
@@ -80,6 +80,8 @@
 #define MADCTL_BGR       0x08
 #define MADCTL_MH        0x04
 
+static const char *TAG = "flow3r-bsp-gc9a01";
+
 // Transaction 'user' structure as used by SPI transactions to the display.
 // Provides enough data for the pre-transaction callback to be able to set the
 // DC pin as needed.
@@ -551,7 +553,13 @@ static esp_err_t flow3r_bsp_gc9a01_blit_next(flow3r_bsp_gc9a01_blit_t *blit) {
 	blit->left -= size;
 	blit->fb += size;
 
-	return spi_device_queue_trans(blit->gc9a01->spi, &blit->spi_tx, portMAX_DELAY);
+	esp_err_t res = spi_device_queue_trans(blit->gc9a01->spi, &blit->spi_tx, portMAX_DELAY);
+	if (res != ESP_OK) {
+
+		ESP_LOGE(TAG, "spi_device_queue_trans (size %d, buf %p, dma capab: %d, largest block: %d): %s",
+			size, blit->fb, esp_ptr_dma_capable(blit->fb), heap_caps_get_largest_free_block(MALLOC_CAP_DMA), esp_err_to_name(res));
+	}
+	return res;
 }
 
 static esp_err_t flow3r_bsp_gc9a01_blit_start(flow3r_bsp_gc9a01_t *gc9a01, flow3r_bsp_gc9a01_blit_t *blit, const uint16_t *fb) {
diff --git a/components/st3m/CMakeLists.txt b/components/st3m/CMakeLists.txt
index 7196e6632a..33bcf75e02 100644
--- a/components/st3m/CMakeLists.txt
+++ b/components/st3m/CMakeLists.txt
@@ -1,8 +1,10 @@
 idf_component_register(
     SRCS
         st3m_gfx.c
+        st3m_counter.c
     INCLUDE_DIRS
         .
     REQUIRES
         flow3r_bsp
+        ctx
 )
diff --git a/components/st3m/st3m_gfx.c b/components/st3m/st3m_gfx.c
index 8aa4ae0e66..1fd02d3ff8 100644
--- a/components/st3m/st3m_gfx.c
+++ b/components/st3m/st3m_gfx.c
@@ -4,33 +4,134 @@
 
 #include "esp_system.h"
 #include "esp_log.h"
+#include "esp_task.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/queue.h"
 
+#include "ctx_config.h"
+#include "ctx.h"
+
 #include "flow3r_bsp.h"
+#include "st3m_counter.h"
+
+static const char *TAG = "st3m-gfx";
 
-// Actual framebuffers, efficiently accessible via DMA.
-static DMA_ATTR uint16_t framebuffers[ST3M_GFX_NBUFFERS][FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT];
+// SRAM framebuffer into which ctx drawlists will be rasterized. After
+// rasterization, their contents will be copied into SPIRAM. Then, the ESP SPI
+// driver will piecewise copy the buffer back into DMA-able memory to send it
+// over to the display.
+//
+// This Rube Goldberg contraption is still faster than directly rasterizing into
+// SPIRAM (~20% faster). Ideally we would also keep both buffers in DMAble SRAM,
+// but we don't have enough SRAM for that.
+static uint16_t framebuffer_staging[240*240];
+
+// framebuffer_staging-backed Ctx instance, used to render drawlists into
+// framebuffer_staging.
+static Ctx *framebuffer_staging_ctx;
 
 static st3m_framebuffer_desc_t framebuffer_descs[ST3M_GFX_NBUFFERS];
 
+static st3m_ctx_desc_t dctx_descs[ST3M_GFX_NCTX];
+
 // Queue of free framebuffer descriptors, written into by crtc once rendered,
 // read from by rasterizer when new frame starts.
 static QueueHandle_t framebuffer_freeq = NULL;
-
 // Queue of framebuffer descriptors to blit out.
 static QueueHandle_t framebuffer_blitq = NULL;
 
+static st3m_counter_rate_t blit_rate;
+static st3m_counter_timer_t blit_read_time;
+static st3m_counter_timer_t blit_work_time;
+static st3m_counter_timer_t blit_write_time;
+
+static QueueHandle_t dctx_freeq = NULL;
+static QueueHandle_t dctx_rastq = NULL;
+
+static st3m_counter_rate_t rast_rate;
+static st3m_counter_timer_t rast_read_fb_time;
+static st3m_counter_timer_t rast_read_dctx_time;
+static st3m_counter_timer_t rast_work_time;
+static st3m_counter_timer_t rast_write_time;
+
+static TaskHandle_t crtc_task;
+static TaskHandle_t rast_task;
+
 static void st3m_gfx_crtc_task(void *_arg) {
 	(void)_arg;
 
 	while (true) {
 		int descno;
+
+		int64_t start = esp_timer_get_time();
 		xQueueReceive(framebuffer_blitq, &descno, portMAX_DELAY);
+		int64_t end = esp_timer_get_time();
+		st3m_counter_timer_sample(&blit_read_time, end-start);
 
+		start = esp_timer_get_time();
     	flow3r_bsp_display_send_fb(framebuffer_descs[descno].buffer);
+		end = esp_timer_get_time();
+		st3m_counter_timer_sample(&blit_work_time, end-start);
 
+		start = esp_timer_get_time();
 		xQueueSend(framebuffer_freeq, &descno, portMAX_DELAY);
+		end = esp_timer_get_time();
+		st3m_counter_timer_sample(&blit_write_time, end-start);
+
+		st3m_counter_rate_sample(&blit_rate);
+
+		if (st3m_counter_rate_report(&blit_rate, 1)) {
+			float rate = 1000000.0 / st3m_counter_rate_average(&blit_rate);
+			float read = st3m_counter_timer_average(&blit_read_time) / 1000.0;
+			float work = st3m_counter_timer_average(&blit_work_time) / 1000.0;
+			float write = st3m_counter_timer_average(&blit_write_time) / 1000.0;
+			ESP_LOGI(TAG, "blitting: %.3f/sec, read %.3fms, work %.3fms, write %.3fms", rate, read, work, write);
+		}
+	}
+}
+
+static void st3m_gfx_rast_task(void *_arg) {
+	(void)_arg;
+
+	while (true) {
+		int fb_descno, dctx_descno;
+		int64_t start = esp_timer_get_time();
+		xQueueReceive(framebuffer_freeq, &fb_descno, portMAX_DELAY);
+		int64_t end = esp_timer_get_time();
+		st3m_counter_timer_sample(&rast_read_fb_time, end-start);
+
+		start = esp_timer_get_time();
+		xQueueReceive(dctx_rastq, &dctx_descno, portMAX_DELAY);
+		end = esp_timer_get_time();
+		st3m_counter_timer_sample(&rast_read_dctx_time, end-start);
+
+
+		start = esp_timer_get_time();
+
+		// Render to staging and memcpy to framebuffer.
+		ctx_render_ctx(dctx_descs[dctx_descno].ctx, framebuffer_staging_ctx);
+		memcpy(framebuffer_descs[fb_descno].buffer, framebuffer_staging, 240*240*2);
+		ctx_drawlist_clear(dctx_descs[dctx_descno].ctx);
+
+		end = esp_timer_get_time();
+		st3m_counter_timer_sample(&rast_work_time, end-start);
+
+		start = esp_timer_get_time();
+		xQueueSend(dctx_freeq, &dctx_descno, portMAX_DELAY);
+		xQueueSend(framebuffer_blitq, &fb_descno, portMAX_DELAY);
+		end = esp_timer_get_time();
+		st3m_counter_timer_sample(&rast_write_time, end-start);
+
+		st3m_counter_rate_sample(&rast_rate);
+
+		if (st3m_counter_rate_report(&rast_rate, 1)) {
+			float rate = 1000000.0 / st3m_counter_rate_average(&rast_rate);
+			float read_fb = st3m_counter_timer_average(&rast_read_fb_time) / 1000.0;
+			float read_dctx = st3m_counter_timer_average(&rast_read_dctx_time) / 1000.0;
+			float work = st3m_counter_timer_average(&rast_work_time) / 1000.0;
+			float write = st3m_counter_timer_average(&rast_write_time) / 1000.0;
+			ESP_LOGI(TAG, "rasterization: %.3f/sec, read fb %.3fms, read dctx %.3fms, work %.3fms, write %.3fms", rate, read_fb, read_dctx, work, write);
+		}
 	}
 }
 
@@ -38,40 +139,121 @@ void st3m_gfx_init(void) {
 	// Make sure we're not being re-initialized.
 	assert(framebuffer_freeq == NULL);
 
+	st3m_counter_rate_init(&blit_rate);
+	st3m_counter_timer_init(&blit_read_time);
+	st3m_counter_timer_init(&blit_work_time);
+	st3m_counter_timer_init(&blit_write_time);
+
+	st3m_counter_rate_init(&rast_rate);
+	st3m_counter_timer_init(&rast_read_fb_time);
+	st3m_counter_timer_init(&rast_read_dctx_time);
+	st3m_counter_timer_init(&rast_work_time);
+	st3m_counter_timer_init(&rast_write_time);
+
     flow3r_bsp_display_init();
+	flow3r_bsp_display_set_backlight(100);
 
 	// Create framebuffer queues.
-	framebuffer_freeq = xQueueCreate(2, sizeof(int));
+	framebuffer_freeq = xQueueCreate(ST3M_GFX_NBUFFERS+1, sizeof(int));
 	assert(framebuffer_freeq != NULL);
-	framebuffer_blitq = xQueueCreate(2, sizeof(int));
+	framebuffer_blitq = xQueueCreate(ST3M_GFX_NBUFFERS+1, sizeof(int));
 	assert(framebuffer_blitq != NULL);
 
-	// Zero out framebuffers and set up descriptors.
+	// Create drawlist ctx queues.
+	dctx_freeq = xQueueCreate(ST3M_GFX_NCTX+1, sizeof(int));
+	assert(dctx_freeq != NULL);
+	dctx_rastq = xQueueCreate(ST3M_GFX_NCTX+1, sizeof(int));
+	assert(dctx_rastq != NULL);
+
+    // Create staging framebuffer Ctx.
+    framebuffer_staging_ctx = ctx_new_for_framebuffer(
+		framebuffer_staging,
+		FLOW3R_BSP_DISPLAY_WIDTH,
+		FLOW3R_BSP_DISPLAY_HEIGHT,
+		FLOW3R_BSP_DISPLAY_WIDTH * 2,
+		CTX_FORMAT_RGB565_BYTESWAPPED
+	);
+	assert(framebuffer_staging_ctx != NULL);
+   	// Rotate by 180 deg and translate x and y by 120 px to have (0,0) at the center of the screen
+	int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2;
+	int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2;
+    ctx_apply_transform(framebuffer_staging_ctx, -1, 0, offset_x, 0, -1, offset_y, 0, 0, 1);
+
 	for (int i = 0; i < ST3M_GFX_NBUFFERS; i++) {
-		memset(&framebuffers[i], 0, FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT * 2);
-		st3m_framebuffer_desc_t *desc = &framebuffer_descs[i];
-		desc->num = i;
-		desc->buffer = framebuffers[i];
+		// Setup framebuffer descriptor.
+		st3m_framebuffer_desc_t *fb_desc = &framebuffer_descs[i];
+		fb_desc->num = i;
+		fb_desc->buffer = malloc(2 * FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT);
+		assert(fb_desc->buffer != NULL);
+		memset(fb_desc->buffer, 0, 2 * FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT);
 
 		// Push descriptor to freeq.
 		BaseType_t res = xQueueSend(framebuffer_freeq, &i, 0);
 		assert(res == pdTRUE);
 	}
 
+	for (int i = 0; i < ST3M_GFX_NCTX; i++) {
+		// Setup dctx descriptor.
+		st3m_ctx_desc_t *dctx_desc = &dctx_descs[i];
+		dctx_desc->num = i;
+		dctx_desc->ctx = ctx_new_drawlist(FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT);
+		assert(dctx_desc->ctx != NULL);
+
+		// Push descriptor to freeq.
+		BaseType_t res = xQueueSend(dctx_freeq, &i, 0);
+		assert(res == pdTRUE);
+	}
+
 	// Start crtc.
-	BaseType_t res = xTaskCreate(st3m_gfx_crtc_task, "crtc", 2048, NULL, configMAX_PRIORITIES - 2, NULL);
+	BaseType_t res = xTaskCreate(st3m_gfx_crtc_task, "crtc", 4096, NULL, ESP_TASK_PRIO_MIN+3, &crtc_task);
+	assert(res == pdPASS);
+
+	// Start rast.
+	res = xTaskCreate(st3m_gfx_rast_task, "rast", 4096, NULL, ESP_TASK_PRIO_MIN+1, &rast_task);
 	assert(res == pdPASS);
 }
 
-st3m_framebuffer_desc_t *st3m_gfx_framebuffer_get(TickType_t ticks_to_wait) {
+st3m_ctx_desc_t *st3m_gfx_drawctx_free_get(TickType_t ticks_to_wait) {
 	int descno;
-	BaseType_t res = xQueueReceive(framebuffer_freeq, &descno, ticks_to_wait);
+	BaseType_t res = xQueueReceive(dctx_freeq, &descno, ticks_to_wait);
 	if (res != pdTRUE) {
 		return NULL;
 	}
-	return &framebuffer_descs[descno];
+	return &dctx_descs[descno];
 }
 
-void st3m_gfx_framebuffer_queue(st3m_framebuffer_desc_t *desc) {
-	xQueueSend(framebuffer_blitq, &desc->num, portMAX_DELAY);
+void st3m_gfx_drawctx_pipe_put(st3m_ctx_desc_t *desc) {
+	xQueueSend(dctx_rastq, &desc->num, portMAX_DELAY);
+}
+
+uint8_t st3m_gfx_drawctx_pipe_full(void) {
+	return uxQueueSpacesAvailable(dctx_rastq) == 0;
+}
+
+void st3m_gfx_flush(void) {
+	ESP_LOGW(TAG, "Pipeline flush/reset requested...");
+	// Drain all workqs and freeqs.
+	xQueueReset(dctx_freeq);
+	xQueueReset(dctx_rastq);
+	xQueueReset(framebuffer_freeq);
+	xQueueReset(framebuffer_blitq);
+
+	// Delay, making sure pipeline tasks have returned all used descriptors. One
+	// second is enough to make sure we've processed everything.
+	vTaskDelay(1000 / portTICK_RATE_MS);
+
+	// And drain again.
+	xQueueReset(framebuffer_freeq);
+	xQueueReset(dctx_freeq);
+
+	// Now, re-submit all descriptors to freeqs.
+	for (int i = 0; i < ST3M_GFX_NBUFFERS; i++) {
+		BaseType_t res = xQueueSend(framebuffer_freeq, &i, 0);
+		assert(res == pdTRUE);
+	}
+	for (int i = 0; i < ST3M_GFX_NCTX; i++) {
+		BaseType_t res = xQueueSend(dctx_freeq, &i, 0);
+		assert(res == pdTRUE);
+	}
+	ESP_LOGW(TAG, "Pipeline flush/reset done.");
 }
\ No newline at end of file
diff --git a/components/st3m/st3m_gfx.h b/components/st3m/st3m_gfx.h
index 55849fd682..53c6c78809 100644
--- a/components/st3m/st3m_gfx.h
+++ b/components/st3m/st3m_gfx.h
@@ -2,18 +2,53 @@
 
 #include "freertos/FreeRTOS.h"
 
-// Each buffer  takes ~116kB SRAM. While one framebuffer is being blitted, the
+#include "ctx_config.h"
+#include "ctx.h"
+
+// Each buffer  takes ~116kB SPIRAM. While one framebuffer is being blitted, the
 // other one is being written to by the rasterizer.
-#define ST3M_GFX_NBUFFERS 1
+#define ST3M_GFX_NBUFFERS 2
+// More ctx drawlists than buffers so that micropython doesn't get starved when
+// pipeline runs in lockstep.
+#define ST3M_GFX_NCTX 2
 
 // A framebuffer descriptor, pointing at a framebuffer.
 typedef struct {
+	// The numeric ID of this descriptor.
 	int num;
+	// SPIRAM buffer.
 	uint16_t *buffer;
 } st3m_framebuffer_desc_t;
 
+// Initialize the gfx subsystem of st3m, includng the rasterization and
+// crtx/blitter pipeline.
 void st3m_gfx_init(void);
 
-st3m_framebuffer_desc_t *st3m_gfx_framebuffer_get(TickType_t ticks_to_wait);
+// A drawlist ctx descriptor, pointing to a drawlist-backed Ctx.
+typedef struct {
+	// The numeric ID of this descriptor.
+	int num;
+	Ctx *ctx;
+} st3m_ctx_desc_t;
+
+// Get a free drawlist ctx to draw into.
+//
+// ticks_to_wait can be used to limit the time to wait for a free ctx
+// descriptor, or portDELAY_MAX can be specified to wait forever. If the timeout
+// expires, NULL will be returned.
+st3m_ctx_desc_t *st3m_gfx_drawctx_free_get(TickType_t ticks_to_wait);
+
+// Submit a filled ctx descriptor to the rasterization pipeline.
+void st3m_gfx_drawctx_pipe_put(st3m_ctx_desc_t *desc);
+
+// Returns true if the rasterizaiton pipeline submission would block.
+uint8_t st3m_gfx_drawctx_pipe_full(void);
 
-void st3m_gfx_framebuffer_queue(st3m_framebuffer_desc_t *desc);
\ No newline at end of file
+// Flush any in-flight pipelined work, resetting the free ctx/framebuffer queues
+// to their initial state. This should be called if there has been any drawlist
+// ctx dropped (ie. drawctx_free_get was called but then drawctx_pipe_put
+// wasn't, for exaple if Micropython restarted).
+//
+// This causes a graphical disturbance and shouldn't be called during normal
+// operation.
+void st3m_gfx_flush(void);
\ No newline at end of file
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index 9c48a07570..6f00a3cd8b 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -102,9 +102,12 @@ set(MICROPY_SOURCE_QSTR
 )
 
 set(IDF_COMPONENTS
-    app_update
     badge23
     flow3r_bsp
+    st3m
+    ctx
+
+    app_update
     bootloader_support
     bt
     driver
diff --git a/micropython/ports/esp32/main.c b/micropython/ports/esp32/main.c
index 7b7ac36be1..eeb0cd5d8d 100644
--- a/micropython/ports/esp32/main.c
+++ b/micropython/ports/esp32/main.c
@@ -69,7 +69,7 @@
 #endif
 
 // MicroPython runs as a task under FreeRTOS
-#define MP_TASK_PRIORITY        (ESP_TASK_PRIO_MIN + 1)
+#define MP_TASK_PRIORITY        (ESP_TASK_PRIO_MIN + 2)
 #define MP_TASK_STACK_SIZE      (16 * 1024)
 
 // Set the margin for detecting stack overflow, depending on the CPU architecture.
@@ -240,6 +240,8 @@ void app_main(void) {
     MICROPY_BOARD_STARTUP();
 
     // Create and transfer control to the MicroPython task.
+
+    os_app_early_init();
     xTaskCreatePinnedToCore(mp_task, "mp_task", MP_TASK_STACK_SIZE / sizeof(StackType_t), NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID);
     os_app_main(); // ./badge23/ entry point
 }
diff --git a/usermodule/micropython.cmake b/usermodule/micropython.cmake
index 326524e3bb..03ce93dbd1 100644
--- a/usermodule/micropython.cmake
+++ b/usermodule/micropython.cmake
@@ -11,15 +11,11 @@ target_sources(usermod_badge23 INTERFACE
     ${CMAKE_CURRENT_LIST_DIR}/mp_badge_link.c
     ${CMAKE_CURRENT_LIST_DIR}/mp_synth.c
     ${CMAKE_CURRENT_LIST_DIR}/mp_kernel.c
+    ${CMAKE_CURRENT_LIST_DIR}/mp_uctx.c
 )
 
 target_include_directories(usermod_badge23 INTERFACE
     ${CMAKE_CURRENT_LIST_DIR}
 )
 
-target_link_libraries(usermod INTERFACE usermod_badge23)
-
-
-
-#Also add uctx as a usermodule
-include(${CMAKE_CURRENT_LIST_DIR}/uctx/uctx/micropython.cmake)
+target_link_libraries(usermod INTERFACE usermod_badge23)
\ No newline at end of file
diff --git a/usermodule/mp_hardware.c b/usermodule/mp_hardware.c
index fcabf2cd62..b7b62c4dff 100644
--- a/usermodule/mp_hardware.c
+++ b/usermodule/mp_hardware.c
@@ -13,11 +13,14 @@
 
 #include "badge23/audio.h"
 #include "badge23/captouch.h"
-#include "badge23/display.h"
 #include "badge23/spio.h"
 #include "badge23/espan.h"
 
 #include "flow3r_bsp.h"
+#include "st3m_gfx.h"
+
+#include "ctx_config.h"
+#include "ctx.h"
 
 mp_obj_t mp_ctx_from_ctx(Ctx *ctx);
 
@@ -31,15 +34,9 @@ STATIC mp_obj_t mp_captouch_calibration_active(void) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_captouch_calibration_active_obj, mp_captouch_calibration_active);
 
-STATIC mp_obj_t mp_display_update(void) {
-    display_update();
-    return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_display_update_obj, mp_display_update);
-
 STATIC mp_obj_t mp_display_set_backlight(mp_obj_t percent_in) {
     uint8_t percent = mp_obj_get_int(percent_in);
-    display_set_backlight(percent);
+    flow3r_bsp_display_set_backlight(percent);
     return mp_const_none;
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_display_set_backlight_obj, mp_display_set_backlight);
@@ -172,14 +169,16 @@ STATIC mp_obj_t mp_version(void) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_version_obj, mp_version);
 
-STATIC mp_obj_t mp_get_ctx(size_t n_args, const mp_obj_t *args) {
-    Ctx *ctx = NULL;
-    // This might be called before the ctx is ready.
-    // HACK: this will go away with the new drawing API.
-    while ((ctx = display_global_ctx()) == NULL) {
-        vTaskDelay(100 / portTICK_PERIOD_MS);
+static st3m_ctx_desc_t *gfx_last_desc = NULL;
+
+STATIC mp_obj_t mp_get_ctx(void) {
+    if (gfx_last_desc == NULL) {
+        gfx_last_desc = st3m_gfx_drawctx_free_get(0);
+        if (gfx_last_desc == NULL) {
+            return mp_const_none;
+        }
     }
-    mp_obj_t mp_ctx = mp_ctx_from_ctx(ctx);
+    mp_obj_t mp_ctx = mp_ctx_from_ctx(gfx_last_desc->ctx);
     return mp_ctx;
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_get_ctx_obj, mp_get_ctx);
@@ -193,6 +192,31 @@ STATIC mp_obj_t mp_freertos_sleep(mp_obj_t ms_in) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_freertos_sleep_obj, mp_freertos_sleep);
 
+STATIC mp_obj_t mp_display_update(mp_obj_t in_ctx) {
+    // TODO(q3k): check in_ctx? Or just drop from API?
+
+    if (gfx_last_desc != NULL) {
+        st3m_gfx_drawctx_pipe_put(gfx_last_desc);
+	    gfx_last_desc = NULL;
+    }
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_display_update_obj, mp_display_update);
+
+STATIC mp_obj_t mp_display_pipe_full(void) {
+    if (st3m_gfx_drawctx_pipe_full()) {
+        return mp_const_true;
+    }
+    return mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_display_pipe_full_obj, mp_display_pipe_full);
+
+STATIC mp_obj_t mp_display_pipe_flush(void) {
+    st3m_gfx_flush();
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_display_pipe_flush_obj, mp_display_pipe_flush);
+
 STATIC const mp_rom_map_elem_t mp_module_hardware_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_badge_audio) },
     { MP_ROM_QSTR(MP_QSTR_init_done), MP_ROM_PTR(&mp_init_done_obj) },
@@ -219,6 +243,8 @@ STATIC const mp_rom_map_elem_t mp_module_hardware_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_dump_all_sources), MP_ROM_PTR(&mp_dump_all_sources_obj) },
     { MP_ROM_QSTR(MP_QSTR_display_update), MP_ROM_PTR(&mp_display_update_obj) },
     { MP_ROM_QSTR(MP_QSTR_freertos_sleep), MP_ROM_PTR(&mp_freertos_sleep_obj) },
+    { MP_ROM_QSTR(MP_QSTR_display_pipe_full), MP_ROM_PTR(&mp_display_pipe_full_obj) },
+    { MP_ROM_QSTR(MP_QSTR_display_pipe_flush), MP_ROM_PTR(&mp_display_pipe_flush_obj) },
     { MP_ROM_QSTR(MP_QSTR_display_set_backlight), MP_ROM_PTR(&mp_display_set_backlight_obj) },
     { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&mp_version_obj) },
     { MP_ROM_QSTR(MP_QSTR_get_ctx), MP_ROM_PTR(&mp_get_ctx_obj) },
diff --git a/usermodule/uctx/uctx/uctx.c b/usermodule/mp_uctx.c
similarity index 73%
rename from usermodule/uctx/uctx/uctx.c
rename to usermodule/mp_uctx.c
index cce8f8140e..f8cfb288d9 100644
--- a/usermodule/uctx/uctx/uctx.c
+++ b/usermodule/mp_uctx.c
@@ -6,193 +6,12 @@
 #include "py/objarray.h"
 #include "py/runtime.h"
 
-#define CTX_TINYVG    1
-#define CTX_TVG_STDIO 0
-#define CTX_DITHER    1
-
-#define CTX_PDF                       0
-#define CTX_PROTOCOL_U8_COLOR         1
-#define CTX_AVOID_CLIPPED_SUBDIVISION 0
-#define CTX_LIMIT_FORMATS             1
-#define CTX_ENABLE_FLOAT              0
-#define CTX_32BIT_SEGMENTS            0
-#define CTX_ENABLE_RGBA8              1
-#define CTX_ENABLE_RGB332             1
-#define CTX_ENABLE_GRAY1              1
-#define CTX_ENABLE_GRAY2              1
-#define CTX_ENABLE_GRAY4              1
-#define CTX_ENABLE_RGB565             1
-#define CTX_ENABLE_RGB565_BYTESWAPPED 1
-#define CTX_ENABLE_CBRLE              0
-#define CTX_BITPACK_PACKER            0
-#define CTX_COMPOSITING_GROUPS        0
-#define CTX_RENDERSTREAM_STATIC       0
-#define CTX_GRADIENT_CACHE            1
-#define CTX_ENABLE_CLIP               1
-#define CTX_MIN_JOURNAL_SIZE        512  // grows dynamically
-#define CTX_MIN_EDGE_LIST_SIZE      512  // is also max and limits complexity
-                                         // of paths that can be filled
-#define CTX_STATIC_OPAQUE       1
-#define CTX_MAX_SCANLINE_LENGTH 512
-#define CTX_1BIT_CLIP           1
-
-#define CTX_MAX_DASHES          10
-#define CTX_MAX_GRADIENT_STOPS  10
-#define CTX_CM                  0
-#define CTX_SHAPE_CACHE         0
-#define CTX_SHAPE_CACHE_DEFAULT 0
-#define CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS 128
-#define CTX_NATIVE_GRAYA8       0
-#define CTX_ENABLE_SHADOW_BLUR  0
-#define CTX_FONTS_FROM_FILE     0
-#define CTX_MAX_KEYDB          16
-#define CTX_FRAGMENT_SPECIALIZE 1
-#define CTX_FAST_FILL_RECT      1
-#define CTX_MAX_TEXTURES        1
-#define CTX_PARSER_MAXLEN       512
-#define CTX_PARSER_FIXED_TEMP   1
-#define CTX_CURRENT_PATH        1
-#define CTX_BLENDING_AND_COMPOSITING 1
-#define CTX_STRINGPOOL_SIZE        256
-#define CTX_AUDIO                    0
-#define CTX_CLIENTS                  0
-
-#ifdef MICROPY_UNIX_MACHINE_IDLE
-
-  // we enable more for the unix port
-
-#include <threads.h>
-#define CTX_FB                     1
-#define CTX_THREADS                1
-#define CTX_TERMINAL_EVENTS        1 
-#define CTX_TILED                  1
-#define CTX_FORMATTER              1
-#define CTX_PARSER                 1
-#define CTX_MATH                   1
-#define CTX_RAW_KB_EVENTS          1
-#define CTX_BRAILLE_TEXT           0
-#else
-#define CTX_RAW_KB_EVENTS          0
-#define CTX_MATH                   0
-#define CTX_TERMINAL_EVENTS        0 // gets rid of posix bits and bobs
-#define CTX_THREADS                0
-#define CTX_TILED                  0
-#define CTX_FORMATTER              0  // we want these eventually
-#define CTX_PARSER                 0  // enabled
-#define CTX_BRAILLE_TEXT           0
-
-#define CTX_BAREMETAL              1
-#endif
-
-
-#define CTX_EVENTS                 1
-#define CTX_MAX_DEVICES            1
-#define CTX_MAX_KEYBINDINGS       16
-#define CTX_RASTERIZER             1
-#define CTX_MAX_STATES             5
-#define CTX_MAX_EDGES            127
-#define CTX_MAX_PENDING           64
-#define CTX_MAX_CBS                8
-#define CTX_MAX_LISTEN_FDS         1
-
-#define CTX_ONE_FONT_ENGINE        1
-/* we keep the ctx implementation here, this compilation taget changes less
- * than the micropython target
- */
-
-#define CTX_STATIC_FONT(font) \
-  ctx_load_font_ctx(ctx_font_##font##_name, \
-                    ctx_font_##font,       \
-                    sizeof (ctx_font_##font))
-
-
-
-#define CTX_MAX_FONTS 10
-
-#if 0
-#include "Roboto-Regular.h"
-#include "Roboto-Bold.h"
-#include "Roboto-Italic.h"
-#include "Roboto-BoldItalic.h"
-#define CTX_FONT_0 CTX_STATIC_FONT(Roboto_Regular)
-#define CTX_FONT_1 CTX_STATIC_FONT(Roboto_Bold)
-#define CTX_FONT_2 CTX_STATIC_FONT(Roboto_Italic)
-//#define CTX_FONT_3 CTX_STATIC_FONT(Roboto_BoldItalic)
-#endif
-
-
-#if 1
-#include "Arimo-Regular.h"
-#include "Arimo-Bold.h"
-#include "Arimo-Italic.h"
-#include "Arimo-BoldItalic.h"
-#define CTX_FONT_0 CTX_STATIC_FONT(Arimo_Regular)
-#define CTX_FONT_1 CTX_STATIC_FONT(Arimo_Bold)
-#define CTX_FONT_2 CTX_STATIC_FONT(Arimo_Italic)
-#define CTX_FONT_3 CTX_STATIC_FONT(Arimo_BoldItalic)
-#endif
-
-#if 0
-#define CTX_FONT_4 CTX_STATIC_FONT(Roboto_Thin)
-#include "Roboto-Thin.h"
-#endif
-
-#if 0
-#include "Carlito-Regular.h"
-#include "Carlito-Bold.h"
-#include "Carlito-Italic.h"
-#include "Carlito-BoldItalic.h"
-#define CTX_FONT_5  CTX_STATIC_FONT(Carlito_Regular)
-#define CTX_FONT_6  CTX_STATIC_FONT(Carlito_Bold)
-#define CTX_FONT_7  CTX_STATIC_FONT(Carlito_Italic)
-#define CTX_FONT_8  CTX_STATIC_FONT(Carlito_BoldItalic)
-#endif
-
-
-#include "Tinos-Regular.h"
-#define CTX_FONT_13 CTX_STATIC_FONT(Tinos_Regular)
-//#include "Tinos-Bold.h"
-//#define CTX_FONT_14 CTX_STATIC_FONT(Tinos_Bold)
-
-#if 0
-#include "Tinos-Italic.h"
-#include "Tinos-BoldItalic.h"
-#define CTX_FONT_15 CTX_STATIC_FONT(Tinos_Italic)
-#define CTX_FONT_16 CTX_STATIC_FONT(Tinos_BoldItalic)
-#endif
-
-#if 0
-#include "Caladea-Regular.h"
-#include "Caladea-Bold.h"
-#include "Caladea-Italic.h"
-#define CTX_FONT_17 CTX_STATIC_FONT(Caladea_Regular)
-#define CTX_FONT_18 CTX_STATIC_FONT(Caladea_Bold)
-#define CTX_FONT_19 CTX_STATIC_FONT(Caladea_Italic)
-#if 0
-#include "Caladea-BoldItalic.h"
-#define CTX_FONT_20 CTX_STATIC_FONT(Caladea_BoldItalic)
-#endif
-#endif
-
-#if 1
-#include "Cousine-Regular.h"
-#include "Cousine-Bold.h"
-#define CTX_FONT_21 CTX_STATIC_FONT(Cousine_Regular)
-#define CTX_FONT_22 CTX_STATIC_FONT(Cousine_Bold)
-//#include "Cousine-Italic.h"
-//#include "Cousine-BoldItalic.h"
-//#define CTX_FONT_23 CTX_STATIC_FONT(Cousine_Italic)
-//#define CTX_FONT_24 CTX_STATIC_FONT(Cousine_BoldItalic)
-#endif
-
-#define CTX_IMPLEMENTATION
+#include "ctx_config.h"
 #include "ctx.h"
 
-typedef struct _mp_ctx_event_obj_t mp_ctx_event_obj_t;
 typedef struct _mp_ctx_obj_t {
 	mp_obj_base_t base;
 	Ctx *ctx;
-	//mp_ctx_event_obj_t *ctx_event;
 	mp_obj_t            user_data;
 } mp_ctx_obj_t;
 
@@ -220,18 +39,6 @@ void gc_collect(void);
 	}                                                                      \
 	MP_DEFINE_CONST_FUN_OBJ_1(mp_ctx_##name##_obj, mp_ctx_##name);
 
-#define MP_CTX_COMMON_FUN_0_idle(name)                                         \
-	static mp_obj_t mp_ctx_##name(mp_obj_t self_in)                        \
-	{                                                                      \
-		mp_ctx_obj_t *self = MP_OBJ_TO_PTR(self_in);                   \
-                gc_collect();\
-		ctx_##name(self->ctx);                                         \
-                mp_idle(0);\
-                while(ctx_get_event(self->ctx)){};\
-		return self_in;                                                \
-	}                                                                      \
-	MP_DEFINE_CONST_FUN_OBJ_1(mp_ctx_##name##_obj, mp_ctx_##name);
-
 #define MP_CTX_COMMON_FUN_1F(name)                                             \
 	static mp_obj_t mp_ctx_##name(mp_obj_t self_in, mp_obj_t arg1)         \
 	{                                                                      \
@@ -425,9 +232,8 @@ MP_CTX_COMMON_FUN_0(begin_path);
 MP_CTX_COMMON_FUN_0(save);
 MP_CTX_COMMON_FUN_0(restore);
 
-MP_CTX_COMMON_FUN_0(consume_events);
 MP_CTX_COMMON_FUN_0(start_frame);
-MP_CTX_COMMON_FUN_0_idle(end_frame);
+MP_CTX_COMMON_FUN_0(end_frame);
 
 MP_CTX_COMMON_FUN_0(start_group);
 MP_CTX_COMMON_FUN_0(end_group);
@@ -737,253 +543,8 @@ STATIC void generic_method_lookup(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
     }
 }
 
-extern const mp_obj_type_t mp_ctx_event_type;
-struct _mp_ctx_event_obj_t {
-	mp_obj_base_t base;
-	CtxEvent  event;
-        mp_obj_t  user_data;
-	mp_obj_t  mp_ev;
-};
-
-
-static mp_obj_t mp_ctx_event_new (void)
-{
-	mp_ctx_event_obj_t *o = m_new_obj(mp_ctx_event_obj_t);
-	o->base.type    = &mp_ctx_event_type;
-	return MP_OBJ_FROM_PTR(o);
-}
 extern const mp_obj_type_t mp_ctx_type;
 
-/** CtxEvent **/
-
-STATIC mp_obj_t
-mp_ctx_event_attr_op (mp_obj_t self_in, qstr attr, mp_obj_t set_val)
-{
-  mp_ctx_event_obj_t *self = MP_OBJ_TO_PTR(self_in);       
-  if (set_val == MP_OBJ_NULL) {
-    switch (attr)
-    {
-      case MP_QSTR_ctx:     
-        {
-	mp_ctx_obj_t *o = m_new_obj(mp_ctx_obj_t);
-	o->base.type    = &mp_ctx_type;
-        o->ctx = self->event.ctx;
-	return MP_OBJ_FROM_PTR(o);
-        }
-      case MP_QSTR_x:         return mp_obj_new_float(self->event.x);
-      case MP_QSTR_y:         return mp_obj_new_float(self->event.y);
-      case MP_QSTR_device_x:  return mp_obj_new_float(self->event.device_x);
-      case MP_QSTR_device_y:  return mp_obj_new_float(self->event.device_y);
-      case MP_QSTR_start_x:   return mp_obj_new_float(self->event.start_x);
-      case MP_QSTR_start_y:   return mp_obj_new_float(self->event.start_y);
-      case MP_QSTR_prev_x:    return mp_obj_new_float(self->event.prev_x);
-      case MP_QSTR_prev_y:    return mp_obj_new_float(self->event.prev_y);
-      case MP_QSTR_delta_x:   return mp_obj_new_float(self->event.delta_x);
-      case MP_QSTR_delta_y:   return mp_obj_new_float(self->event.delta_y);
-      case MP_QSTR_device_no: return mp_obj_new_int(self->event.device_no);
-      case MP_QSTR_unicode:   return mp_obj_new_int(self->event.unicode);
-      case MP_QSTR_user_data: return self->user_data;
-      case MP_QSTR_scroll_direction:  return mp_obj_new_int(self->event.scroll_direction);
-      case MP_QSTR_time:      return mp_obj_new_int(self->event.time);
-      case MP_QSTR_modifier_state:   return mp_obj_new_int(self->event.state);
-      case MP_QSTR_string:    if (self->event.string)
-                                 // gambling on validity
-                                 return mp_obj_new_str(self->event.string, strlen(self->event.string));
-                              else
-                                 return mp_obj_new_str("", 0);
-    }
-  }
-  else
-  {
-     return set_val;
-  }
-  return self_in;
-}
-
-STATIC void mp_ctx_event_attr(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
-
-    if(attr == MP_QSTR_x
-     ||attr == MP_QSTR_y
-     ||attr == MP_QSTR_ctx
-     ||attr == MP_QSTR_start_x
-     ||attr == MP_QSTR_start_y
-     ||attr == MP_QSTR_prev_x
-     ||attr == MP_QSTR_prev_y
-     ||attr == MP_QSTR_delta_x
-     ||attr == MP_QSTR_delta_y
-     ||attr == MP_QSTR_device_no
-     ||attr == MP_QSTR_unicode
-     ||attr == MP_QSTR_user_data
-     ||attr == MP_QSTR_scroll_direction
-     ||attr == MP_QSTR_time
-     ||attr == MP_QSTR_modifier_state
-     ||attr == MP_QSTR_string
-     ||attr == MP_QSTR_device_x
-     ||attr == MP_QSTR_device_y)
-    {
-        if (dest[0] == MP_OBJ_NULL) {
-            // load attribute
-            mp_obj_t val = mp_ctx_event_attr_op(obj, attr, MP_OBJ_NULL);
-            dest[0] = val;
-        } else {
-            // delete/store attribute
-            if (mp_ctx_event_attr_op(obj, attr, dest[1]) != MP_OBJ_NULL)
-                dest[0] = MP_OBJ_NULL; // indicate success
-        }
-    }
-    else {
-        // A method call
-        generic_method_lookup(obj, attr, dest);
-    }
-}
-
-static const mp_rom_map_elem_t mp_ctx_event_locals_dict_table[] = {
-       MP_CTX_ATTR(x),
-       MP_CTX_ATTR(y),
-       MP_CTX_ATTR(ctx),
-       MP_CTX_ATTR(device_x),
-       MP_CTX_ATTR(device_y),
-       MP_CTX_ATTR(start_x),
-       MP_CTX_ATTR(start_y),
-       MP_CTX_ATTR(prev_x),
-       MP_CTX_ATTR(prev_y),
-       MP_CTX_ATTR(delta_x),
-       MP_CTX_ATTR(delta_y),
-       MP_CTX_ATTR(device_no),
-       MP_CTX_ATTR(unicode),
-       MP_CTX_ATTR(user_data),
-       MP_CTX_ATTR(scroll_direction),
-       MP_CTX_ATTR(time),
-       MP_CTX_ATTR(modifier_state),
-       MP_CTX_ATTR(string)
-};
-static MP_DEFINE_CONST_DICT(mp_ctx_event_locals_dict, mp_ctx_event_locals_dict_table);
-
-static mp_obj_t mp_ctx_event_make_new(
-	const mp_obj_type_t *type,
-	size_t n_args,
-	size_t n_kw,
-	const mp_obj_t *args
-) {
-	mp_ctx_event_obj_t *o = m_new_obj(mp_ctx_event_obj_t);
-	o->base.type    = type;
-	return MP_OBJ_FROM_PTR(o);
-}
-
-MP_DEFINE_CONST_OBJ_TYPE(
-    mp_ctx_event_type,
-    MP_QSTR_ctx_event_type,
-    MP_TYPE_FLAG_NONE,
-    //print, array_print,
-    make_new, mp_ctx_event_make_new,
-    attr, mp_ctx_event_attr,
-    locals_dict, &mp_ctx_event_locals_dict
-);
-
-/*
-const mp_obj_type_t mp_ctx_event_type = {
-	.base        = { &mp_type_type },
-	.name        = MP_QSTR_CtxEvent,
-	.make_new    = mp_ctx_event_make_new,
-	.locals_dict = (mp_obj_t)&mp_ctx_event_locals_dict,
-        .attr = mp_ctx_event_attr
-};
-*/
-
-static void mp_ctx_listen_cb_handler (CtxEvent *event, void *data1, void*data2)
-{
-  mp_obj_t event_in = data2;
-  mp_ctx_event_obj_t *mp_ctx_event = MP_OBJ_TO_PTR(event_in);
-  mp_ctx_event->event = *event; // XXX todo stop copying, make stop_propagate work
-  mp_call_function_1(data1, event_in);
-}
-
-static void mp_ctx_listen_cb_handler_stop_propagate (CtxEvent *event, void *data1, void*data2)
-{
-  mp_obj_t event_in = data2;
-  mp_ctx_event_obj_t *mp_ctx_event = MP_OBJ_TO_PTR(event_in);
-  mp_ctx_event->event = *event;
-  mp_call_function_1(data1, event_in);
-  event->stop_propagate = 1;
-}
-
-static mp_obj_t mp_ctx_listen (size_t n_args, const mp_obj_t *args)
-{
-  mp_obj_t self_in = args[0];
-  mp_obj_t event_mask = args[1];
-  mp_obj_t cb_in = args[2];
-  mp_obj_t user_data_in = n_args==4?args[3]:mp_const_none;
-  mp_ctx_obj_t *self = MP_OBJ_TO_PTR(self_in);
-  if (cb_in != mp_const_none &&
-      !mp_obj_is_callable(cb_in))
-          mp_raise_ValueError(MP_ERROR_TEXT("invalid handler"));
-  mp_ctx_event_obj_t *ctx_event = mp_ctx_event_new ();
-  ctx_event->user_data = user_data_in;
-  ctx_listen (self->ctx,
-              mp_obj_get_int(event_mask),
-              mp_ctx_listen_cb_handler,
-              (cb_in), ctx_event);
-  return MP_OBJ_FROM_PTR(self);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_ctx_listen_obj, 3, 4, mp_ctx_listen);
-
-static void mp_ctx_key_binding_cb_handler (CtxEvent *event, void *data1, void*data2)
-{
-  mp_ctx_event_obj_t *ctx_event = mp_ctx_event_new ();
-  //mp_ctx_event_obj_t *mp_ctx_event = MP_OBJ_TO_PTR(event_in);
-  ctx_event->event = *event;
-#if 0
-  mp_sched_schedule (data1, event_in);
-#else
-  mp_call_function_1(data1, ctx_event);
-#endif
-}
-
-static mp_obj_t mp_ctx_add_key_binding (size_t n_args, const mp_obj_t *args)
-{
-  mp_obj_t self_in    = args[0];
-  mp_obj_t key_in     = args[1];
-  mp_obj_t action_in  = args[2];
-  mp_obj_t label_in   = args[3];
-  mp_obj_t cb_in      = args[4];
-  //mp_obj_t user_data_in = args[5];
-  mp_ctx_obj_t *self = MP_OBJ_TO_PTR(self_in);
-  if (cb_in != mp_const_none &&
-      !mp_obj_is_callable(cb_in))
-          mp_raise_ValueError(MP_ERROR_TEXT("invalid handler"));
-  ctx_add_key_binding (self->ctx,
-              mp_obj_str_get_str(key_in),
-              mp_obj_str_get_str(action_in),
-              mp_obj_str_get_str(label_in),
-              mp_ctx_key_binding_cb_handler,
-              (cb_in));//, ctx_event);
-  return MP_OBJ_FROM_PTR(self);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_ctx_add_key_binding_obj, 5, 5, mp_ctx_add_key_binding);
-
-
-static mp_obj_t mp_ctx_listen_stop_propagate (size_t n_args, const mp_obj_t *args)
-{
-  mp_obj_t self_in = args[0];
-  mp_obj_t event_mask = args[1];
-  mp_obj_t cb_in = args[2];
-  mp_obj_t user_data_in = n_args==4?args[3]:mp_const_none;
-  mp_ctx_obj_t *self = MP_OBJ_TO_PTR(self_in);
-  if (cb_in != mp_const_none &&
-      !mp_obj_is_callable(cb_in))
-          mp_raise_ValueError(MP_ERROR_TEXT("invalid handler"));
-  mp_ctx_event_obj_t *ctx_event = mp_ctx_event_new ();
-  ctx_event->user_data = user_data_in;
-  ctx_listen (self->ctx,
-              mp_obj_get_int(event_mask),
-              mp_ctx_listen_cb_handler_stop_propagate,
-              (cb_in), ctx_event);
-  return MP_OBJ_FROM_PTR(self);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_ctx_listen_stop_propagate_obj, 3, 4, mp_ctx_listen_stop_propagate);
-
-
-
 #if CTX_TINYVG
 static mp_obj_t mp_ctx_tinyvg_get_size (mp_obj_t self_in, mp_obj_t buffer_in)
 {
@@ -1145,9 +706,6 @@ mp_ctx_attr_op (mp_obj_t self_in, qstr attr, mp_obj_t set_val)
        case MP_QSTR_flags:
             return mp_obj_new_int(ctx_cb_get_flags (self->ctx));
 
-       case MP_QSTR_need_redraw:
-            return mp_obj_new_bool(ctx_need_redraw (self->ctx));
-
        case MP_QSTR_line_cap:
             return mp_obj_new_int(ctx_get_line_cap (self->ctx));
        case MP_QSTR_line_join:
@@ -1196,8 +754,6 @@ mp_ctx_attr_op (mp_obj_t self_in, qstr attr, mp_obj_t set_val)
          ctx_line_cap (self->ctx, mp_obj_get_int (set_val)); break;
        case MP_QSTR_flags:
          ctx_cb_set_flags (self->ctx, mp_obj_get_int (set_val)); break;
-       case MP_QSTR_need_redraw:
-         ctx_queue_draw (self->ctx); break;
        case MP_QSTR_line_join:
          ctx_line_join (self->ctx, mp_obj_get_int (set_val)); break;
        case MP_QSTR_text_align:
@@ -1244,7 +800,6 @@ STATIC void mp_ctx_attr(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
      ||attr == MP_QSTR_compositing_mode
 #endif
      ||attr == MP_QSTR_flags
-     ||attr == MP_QSTR_need_redraw
      ||attr == MP_QSTR_line_cap
      ||attr == MP_QSTR_line_join
      ||attr == MP_QSTR_text_align
@@ -1320,11 +875,7 @@ static const mp_rom_map_elem_t mp_ctx_locals_dict_table[] = {
 	MP_CTX_METHOD(save),
 	MP_CTX_METHOD(restore),
 	MP_CTX_METHOD(start_frame),
-	//MP_CTX_METHOD(consume_events),
 	MP_CTX_METHOD(end_frame),
-	MP_CTX_METHOD(add_key_binding),
-	MP_CTX_METHOD(listen),
-	MP_CTX_METHOD(listen_stop_propagate),
 	MP_CTX_METHOD(get_font_name),
 
         MP_CTX_METHOD(gray),
@@ -1341,16 +892,6 @@ static const mp_rom_map_elem_t mp_ctx_locals_dict_table[] = {
 #endif
 	MP_CTX_METHOD(logo),
 
-        MP_CTX_METHOD(pointer_motion),
-        MP_CTX_METHOD(pointer_release),
-        MP_CTX_METHOD(pointer_press),
-        MP_CTX_METHOD(scrolled),
-        MP_CTX_METHOD(key_press),
-        MP_CTX_METHOD(key_up),
-        MP_CTX_METHOD(key_down),
-        MP_CTX_METHOD(incoming_message),
-
-
         // Instance attributes
         MP_CTX_ATTR(x),
         MP_CTX_ATTR(y),
@@ -1362,7 +903,6 @@ static const mp_rom_map_elem_t mp_ctx_locals_dict_table[] = {
         MP_CTX_ATTR(compositing_mode),
         MP_CTX_ATTR(blend_mode),
 #endif
-        MP_CTX_ATTR(need_redraw),
         MP_CTX_ATTR(flags),
         MP_CTX_ATTR(line_cap),
         MP_CTX_ATTR(line_join),
@@ -1506,7 +1046,6 @@ const mp_obj_type_t mp_ctx_type = {
 static const mp_rom_map_elem_t mp_ctx_module_globals_table[] = {
 	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ctx_module) },
 	{ MP_ROM_QSTR(MP_QSTR_Context), MP_ROM_PTR(&mp_ctx_type) },
-	{ MP_ROM_QSTR(MP_QSTR_CtxEvent), MP_ROM_PTR(&mp_ctx_event_type) },
 
 	MP_CTX_INT_CONSTANT(FORMAT,GRAY8),
 	MP_CTX_INT_CONSTANT(FORMAT,GRAYA8),
diff --git a/usermodule/uctx/examples/332pal.py b/usermodule/uctx/examples/332pal.py
deleted file mode 100755
index 36688a0e0a..0000000000
--- a/usermodule/uctx/examples/332pal.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env uctx
-
-import uimui
-exit=False
-while not exit:
-  uimui.start_frame()
-  uimui.label("foo")
-  valid_red=(0,40,80,140,174,209,233,255)  # 176
-  valid_green=(0,40,80,140,174,209,233,255)  # 176
-  valid_blue=(0,80,140,255)    
-
-  ctx = uimui.get_ctx()
-  y = 0
-  x = 0
-  dim = ctx.width / (36)
-  for green in valid_green:
-     for red in valid_red:
-         for blue in valid_blue:
-              real_blue = blue | (green &31) # mix in low bits of green
-              ctx.rectangle(x, y, dim, dim).rgb(red/255,green/255,real_blue/255).fill()
-              x += dim
-              if x + dim >= ctx.width:
-                  x = 0
-                  y += dim
-  if uimui.button("X", x= 0, y =0, width = ctx.width/10):
-    exit = True  
-  uimui.end_frame()
diff --git a/usermodule/uctx/examples/Calculator.py b/usermodule/uctx/examples/Calculator.py
deleted file mode 100755
index a9c8ad4370..0000000000
--- a/usermodule/uctx/examples/Calculator.py
+++ /dev/null
@@ -1,242 +0,0 @@
-#!/usr/bin/env uctx
-
-import canvas
-import micropython
-import gc
-
-class Calculator:
-    def __init__(self):
-        True
-    
-    def foo(self):
-        print("fooed")
-
-
-calc=Calculator()
-calc.foo()
-ctx=canvas.ctx
-o=ctx
-
-ctx.flags = ctx.HASH_CACHE | ctx.INTRA_UPDATE
-
-pointer_x = 0
-pointer_y = 0
-pointer_down = False
-
-pointer_was_down = False
-
-widget_font_size_vh = 0.12
-widget_bg=[70/255,70/255,90/255]
-widget_fg=[1.0,1.0,1.0]
-widget_marker=[1.0,0,0]
-widget_fs=0.1
-
-button_bg=widget_bg
-button_fg=widget_fg
-button_bg_active=widget_bg#[200,20,100]
-
-def inside_rect(u,v,x,y,w,h):
-    if u >= x and  u < x + w and v >= y and v < y + h:
-      return True
-    return False
-
-def button(x, y, w, h, label):
-    global pointer_down, pointer_was_down
-    result = False
-    ctx.font_size = ctx.height * widget_font_size_vh # why do we need this override
-    lwidth = ctx.text_width (label)
-    ctx.rectangle(x, y, w, h)
-    ctx.rgb(*button_bg)
-    if pointer_down and pointer_was_down == False and inside_rect(pointer_x,pointer_y,x,y,w,h):
-      result = True
-      ctx.rgb(*button_bg_active)    
-    ctx.fill()
-    ctx.rgb(*button_fg)
-    ctx.move_to(x + w/2-lwidth/2, y + h/2 + ctx.font_size/3)
-    ctx.text(label)
-    return result
-
-def toggle(x, y, w, h, label, value):
-    global pointer_down, pointer_was_down
-    result = value
-    ctx.font_size = ctx.height * widget_font_size_vh # why do we need this override
-    
-    if pointer_down and pointer_was_down == False and inside_rect(pointer_x,pointer_y,x,y,w,h):
-      result = not value
-      ctx.rectangle(x, y, w, h).rgb(*button_bg_active).fill()
-
-    ctx.rgb(*widget_fg)
-    ctx.move_to(x + ctx.font_size*0.1, y + ctx.font_size*0.8)
-    ctx.text(label)
-    ctx.save()
-    ctx.text_align=ctx.RIGHT
-    ctx.move_to(x+w,y+ctx.font_size*0.8)
-    if value:
-        ctx.text("on")
-    else:
-        ctx.text("off")
-    ctx.restore()
-
-    return value
-
-
-def coords_press(x, y):
-    global pointer_x, pointer_y, pointer_down
-    pointer_x = x
-    pointer_y = y
-    pointer_down = True
-
-def coords_motion(x, y):
-    global pointer_x, pointer_y
-    pointer_x = x
-    pointer_y = y
-
-def coords_release(x, y):
-    global pointer_x, pointer_y, pointer_down
-    pointer_x = x
-    pointer_y = y
-    pointer_down = False
-
-exit = False
-need_clear = True
-frame_no = 0
-value = 0
-accumulator = 0
-op = ""
-in_decimal = 0  # higher than zero means were in decimals at that digit
-hex_mode = False
-
-def compute_op():
-    global need_clear,value, accumulator, op, in_decimals
-    if op == '+':
-      value = accumulator + value
-      accumulator = 0
-    if op == '-':
-      value = accumulator - value
-      accumulator = 0
-    if op == 'x':
-      value = accumulator * value
-      accumulator = 0
-    if op == '/':
-      if value != 0.0:
-         value = accumulator / value
-      else:
-         value = -0.0
-      accumulator = 0
-    op = ''
-    need_clear = True
-
-def calc_loop():
-    global hex_mode,need_clear,value, accumulator, in_decimal, op, exit, pointer_was_down, pointer_down
-    bw = ctx.width * 0.13
-    bh = ctx.height * 0.19
-    bsx = ctx.width * 0.14
-    bsy = ctx.height * 0.2
-    ctx.start_frame()
-    ctx.translate(0,20)
-    ctx.rectangle(0,0,ctx.width, ctx.height)#,ctx.height)
-    o.listen(o.PRESS, lambda e:coords_press(e.x, e.y))
-    o.listen(o.MOTION, lambda e:coords_motion(e.x, e.y))
-    o.listen(o.RELEASE, lambda e:coords_release(e.x, e.y))
-    
-    ctx.gray(0).fill()
-
-    ctx.font_size = ctx.height * widget_font_size_vh
-    ctx.rgb(*widget_fg)
-    
-    ctx.text_align = ctx.RIGHT
-    ctx.move_to(bsx*6,ctx.font_size*0.8)
-    if hex_mode:
-      value = int(value)
-      ctx.text(hex(value))
-    else:
-      ctx.text(str(value))
-    ctx.text_align = ctx.LEFT
-
-    if accumulator != 0:
-        ctx.move_to(0,ctx.font_size*0.8)
-        ctx.text(str(accumulator) + " " + op)
-
-
-    for digit in range(1,10):
-      if button((((digit-1)%3)+1) * bsx, (3-int((digit-1)/3)) * bsy, bw, bh, str(digit)):
-        if need_clear:
-            value = 0
-        need_clear = False
-        if in_decimal>0:
-            value = value + 1.0/pow(10,in_decimal)*digit
-            in_decimal+=1
-        else:
-            value = value * 10 + digit
-    if button(0 * bsx, 3 * bsy, bw, bh, "0"):
-        if need_clear:
-           value = 0
-        need_clear = False
-
-        if in_decimal>0:
-            value = value + 0.0
-        else:
-            value = value * 10 + 0
-        
-    if button(0 * bsx, 2 * bsy, bw, bh, "."):
-        in_decimal = 1
-    if button(4 * bsx, 3 * bsy, bw * 1.5, bh, "="):
-        compute_op()
-        
-    if button(5 * bsx, 1 * bsy, bw, bh, "/"):
-        compute_op()
-        accumulator = value
-        value = 0
-        op = "/"
-        in_decimal = 0
-    if button(6 * bsx, 2 * bsy, bw, bh, "sqrt"):
-        value = pow(value, 0.5)
-        op = ""
-        need_clear = 1
-        in_decimal = 0
-
-    if hex_mode:
-      if button(6 * bsx, 1 * bsy, bw, bh, "hex"):
-        hex_mode = False
-    else:
-      if button(6 * bsx, 1 * bsy, bw, bh, "dec"):
-        hex_mode = True
-
-    if button(5.5 * bsx, 3 * bsy, 1.5 * bw, bh, "C"):
-        value = 0
-        accumulator = 0
-        in_decimal = 0
-    if button(4 * bsx, 2 * bsy, bw, bh, "+"):
-        compute_op()
-        accumulator = value
-        value = 0
-        op = "+"
-        in_decimal = 0
-    if button(5 * bsx, 2 * bsy, bw, bh, "x"):
-        compute_op()        
-        accumulator = value
-        value = 0
-        op = "x"
-        in_decimal = 0
-    if button(4 * bsx, 1 * bsy, bw, bh, "-"):
-        compute_op()
-        accumulator = value
-        value = 0
-        op = "-"
-        in_decimal = 0
-    if button(0, 1 * bsy, bw, bh, "q"):
-        exit = True
-    
-    #ctx.rectangle(pointer_x-2, pointer_y-2, 4, 4).color([255,0,0]).fill()
-    pointer_was_down = pointer_down # must happen after all the buttons
-    #micropython.mem_info()
-    ctx.end_frame()
-    gc.collect()    
-    
-import micropython
-    
-while not exit:
-    calc_loop()
-    #micropython.mem_info(1)
-
-
diff --git a/usermodule/uctx/examples/canvas.py b/usermodule/uctx/examples/canvas.py
deleted file mode 100755
index ed978cf72f..0000000000
--- a/usermodule/uctx/examples/canvas.py
+++ /dev/null
@@ -1,300 +0,0 @@
-#!/usr/bin/env uctx
-
-import os
-import sys
-import ctx as modctx
-
-_ctx = None
-
-# this is the function exposed to the outside
-def get_ctx(): 
-  global _ctx
-  if _ctx != None:  # we try to only run once
-      return _ctx
-
-  if sys.platform == 'linux':
-    _ctx = unix_get_ctx ()
-  elif sys.platform == 'javascript':
-    _ctx = wasm_get_ctx ()
-  else:
-    print('you need to configure a display config for ctx in canvas.py')
-
-    #_ctx = rp_pico_waveshare_240x240_joystick()
-    _ctx = rp_pico_waveshare_480x320_res_touch()
-    #_ctx = rp_pico_waveshare_240x320_res_touch()
-    #_ctx = esp32_waveshare_320x240()
-
-    #_ctx = dummy_get_ctx ()
-  return _ctx
-
-# The canvas module provides backend integration and configuration for
-# ctx, by importing canvas.
-
-scratch_size = 53 * 1024
-    # for the cb backend used on microcontrollers, how much heap
-    # to use for a scratch compositing buffer.
-    # For a 480x320 display:
-    #   14kb is enough for 2x2 GRAY2
-    #                      5x5 LOWRES
-    #   23kb is enough for 2x2 GRAY4 
-    #                      3x3 RGB332
-    #                      4x4 LOWRES
-    #                      1x1 GRAY1  (not currently available)
-    #   42kb is enough for 2x2 RGB332
-    #                      1x1 GRAY2
-    #                      3x3 LOWRES
-
-canvas_flags = modctx.INTRA_UPDATE|modctx.LOWFI
-    # the default flags the cb backend gets initialized with
-    # possible values:
-    #   INTRA_UPDATE : call the event handling between renders in hifi mode
-    #   HASH_CACHE   : keep track of rendered content and only re-render changed areas
-    #   LOWFI        : do preview rendering with RGB565
-    #   RGB332       : trade color fidelity for higher res preview
-    #   GRAY8        : full grayscale
-    #   GRAY4        : 16 level gray
-    #   GRAY2        : 4 level gray
-    #   CBRLE        : constant bitrate RLE
-
-# when non-zero override board default
-canvas_width  = 0
-canvas_height = 0
-
-##### end of basic configuration ###########
-############################################
-############################################
-
-pointer_down = False
-pointer_x = 0
-pointer_y = 0
-
-# this is currently used by one of the backends
-# adding gpio based input for more boards should
-# follow the same pattern
-
-keys={}
-key_state={}
-def get_pin_events(ctx):
-    ret = False
-    for name,pin in keys.items():
-       if pin.value()== 0:
-           if key_state[name] != 0:
-               key_state[name]=0
-               ctx.key_down(0, name, 0)
-               ctx.key_press(0, name, 0)
-               ret = True
-       else:
-          if key_state[name] != 1:
-               ctx.key_up(0, name, 0)
-               key_state[name]=1
-               ret = True
-    return ret
-
-
-def rp_waveshare_240x240_joystick():
-    import machine
-    from machine import Pin,SPI,PWM
-    global keys,key_state,canvas_width, canvas_height
-    machine.freq(266_000_000)
-
-
-    keys['a']= Pin(15,Pin.IN,Pin.PULL_UP)
-    keys['b'] = Pin(17,Pin.IN,Pin.PULL_UP)
-    keys['x'] = Pin(19 ,Pin.IN,Pin.PULL_UP)
-    keys['y'] = Pin(21 ,Pin.IN,Pin.PULL_UP)
-    
-    keys['up'] = Pin(2,Pin.IN,Pin.PULL_UP)
-    keys['down'] = Pin(18,Pin.IN,Pin.PULL_UP)
-    keys['left'] = Pin(16,Pin.IN,Pin.PULL_UP)
-    keys['right'] = Pin(20,Pin.IN,Pin.PULL_UP)
-    keys['space'] = Pin(3,Pin.IN,Pin.PULL_UP)
-
-    for key,value in keys.items():
-       key_state[key]=1
-        
-    import lcd13
-    import machine
-    display=lcd13.LCD_1inch3()
-    
-    if canvas_width == 0:
-        canvas_width = 240
-    if canvas_height == 0:
-        canvas_height = 240
-
-    ret_ctx = modctx.Context(
-      width=canvas_width,
-      height=canvas_height,
-      format=modctx.RGB565_BYTESWAPPED,
-      # function to update a subregion of target framebuffer using prepared buf
-      # with appropriate stride
-      set_pixels=lambda x, y, w, h, buf: display.blit_buffer(buf, x, y, w, h),
-      update=lambda:get_pin_events (ret_ctx),
-      memory_budget=scratch_size,
-      flags=canvas_flags)
-    return ret_ctx
-def update_events(lcd):
-   global pointer_down, pointer_x, pointer_y
-   touch=lcd.touch_get()
-   if(touch):
-      pointer_x=touch[0]
-      pointer_y=touch[1]
-      if not pointer_down:
-         _ctx.pointer_press(pointer_x,pointer_y, 0, 0)
-      else:
-         _ctx.pointer_motion(pointer_x,pointer_y, 0, 0)
-      pointer_down = True
-      return True # abort rendering if in slow refresh
-   else:
-      if pointer_down:
-         _ctx.pointer_release(pointer_x,pointer_y, 0, 0)
-         pointer_down = False
-         return True
-      return False
-
-def rp_pico_waveshare_480x320_res_touch():
-    global canvas_width, canvas_height
-    import ililcd
-    lcd=ililcd.LCD()#480, 320, 15, 8, 9, 10, 11, 12, 13)
-    if canvas_width == 0:
-        canvas_width = 480
-    if canvas_height == 0:
-        canvas_height = 320
-
-    return modctx.Context(
-      width=canvas_width,
-      height=canvas_height,
-                             
-      # the format specified here is the format of the lcd
-      # not neccesarily the format used for rendering
-      format=modctx.RGB565_BYTESWAPPED,
-
-      # function to update a subregion of target framebuffer using prepared buf
-      # with appropriate stride
-      set_pixels=lambda x, y, w, h, buf: lcd.blit_buffer(buf, x, y, w, h),
-                             
-      # callback to be invoked in between batches of render+blit
-      # if True is returned progressive updates are aborted
-      # this is where touch events and button presses should be fed
-      # to ctx
-      update=lambda : update_events(lcd),
-      memory_budget=scratch_size,
-      flags=canvas_flags)
-
-def dummy_get_ctx():
-    global canvas_width, canvas_height
-    if canvas_width == 0:
-        canvas_width = 240
-    if canvas_height == 0:
-        canvas_height = 240
-
-    return modctx.Context(
-      width=canvas_width,
-      height=canvas_height,
-      format=modctx.RGB565_BYTESWAPPED,
-      # function to update a subregion of target framebuffer using prepared buf
-      # with appropriate stride
-      set_pixels = lambda x, y, w, h, buf: True,
-      update= lambda : False,
-      memory_budget=scratch_size,
-      flags=canvas_flags)
-
-def esp32_waveshare_320x240():
-    import st7789py
-    import machine    
-    machine.freq(240_000_000) # we want full tilt!
-    spi = machine.SPI(2, baudrate=40000000, polarity=1)
-    display = st7789py.ST7789(
-        spi, 240, 320,
-        reset=machine.Pin(17, machine.Pin.OUT),
-        dc=machine.Pin(16, machine.Pin.OUT),
-        cs=machine.Pin(5, machine.Pin.OUT),
-        xstart=0,ystart=0
-    )
-    display.init()
-    display.inversion_mode(False)
-
-    if canvas_width == 0:
-        canvas_width = 240
-    if canvas_height == 0:
-        canvas_height = 320
-
-    return modctx.Context(
-      width=canvas_width,
-      height=canvas_height,
-      format=modctx.RGB565_BYTESWAPPED,
-      # function to update a subregion of target framebuffer using prepared buf
-      # with appropriate stride
-      set_pixels = lambda x, y, w, h, buf: display.blit_buffer(buf, x, y, w, h),
-      update= lambda : False,
-      memory_budget=scratch_size,
-      flags=canvas_flags)
-  
-def rp_pico_waveshare_240x320_res_touch():
-    global canvas_width, canvas_height
-    import st7789py
-    import time, machine
-    machine.Pin(13,machine.Pin.OUT).low()
-    spi = machine.SPI(1, baudrate=50000000, phase=1,polarity=1)
-    display = st7789py.ST7789(spi, 240, 320,
-        reset=machine.Pin(15, machine.Pin.OUT),
-        backlight=machine.Pin(13, machine.Pin.OUT),
-        sck=10,#machine.Pin(10, machine.Pin.OUT),        
-        mosi=11,
-        miso=12,
-        dc=machine.Pin(8, machine.Pin.OUT),
-        cs=machine.Pin(9, machine.Pin.OUT),xstart=0,ystart=0,tp_irq=17,tp_cs=18)
-    display.init()
-    if canvas_width == 0:
-        canvas_width = 240
-    if canvas_height == 0:
-        canvas_height = 320
-    
-    return modctx.Context(
-      width=canvas_width,
-      height=canvas_height,
-      format=modctx.RGB565_BYTESWAPPED,
-      # function to update a subregion of target framebuffer using prepared buf
-      # with appropriate stride
-      set_pixels=lambda x, y, w, h, buf: display.blit_buffer(buf, x, y, w, h),
-      update = lambda : update_events(display),
-      memory_budget=scratch_size,
-      flags=canvas_flags)
-
-def reset_terminal():
-    os.system('reset')
-
-def unix_get_ctx():  # perhaps turn this into an attribute of the module?
-  print("\e[H\e[2J")
-  sys.atexit(reset_terminal)
-  return modctx.Context()
-
-def wasm_get_ctx():
-  ctx = modctx.Context(memory_budget=scratch_size)
-  ctx.flags=canvas_flags
-  return ctx
-
-def __getattr__(name):
-    if name == 'ctx2d':
-        return get_ctx()    
-    elif name == 'ctx':
-        return get_ctx()
-    elif name == 'width':
-        return get_ctx().width
-    elif name == 'height':
-        return get_ctx().height
-    raise AttributeError("module '{__name__}' has no attribute '{name}'")
-
-if __name__=='__main__':
-    ctx = get_ctx()
-    frames=60
-    for frame in range(0,frames):
-      ctx.start_frame()
-      ctx.rgb(50/255,50/255,30/255).rectangle(0,0,ctx.width,ctx.height).fill()
-      dim = ctx.height * frame / (frames-2.0)
-      if frame >= frames-2:
-        dim = ctx.height
-      ctx.logo(ctx.width/2,ctx.height/2, dim)
-      ctx.end_frame()
-
-
-
diff --git a/usermodule/uctx/examples/fonts.py b/usermodule/uctx/examples/fonts.py
deleted file mode 100755
index 428cb18d25..0000000000
--- a/usermodule/uctx/examples/fonts.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env uctx
-import canvas
-ctx = canvas.get_ctx()
-
-ctx.flags=0
-
-frames=400
-for frame in range(0,frames):
-        ctx.start_frame()
-        ctx.rgb(50/255,50/255,30/255).rectangle(0,0,ctx.width,ctx.height).fill()
-        dim = ctx.height * frame / (frames-2.0)
-        ctx.rgb(1.0,1.0,1.0)
-        ctx.font_size= ctx.height * 0.15
-        ctx.save()
-        ctx.translate(0,-frame/frames * ctx.height *2.5)
-        ctx.move_to(0,ctx.height)
-        ctx.rgba(1.0,0.0,0.0, .85)
-
-        for font in ('Sans','Regular',
-                     'Sans Bold','Bold',
-                     "Courier Italic",
-                     'Times',
-                     'Mono',
-                     'Arial Bold',
-                     'Foobar Bold Italic',
-                     'Helvetica Bold',
-                     'Mono Bold',
-                     'Mono Italic',
-                     'Bold Italic', 
-                     'Times Italic'):
-          ctx.font=font
-          ctx.text(font+'\n')
-
-        ctx.rgba(1.0,1.0,1.0, .85)
-        
-        font_no = 0 
-        
-        while ctx.get_font_name(font_no) != None:
-          font = ctx.get_font_name(font_no)
-          font_no+=1
-          ctx.font=font
-          ctx.text(font+"\n")
-
-          dim=ctx.height
-        ctx.restore()
-        ctx.end_frame()
-
-
diff --git a/usermodule/uctx/examples/ililcd.py b/usermodule/uctx/examples/ililcd.py
deleted file mode 100644
index a4895ceb63..0000000000
--- a/usermodule/uctx/examples/ililcd.py
+++ /dev/null
@@ -1,183 +0,0 @@
-from machine import Pin,SPI,PWM
-import framebuf
-import time
-import os
-
-LCD_DC   = 8
-LCD_CS   = 9
-LCD_SCK  = 10
-LCD_MOSI = 11
-LCD_MISO = 12
-LCD_BL   = 13
-LCD_RST  = 15
-TP_CS    = 16
-TP_IRQ   = 17
-
-class LCD():
-
-    def __init__(self):
-        self.RED   =   0x07E0
-        self.GREEN =   0x001f
-        self.BLUE  =   0xf800
-        self.WHITE =   0xffff
-        self.BLACK =   0x0000
-        
-        self.width = 480
-        self.height = 160
-        
-        self.cs = Pin(LCD_CS,Pin.OUT)
-        self.rst = Pin(LCD_RST,Pin.OUT)
-        self.dc = Pin(LCD_DC,Pin.OUT)
-        
-        self.tp_cs =Pin(TP_CS,Pin.OUT)
-        self.irq = Pin(TP_IRQ,Pin.IN)
-        
-        self.cs(1)
-        self.dc(1)
-        self.rst(1)
-        self.tp_cs(1)
-        self.spi = SPI(1,60_000_000,sck=Pin(LCD_SCK),mosi=Pin(LCD_MOSI),miso=Pin(LCD_MISO))
-              
-        self.init_display()
-
-        
-    def write_cmd(self, cmd):
-        self.cs(1)
-        self.dc(0)
-        self.cs(0)
-        self.spi.write(bytearray([cmd]))
-        self.cs(1)
-
-    def write_data(self, buf):
-        self.cs(1)
-        self.dc(1)
-        self.cs(0)
-        #self.spi.write(bytearray([0X00]))
-        self.spi.write(bytearray([buf]))
-        self.cs(1)
-
-
-    def init_display(self):
-        """Initialize dispaly"""  
-        self.rst(1)
-        time.sleep_ms(5)
-        self.rst(0)
-        time.sleep_ms(10)
-        self.rst(1)
-        time.sleep_ms(5)
-        self.write_cmd(0x21)
-        self.write_cmd(0xC2)
-        self.write_data(0x33)
-        self.write_cmd(0XC5)
-        self.write_data(0x00)
-        self.write_data(0x1e)
-        self.write_data(0x80)
-        self.write_cmd(0xB1)
-        self.write_data(0xB0)
-        self.write_cmd(0x36)
-        self.write_data(0x28)
-        self.write_cmd(0XE0)
-        self.write_data(0x00)
-        self.write_data(0x13)
-        self.write_data(0x18)
-        self.write_data(0x04)
-        self.write_data(0x0F)
-        self.write_data(0x06)
-        self.write_data(0x3a)
-        self.write_data(0x56)
-        self.write_data(0x4d)
-        self.write_data(0x03)
-        self.write_data(0x0a)
-        self.write_data(0x06)
-        self.write_data(0x30)
-        self.write_data(0x3e)
-        self.write_data(0x0f)
-        self.write_cmd(0XE1)
-        self.write_data(0x00)
-        self.write_data(0x13)
-        self.write_data(0x18)
-        self.write_data(0x01)
-        self.write_data(0x11)
-        self.write_data(0x06)
-        self.write_data(0x38)
-        self.write_data(0x34)
-        self.write_data(0x4d)
-        self.write_data(0x06)
-        self.write_data(0x0d)
-        self.write_data(0x0b)
-        self.write_data(0x31)
-        self.write_data(0x37)
-        self.write_data(0x0f)
-        self.write_cmd(0X3A)
-        self.write_data(0x55)
-        self.write_cmd(0x11)
-        time.sleep_ms(120)
-        self.write_cmd(0x29)
-        
-        self.write_cmd(0xB6)
-        self.write_data(0x00)
-        self.write_data(0x62)
-        
-        self.write_cmd(0x36)
-        self.write_data(0x28)
-    def blit_buffer(self, buffer,x,y,w,h):
-        self.write_cmd(0x2A)
-        self.write_data(int(x/256))
-        self.write_data(int(x&255))
-        self.write_data(int((x+w-1)/256))
-        self.write_data(int((x+w-1)&255))
-
-        self.write_cmd(0x2B)
-        self.write_data(int(y/256))
-        self.write_data(int(y&255))
-        self.write_data(int((y+h-1)/256))
-        self.write_data(int((y+h-1)&255))
-        
-        self.write_cmd(0x2C)
-        
-        self.cs(1)
-        self.dc(1)
-        self.cs(0)
-        self.spi.write(buffer)
-        self.cs(1)
-    def bl_ctrl(self,duty):
-        pwm = PWM(Pin(LCD_BL))
-        pwm.freq(1000)
-        if(duty>=100):
-            pwm.duty_u16(65535)
-        else:
-            pwm.duty_u16(655*duty)
-    def touch_get(self): 
-        if self.irq() == 0:
-            self.spi = SPI(1,5_000_000,sck=Pin(LCD_SCK),mosi=Pin(LCD_MOSI),miso=Pin(LCD_MISO))
-            self.tp_cs(0)
-            X_Point = 0
-            Y_Point = 0
-            for i in range(0,3):
-                self.spi.write(bytearray([0XD0]))
-                Read_date = self.spi.read(2)
-                time.sleep_us(10)
-                Y_Point=Y_Point+(((Read_date[0]<<8)+Read_date[1])>>3)
-                
-                self.spi.write(bytearray([0X90]))
-                Read_date = self.spi.read(2)
-                X_Point=X_Point+(((Read_date[0]<<8)+Read_date[1])>>3)
-
-            X_Point=X_Point/3
-            Y_Point=Y_Point/3
-            
-            self.tp_cs(1) 
-            self.spi = SPI(1,60_000_000,sck=Pin(LCD_SCK),mosi=Pin(LCD_MOSI),miso=Pin(LCD_MISO))
-
-            X_Point = int((X_Point-430)*480/3270)
-            if(X_Point>480):
-                X_Point = 480
-            elif X_Point<0:
-                X_Point = 0
-            Y_Point = 320-int((Y_Point-430)*320/3270)
-
-
-            Result_list = [X_Point,Y_Point]
-            #print(Result_list)
-            return(Result_list)
-
diff --git a/usermodule/uctx/examples/lcd13.py b/usermodule/uctx/examples/lcd13.py
deleted file mode 100644
index e5d66528d0..0000000000
--- a/usermodule/uctx/examples/lcd13.py
+++ /dev/null
@@ -1,146 +0,0 @@
-from machine import Pin,SPI,PWM
-import framebuf
-import time
-import os
-
-BL = 13
-DC = 8
-RST = 12
-MOSI = 11
-SCK = 10
-CS = 9
-
-
-class LCD_1inch3():#framebuf.FrameBuffer):
-    def __init__(self):
-        pwm = PWM(Pin(BL))
-        pwm.freq(1000)
-        pwm.duty_u16(int(65535*0.3))#max 65535
-        
-        self.width = 240
-        self.height = 240
-        
-        self.cs = Pin(CS,Pin.OUT)
-        self.rst = Pin(RST,Pin.OUT)
-        self.cs(1)
-        self.spi = SPI(1,80_000_000,polarity=0, phase=0,sck=Pin(SCK),mosi=Pin(MOSI),miso=None)
-        self.dc = Pin(DC,Pin.OUT)
-        self.dc(1)
-        self.init_display()
-    def write_cmd(self, cmd):
-        self.cs(1)
-        self.dc(0)
-        self.cs(0)
-        self.spi.write(bytearray([cmd]))
-        self.cs(1)
-
-    def write_data(self, buf):
-        self.cs(1)
-        self.dc(1)
-        self.cs(0)
-        self.spi.write(bytearray([buf]))
-        self.cs(1)
-
-    def init_display(self):
-        """Initialize dispaly"""  
-        self.rst(1)
-        self.rst(0)
-        self.rst(1)
-        
-        self.write_cmd(0x36)
-        self.write_data(0x70)
-
-        self.write_cmd(0x3A) 
-        self.write_data(0x05)
-
-        self.write_cmd(0xB2)
-        self.write_data(0x0C)
-        self.write_data(0x0C)
-        self.write_data(0x00)
-        self.write_data(0x33)
-        self.write_data(0x33)
-
-        self.write_cmd(0xB7)
-        self.write_data(0x35) 
-
-        self.write_cmd(0xBB)
-        self.write_data(0x19)
-
-        self.write_cmd(0xC0)
-        self.write_data(0x2C)
-
-        self.write_cmd(0xC2)
-        self.write_data(0x01)
-
-        self.write_cmd(0xC3)
-        self.write_data(0x12)   
-
-        self.write_cmd(0xC4)
-        self.write_data(0x20)
-
-        self.write_cmd(0xC6)
-        self.write_data(0x0F) 
-
-        self.write_cmd(0xD0)
-        self.write_data(0xA4)
-        self.write_data(0xA1)
-
-        self.write_cmd(0xE0)
-        self.write_data(0xD0)
-        self.write_data(0x04)
-        self.write_data(0x0D)
-        self.write_data(0x11)
-        self.write_data(0x13)
-        self.write_data(0x2B)
-        self.write_data(0x3F)
-        self.write_data(0x54)
-        self.write_data(0x4C)
-        self.write_data(0x18)
-        self.write_data(0x0D)
-        self.write_data(0x0B)
-        self.write_data(0x1F)
-        self.write_data(0x23)
-
-        self.write_cmd(0xE1)
-        self.write_data(0xD0)
-        self.write_data(0x04)
-        self.write_data(0x0C)
-        self.write_data(0x11)
-        self.write_data(0x13)
-        self.write_data(0x2C)
-        self.write_data(0x3F)
-        self.write_data(0x44)
-        self.write_data(0x51)
-        self.write_data(0x2F)
-        self.write_data(0x1F)
-        self.write_data(0x1F)
-        self.write_data(0x20)
-        self.write_data(0x23)
-        
-        self.write_cmd(0x21)
-
-        self.write_cmd(0x11)
-
-        self.write_cmd(0x29)
-
-    def blit_buffer(self, buffer,x,y,w,h):
-        self.write_cmd(0x2A)
-        self.write_data(int(x/256))
-        self.write_data(int(x&255))
-        self.write_data(int((x+w-1)/256))
-        self.write_data(int((x+w-1)&255))
-
-        self.write_cmd(0x2B)
-        self.write_data(int(y/256))
-        self.write_data(int(y&255))
-        self.write_data(int((y+h-1)/256))
-        self.write_data(int((y+h-1)&255))
-        
-        self.write_cmd(0x2C)
-        
-        self.cs(1)
-        self.dc(1)
-        self.cs(0)
-        self.spi.write(buffer)
-        self.cs(1)
-
diff --git a/usermodule/uctx/examples/menu.py b/usermodule/uctx/examples/menu.py
deleted file mode 100755
index 00651f3e26..0000000000
--- a/usermodule/uctx/examples/menu.py
+++ /dev/null
@@ -1,365 +0,0 @@
-#!/usr/bin/env uctx
-
-# If you are reading this on the web, this file is probably part of your
-# persistent micropython filsystem on this URL (stored in your browser).
-# as part of a rapid protoyping environment.
-#
-# main.py and canvas.py are copied afresh from the server on each reload, if
-# canvas.py is missing all the preloaded contents are brought back. Navigate
-# filesystem in dropdown, create files and folders by specifying paths to save.
-#
-# press ctrl+return to run code
-#
-
-import canvas # this contains the python configuration to create a context
-import io,os,gc,time,sys
-
-ctx=canvas.ctx
-
-clientflags = ctx.flags # the flags used for launching clients
-
-# override client flags
-clientflags = ctx.HASH_CACHE | ctx.RGB332
-# and set the flags specific for the launcher
-ctx.flags |= ctx.HASH_CACHE | ctx.GRAY4
-
-light_red=(255/255,80/255,80/255)
-white=(1.0,1.0,1.0)
-black=(0,0,0)
-dark_gray=(80/255,80/255,80/255)
-light_gray=(170/255,170/255,170/255)
-
-wallpaper_bg    = black
-document_bg     = white
-document_fg     = black
-toolbar_bg      = dark_gray
-toolbar_fg      = white
-button_bg       = dark_gray
-button_fg       = white
-dir_selected_bg = white
-dir_selected_fg = black
-dir_entry_fg    = white
-scrollbar_fg    = dark_gray
-
-button_height_vh = 0.33
-button_width_vh  = 0.3
-font_size_vh     = 0.11
-
-if ctx.width < ctx.height:
-  font_size_vh = 0.06
-  button_width_vh = 0.2
-
-cur = 0
-def set_cur(event, no):
-    global cur
-    cur=no
-    return 0
-
-maxframe=10
-def linear(start_val,end_val):
-  return (frame/maxframe)*(end_val-start_val)+start_val
-
-def mbutton(ctx, x, y, label, cb, user_data):
-   ctx.save()
-   ctx.font_size *= 0.75
-   ctx.translate(x, y)
-   ctx.begin_path().rectangle(0,0, ctx.height*button_width_vh * 0.95, ctx.height * button_height_vh * 0.95)
-   ctx.listen_stop_propagate(ctx.PRESS, lambda e:cb(e, e.user_data), user_data)
-   ctx.rgb(*button_bg).fill()
-   ctx.rgb(*button_fg).move_to(ctx.font_size/3, ctx.height * button_height_vh / 2).text(label)
-   ctx.restore()
-
-def mbutton_thin(ctx, x, y, label, cb, user_data):
-   ctx.save()
-   ctx.font_size *= 0.8
-   ctx.translate(x, y)
-   ctx.begin_path().rectangle(0,0, ctx.height*button_width_vh * 0.95, ctx.font_size * 3)
-   ctx.listen_stop_propagate(ctx.PRESS, lambda e:cb(e, e.user_data), user_data)
-   ctx.begin_path().rectangle(0,0, ctx.height*button_width_vh * 0.95, ctx.font_size)
-
-   ctx.rgb(*button_bg).fill()
-   ctx.rgb(*button_fg).move_to(ctx.font_size/3, ctx.font_size*0.8).text(label)
-   ctx.restore()
-
-response = False
-
-def respond(val):
-    global response
-    response = val
-
-more_actions=False
-def show_more_cb(event, userdata):
-    global more_actions
-    more_actions = True
-    #event.stop_propagate=1
-
-def hide_more_cb(userdata):
-    global more_actions
-    more_actions = False
-    #event.stop_propagate=1
-
-
-def remove_cb(event, path):
-    global more_actions
-    os.remove(path)
-    more_actions = False
-    #event.stop_propagate=1
-
-offset=0
-
-def drag_cb(event):
-    global offset
-    offset -=event.delta_y/(font_size_vh*ctx.height) #20.0
-
-view_file=""
-run_file=False
-frame_no = 0
-
-def run_cb(event, path):
-    global run_file
-    run_file = path
-
-def view_cb(event, path):
-    global view_file, offset
-    offset = 0
-    view_file = path
-    #event.stop_propagate=1
-
-def space_cb(event):
-    run_cb(None, current_file)
-    print(event.string)
-
-def up_cb(event):
-    global cur
-    cur -= 1
-    if cur <= 0:
-        cur = 0
-
-def down_cb(event):
-    global cur
-    cur += 1
-
-def exit_cb(event):
-    global main_exit
-    main_exit = True
-
-import micropython
-
-def dir_view(ctx):
-   global cur,frame_no,current_file,offset
-   frame_no += 1
-
-#   if cur > 4:
-       
-
-   #gc.collect()
-   ctx.start_frame()
-   #micropython.mem_info()
-   ctx.add_key_binding("space", "", "", space_cb)
-   ctx.add_key_binding("up", "", "", up_cb)
-   ctx.add_key_binding("down", "", "", down_cb)
-   ctx.add_key_binding("q", "", "", exit_cb)
-
-   ctx.font_size=ctx.height*font_size_vh#32
-
-   if (offset ) < cur - (ctx.height/ctx.font_size) * 0.75:
-     offset = cur - (ctx.height/ctx.font_size)*0.42
-   if (offset ) > cur - (ctx.height/ctx.font_size) * 0.2:
-     offset = cur - (ctx.height/ctx.font_size)*0.42
-   if offset < 0:
-     offset = 0
-
-
-
-   y = ctx.font_size - offset * ctx.font_size
-   no = 0 
-      
-   ctx.rectangle(0,0,ctx.width,ctx.height).rgb(0.0,0.0,0.0).fill()
-   #ctx.listen(ctx.MOTION, drag_cb)
-   #ctx.begin_path()
-   
-   current_file = ""
-
-   if hasattr(os, 'listdir'):
-     file_list = os.listdir('/')
-   else:
-     file_list = []
-     for f in os.ilistdir('/'):
-         file_list.append(f[0])
-   file_list.sort()
-
-   for file in file_list:        
-    if file[0] != '.':
-      ctx.rectangle(ctx.height * button_width_vh * 1.2,y-ctx.font_size*0.75,
-                  ctx.width - ctx.height * button_width_vh * 1.2, ctx.font_size)
-      if no == cur:
-        ctx.rgb(*dir_selected_bg)
-        current_file = file
-        ctx.fill()
-        ctx.rgb(*dir_selected_fg)
-      else:
-        ctx.listen(ctx.PRESS, lambda e:set_cur(e, e.user_data), no)
-        ctx.begin_path()
-        ctx.rgb(*dir_entry_fg)
-      ctx.move_to(ctx.height * button_width_vh * 1.2 + ctx.font_size * 0.1,y)
-      
-      ctx.text(file)
-      
-      y += ctx.font_size
-      no += 1
-
-   mbutton(ctx, 0, 0,
-          "view", view_cb, current_file)
-   mbutton(ctx, 0, ctx.height * button_height_vh,
-          "run", run_cb, current_file)
-   mbutton(ctx, 0, ctx.height - ctx.height * button_height_vh * 1,
-          "...", show_more_cb, current_file)
-   if more_actions:
-     ctx.rectangle(60,0,ctx.width,ctx.height)
-     ctx.listen_stop_propagate(ctx.PRESS, hide_more_cb)
-     mbutton(ctx, ctx.width-ctx.height * button_width_vh, ctx.height - ctx.height * button_height_vh * 1, "remove", remove_cb, current_file)
-
-   if frame_no > 1000:
-     ctx.save()
-     global_alpha=((frame_no-32)/50.0)
-     if global_alpha > 1.0:
-         global_alpha = 1.0
-     elif global_alpha < 0:
-         global_alpha = 0.0
-     ctx.global_alpha = global_alpha
-     ctx.logo(ctx.width - 32,ctx.height-32,64)
-     ctx.restore()
-   ctx.end_frame()
-   
-def scrollbar_cb(event):
-    global offset
-    factor = (event.y - ctx.font_size * 1.5) / (ctx.height-ctx.font_size*2);
-    if factor < 0.0:
-        factor = 0.0
-    if factor > 1.0:
-        factor = 1.0
-    offset = factor * event.user_data
-
-def prev_page_cb(event):
-    global offset
-    offset -= ((ctx.height / ctx.font_size) - 2)
-
-def next_page_cb(event):
-    global offset
-    offset += ((ctx.height / ctx.font_size) - 2)
-
-def file_view(ctx):
-   global offset
-   gc.collect()
-   ctx.start_frame()
-   ctx.save()
-
-   ctx.font_size = ctx.height * font_size_vh
-
-   #offset += 0.25
-   ctx.rectangle(0,0,ctx.width,ctx.height)
-   #ctx.listen(ctx.MOTION, drag_cb)
-   ctx.rgb(*document_bg).fill()
-   
-   ctx.rgb(*document_fg)
-   ctx.translate(0,(int(offset)-offset) * ctx.font_size)
-   ctx.move_to(0, ctx.font_size*0.8 * 2)
-   line_no = 0
-   ctx.font="mono";
-   y = ctx.font_size * 0.8 * 2
-   with open(view_file,'r') as file:
-     for line in file:
-       if line_no > offset and y - ctx.font_size < ctx.height:
-          ctx.move_to (0, int(y))
-          for word in line.split():
-            ctx.move_to(int(ctx.x), int(ctx.y))
-            ctx.text(word + ' ')
-          y+=ctx.font_size
-            
-       line_no += 1
-   ctx.restore()
-
-   ctx.save()
-   ctx.rgb(*toolbar_bg)
-   ctx.rectangle(0,0,ctx.width, ctx.font_size).clip()
-   ctx.paint()
-   ctx.text_align=ctx.RIGHT
-   ctx.rgb(*toolbar_fg)
-   ctx.move_to(ctx.width, ctx.font_size*0.8)
-   ctx.text(view_file)
-   ctx.restore()
-   mbutton_thin(ctx, 0, ctx.height * button_height_vh * 0, "close", lambda e,d:view_cb(e,False), -3)
-
-   ctx.rgb(*scrollbar_fg)
-   
-   ctx.move_to(ctx.width - ctx.font_size * 1.2, ctx.font_size + ctx.font_size)
-   
-   if True:#draw scrollbar
-    ctx.line_to(ctx.width - ctx.font_size * 1.2, ctx.height - ctx.font_size)
-    ctx.line_width=1
-    ctx.stroke()
-    ctx.arc(ctx.width - ctx.font_size * 1.2,
-          ctx.font_size + ctx.font_size + (offset / line_no) * (ctx.height - ctx.font_size * 2),
-          ctx.font_size*0.8, 0.0, 3.14152*2, 0).stroke()
-    ctx.rectangle(ctx.width - ctx.font_size * 2, 0, ctx.font_size * 2, ctx.height)
-    ctx.listen(ctx.PRESS|ctx.DRAG_MOTION, scrollbar_cb, line_no)
-    ctx.begin_path()
-    
-   ctx.rectangle(0, ctx.font_size,
-               ctx.width, (ctx.height - ctx.font_size)/2-1)
-   ctx.listen(ctx.PRESS, prev_page_cb)
-   ctx.begin_path()
-   ctx.rectangle(0, ctx.font_size + (ctx.height - ctx.font_size)/2,
-               ctx.width, (ctx.height - ctx.font_size)/2-1)
-   ctx.listen(ctx.PRESS, next_page_cb)
-   ctx.begin_path()
-   ctx.end_frame()
-
-
-main_exit = False
-while not main_exit:
-    if view_file:
-        file_view(ctx)
-    else:
-        dir_view(ctx)
-        if run_file != False:
-            backupflags = ctx.flags
-            # we remove any scratch format from flags
-            ctx.flags = backupflags - (ctx.flags&(ctx.GRAY2|ctx.GRAY4|ctx.RGB332))
-            # and add in low res
-            ctx.flags = clientflags
-
-            gc.collect()
-            ctx.start_frame()    
-            ctx.rgb(*wallpaper_bg).paint()
-            ctx.end_frame()
-            ctx.start_frame()    
-            ctx.rgb(*wallpaper_bg).paint()
-            ctx.font_size=ctx.height*font_size_vh#32
-            ctx.rgb(*white).move_to(0,ctx.font_size).text(run_file)
-            ctx.end_frame()
-            gc.collect()
-
-
-            
-            try:
-              exec(open(run_file).read())
-            except Exception as e:
-              string_res=io.StringIO(256)
-              sys.print_exception(e, string_res)
-              for frame in range(0,2):
-               ctx.start_frame()
-               ctx.rgb(*wallpaper_bg).paint()
-               ctx.font_size=ctx.height*font_size_vh#32
-               ctx.rgb(*white).move_to(0,ctx.font_size).text(run_file)
-               #ctx.rgb(*[255,0,0]).move_to(0,ctx.font_size*2).text(str(e))
-               ctx.rgb(*light_red).move_to(0,ctx.font_size*3).text(string_res.getvalue())
-
-               ctx.end_frame()
-              time.sleep(5)
-     
-            ctx.flags = backupflags
-            run_file = False
-            gc.collect()
-
-
diff --git a/usermodule/uctx/examples/rectangles.py b/usermodule/uctx/examples/rectangles.py
deleted file mode 100755
index d12f9762c9..0000000000
--- a/usermodule/uctx/examples/rectangles.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env uctx
-
-import canvas
-
-ctx=canvas.ctx
-
-down = False
-
-def on_press(e):
-    global down
-    down = True
-
-def on_release(e):
-    global down
-    down = False
-
-x = ctx.width/2
-y = ctx.height/2
-
-def on_motion(e):
-  global x,y
-  x = e.x
-  y = e.y
-
-exit = False
-
-def exit_cb():
-    global exit
-    exit=True
-
-#machine.freq(200_000_000)
-max_frame = 100.0
-frame_no = 1
-while not exit:
-   ctx.start_frame()
-   ctx.add_key_binding("q", "", "", exit_cb)
-   ctx.font_size = ctx.height * 0.1
-
-   ctx.rectangle(0,0,ctx.width,ctx.height)
-   ctx.listen(ctx.PRESS, on_press)
-   ctx.listen(ctx.RELEASE, on_release)
-   ctx.listen(ctx.MOTION, on_motion) 
-  
-   if (down):
-     ctx.color([0,111,222])
-   else:
-     ctx.color([255,255,255])
- 
-   ctx.fill()
-   dim = (frame_no/max_frame) * ctx.height
-
-
-   if frame_no >= max_frame-2:
-       dim = ctx.height
-   ctx.logo(x,y, dim)
-   ctx.end_frame()
-   frame_no+=1
-   
diff --git a/usermodule/uctx/examples/simple.py b/usermodule/uctx/examples/simple.py
deleted file mode 100755
index 0f105aad26..0000000000
--- a/usermodule/uctx/examples/simple.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/env uctx
-
-import canvas
-
-ctx=canvas.ctx
-
-down = False
-
-def on_press(e):
-    global down
-    down = True
-
-def on_release(e):
-    global down
-    down = False
-
-x = ctx.width/2
-y = ctx.height/2
-
-def on_motion(e):
-  global x,y
-  x = e.x
-  y = e.y
-
-exit = False
-
-
-def exit_cb():
-    global exit
-    exit=True
-
-#machine.freq(200_000_000)
-max_frame = 100.0
-frame_no = 0
-while not exit:
-   ctx.start_frame()
-   ctx.add_key_binding("q", "", "", exit_cb)
-   ctx.font_size = ctx.height * 0.1
-
-   ctx.rectangle(0,0,ctx.width,ctx.height)
-   ctx.listen(ctx.PRESS, on_press)
-   ctx.listen(ctx.RELEASE, on_release)
-   ctx.listen(ctx.MOTION, on_motion) 
-  
-   if (down):
-     ctx.rgb(0,111,222)
-   else:
-     ctx.rgb(255,255,255)
- 
-   ctx.fill()
-   dim = (frame_no/max_frame) * ctx.height
-   if frame_no >= max_frame-2:
-       dim = ctx.height
-   ctx.logo(x,y, dim)
-   ctx.end_frame()
-
-   frame_no+=1
-   if frame_no > max_frame:
-       frame_no = 0
-   
diff --git a/usermodule/uctx/examples/st7789py.py b/usermodule/uctx/examples/st7789py.py
deleted file mode 100644
index e37ef4b098..0000000000
--- a/usermodule/uctx/examples/st7789py.py
+++ /dev/null
@@ -1,403 +0,0 @@
-#from machine import Pin,SPI,PWM
-import machine
-import time
-import ctx
-import gc
-from micropython import const
-import ustruct as struct
-
-# commands
-ST77XX_NOP = const(0x00)
-ST77XX_SWRESET = const(0x01)
-ST77XX_RDDID = const(0x04)
-ST77XX_RDDST = const(0x09)
-
-ST77XX_SLPIN = const(0x10)
-ST77XX_SLPOUT = const(0x11)
-ST77XX_PTLON = const(0x12)
-ST77XX_NORON = const(0x13)
-
-ST77XX_INVOFF = const(0x20)
-ST77XX_INVON = const(0x21)
-ST77XX_DISPOFF = const(0x28)
-ST77XX_DISPON = const(0x29)
-ST77XX_CASET = const(0x2A)
-ST77XX_RASET = const(0x2B)
-ST77XX_RAMWR = const(0x2C)
-ST77XX_RAMRD = const(0x2E)
-
-ST77XX_PTLAR = const(0x30)
-ST77XX_COLMOD = const(0x3A)
-ST7789_MADCTL = const(0x36)
-
-ST7789_MADCTL_MY = const(0x80)
-ST7789_MADCTL_MX = const(0x40)
-ST7789_MADCTL_MV = const(0x20)
-ST7789_MADCTL_ML = const(0x10)
-ST7789_MADCTL_BGR = const(0x08)
-ST7789_MADCTL_MH = const(0x04)
-ST7789_MADCTL_RGB = const(0x00)
-
-ST7789_RDID1 = const(0xDA)
-ST7789_RDID2 = const(0xDB)
-ST7789_RDID3 = const(0xDC)
-ST7789_RDID4 = const(0xDD)
-
-ColorMode_65K = const(0x50)
-ColorMode_262K = const(0x60)
-ColorMode_12bit = const(0x03)
-ColorMode_16bit = const(0x05)
-ColorMode_18bit = const(0x06)
-ColorMode_16M = const(0x07)
-
-# Color definitions
-BLACK = const(0x0000)
-BLUE = const(0x001F)
-RED = const(0xF800)
-GREEN = const(0x07E0)
-CYAN = const(0x07FF)
-MAGENTA = const(0xF81F)
-YELLOW = const(0xFFE0)
-WHITE = const(0xFFFF)
-
-_ENCODE_PIXEL = ">H"
-_ENCODE_POS = ">HH"
-_DECODE_PIXEL = ">BBB"
-
-_BUFFER_SIZE = const(256)
-
-
-def delay_ms(ms):
-    time.sleep_ms(ms)
-
-
-def color565(r, g=0, b=0):
-    """Convert red, green and blue values (0-255) into a 16-bit 565 encoding.  As
-    a convenience this is also available in the parent adafruit_rgb_display
-    package namespace."""
-    try:
-        r, g, b = r  # see if the first var is a tuple/list
-    except TypeError:
-        pass
-    return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3
-
-
-class ST77xx:
-    def __init__(self, spi, width, height, reset, dc, cs=None, backlight=None,
-                 xstart=-1, ystart=-1, sck=None, mosi=None, miso=None, tp_irq=None, tp_cs=None):
-        """
-        display = st7789.ST7789(
-            SPI(1, baudrate=40000000, phase=0, polarity=1),
-            240, 240,
-            reset=machine.Pin(5, machine.Pin.OUT),
-            dc=machine.Pin(2, machine.Pin.OUT),
-        )
-        """
-        self.width = width
-        self.height = height
-        self.spi = spi
-        self.sck = sck
-        self.ctx = False
-        if spi == None:
-            self.spi = machine.SPI(1, baudrate=50000000, polarity=1)
-        self.reset = reset
-        self.dc = dc
-        self.cs = cs
-        self.mosi = mosi
-        self.miso = miso
-        
-
-        
-        self.backlight = backlight
-        if xstart >= 0 and ystart >= 0:
-            self.xstart = xstart
-            self.ystart = ystart
-        elif (self.width, self.height) == (320, 240):
-            self.xstart = 0
-            self.ystart = 0            
-        elif (self.width, self.height) == (240, 320):
-            self.xstart = 0
-            self.ystart = 0            
-        elif (self.width, self.height) == (240, 240):
-            self.xstart = 0
-            self.ystart = 0
-        elif (self.width, self.height) == (135, 240):
-            self.xstart = 52
-            self.ystart = 40
-        else:
-            raise ValueError(
-                "Unsupported display. Only 240x240 and 135x240 are supported "
-                "without xstart and ystart provided"
-            )
-        self.X_Point = 0
-        self.Y_Point = 1
-        
-        if tp_irq != None:
-          self.irq = machine.Pin(tp_irq,machine.Pin.IN)
-          self.tp_cs = machine.Pin(tp_cs,machine.Pin.OUT)
-          self.tp_cs(1)
-
-        self.pointer_down = False
-        if self.backlight:
-            self.backlight.high();
-
-    def get_id(self):
-        self.cs_low()
-        self.dc_low()
-        self.spi.write(bytes([ST7789_RDID2]))
-        res = self.spi.read(1)
-        self.cs_high()
-        return res[0]
-
-    def dc_low(self):
-        self.dc.off()
-
-    def dc_high(self):
-        self.dc.on()
-
-    def reset_low(self):
-        if self.reset:
-            self.reset.off()
-
-    def reset_high(self):
-        if self.reset:
-            self.reset.on()
-
-    def cs_low(self):
-        if self.cs:
-            self.cs.off()
-
-    def cs_high(self):
-        if self.cs:
-            self.cs.on()
-
-    def write(self, command=None, data=None):
-        """SPI write to the device: commands and data"""
-        self.cs_low()
-        if command is not None:
-            self.dc_low()
-            self.spi.write(bytes([command]))
-        if data is not None:
-            self.dc_high()
-            self.spi.write(data)
-        self.cs_high()
-
-    def hard_reset(self):
-        self.cs_low()
-        self.reset_high()
-        delay_ms(50)
-        self.reset_low()
-        delay_ms(50)
-        self.reset_high()
-        delay_ms(150)
-        self.cs_high()
-
-    def soft_reset(self):
-        self.write(ST77XX_SWRESET)
-        delay_ms(150)
-
-    def sleep_mode(self, value):
-        if value:
-            self.write(ST77XX_SLPIN)
-        else:
-            self.write(ST77XX_SLPOUT)
-
-    def inversion_mode(self, value):
-        if value:
-            self.write(ST77XX_INVON)
-        else:
-            self.write(ST77XX_INVOFF)
-
-    def _set_color_mode(self, mode):
-        self.write(ST77XX_COLMOD, bytes([mode & 0x77]))
-
-    def init(self, *args, **kwargs):
-        self.hard_reset()      
-        self.soft_reset()
-        self.sleep_mode(False)
-        return True
-
-    def _set_mem_access_mode(self, rotation, vert_mirror, horz_mirror, is_bgr):
-        rotation &= 7
-        value = {
-            0: 0,
-            1: ST7789_MADCTL_MX,
-            2: ST7789_MADCTL_MY,
-            3: ST7789_MADCTL_MX | ST7789_MADCTL_MY,
-            4: ST7789_MADCTL_MV,
-            5: ST7789_MADCTL_MV | ST7789_MADCTL_MX,
-            6: ST7789_MADCTL_MV | ST7789_MADCTL_MY,
-            7: ST7789_MADCTL_MV | ST7789_MADCTL_MX | ST7789_MADCTL_MY,
-        }[rotation]
-
-        if vert_mirror:
-            value = ST7789_MADCTL_ML
-        elif horz_mirror:
-            value = ST7789_MADCTL_MH
-
-        if is_bgr:
-            value |= ST7789_MADCTL_BGR
-        self.write(ST7789_MADCTL, bytes([value]))
-
-    def _encode_pos(self, x, y):
-        """Encode a postion into bytes."""
-        return struct.pack(_ENCODE_POS, x, y)
-
-    def _encode_pixel(self, color):
-        """Encode a pixel color into bytes."""
-        return struct.pack(_ENCODE_PIXEL, color)
-
-    def _set_columns(self, start, end):
-        if start > end or end >= self.width:
-            return
-        start += self.xstart
-        end += self.xstart
-        self.write(ST77XX_CASET, self._encode_pos(start, end))
-
-    def _set_rows(self, start, end):
-        if start > end or end >= self.height:
-            return
-        start += self.ystart
-        end += self.ystart
-        self.write(ST77XX_RASET, self._encode_pos(start, end))
-
-    def set_window(self, x0, y0, x1, y1):
-        self._set_columns(x0, x1)
-        self._set_rows(y0, y1)
-        self.write(ST77XX_RAMWR)
-
-    def vline(self, x, y, length, color):
-        self.fill_rect(x, y, 1, length, color)
-
-    def hline(self, x, y, length, color):
-        self.fill_rect(x, y, length, 1, color)
-
-    def pixel(self, x, y, color):
-        self.set_window(x, y, x, y)
-        self.write(None, self._encode_pixel(color))
-
-    def blit_buffer(self, buffer, x, y, width, height):
-        self.set_window(x, y, x + width -1, y + height -1)
-        self.write(None, buffer)
-
-    def rect(self, x, y, w, h, color):
-        self.hline(x, y, w, color)
-        self.vline(x, y, h, color)
-        self.vline(x + w - 1, y, h, color)
-        self.hline(x, y + h - 1, w, color)
-
-    def fill_rect(self, x, y, width, height, color):
-        self.set_window(x, y, x + width - 1, y + height - 1)
-        chunks, rest = divmod(width * height, _BUFFER_SIZE)
-        pixel = self._encode_pixel(color)
-        self.dc_high()
-        if chunks:
-            data = pixel * _BUFFER_SIZE
-            for _ in range(chunks):
-                self.write(None, data)
-        if rest:
-            self.write(None, pixel * rest)
-
-    def fill(self, color):
-        self.fill_rect(0, 0, self.width, self.height, color)
-
-    def line(self, x0, y0, x1, y1, color):
-        # Line drawing function.  Will draw a single pixel wide line starting at
-        # x0, y0 and ending at x1, y1.
-        steep = abs(y1 - y0) > abs(x1 - x0)
-        if steep:
-            x0, y0 = y0, x0
-            x1, y1 = y1, x1
-        if x0 > x1:
-            x0, x1 = x1, x0
-            y0, y1 = y1, y0
-        dx = x1 - x0
-        dy = abs(y1 - y0)
-        err = dx // 2
-        if y0 < y1:
-            ystep = 1
-        else:
-            ystep = -1
-        while x0 <= x1:
-            if steep:
-                self.pixel(y0, x0, color)
-            else:
-                self.pixel(x0, y0, color)
-            err -= dy
-            if err < 0:
-                y0 += ystep
-                err += dx
-            x0 += 1
-    def touch_get(self): 
-        if self.irq() == 0:
-            self.spi =machine.SPI(1, baudrate=5000000, sck=machine.Pin(self.sck),
-                                   mosi=machine.Pin(self.mosi),
-                                   miso=machine.Pin(self.miso))
-            self.tp_cs(0)
-            X_Point = 0
-            Y_Point = 0
-            for i in range(0,2):
-                self.spi.write(bytearray([0XD0]))
-                Read_date = self.spi.read(3)
-                time.sleep_us(10)
-                X_Point=X_Point+(((Read_date[0]<<8)+Read_date[1])>>3)
-                
-                self.spi.write(bytearray([0X90]))
-                Read_date = self.spi.read(2)
-                Y_Point=Y_Point+(((Read_date[0]<<8)+Read_date[1])>>3)
-
-            X_Point=X_Point/2
-            Y_Point=Y_Point/2
-            
-            self.tp_cs(1)
-
-            self.spi =machine.SPI(1, baudrate=40000000, polarity=1, sck=machine.Pin(self.sck),
-                                     mosi=machine.Pin(self.mosi),
-                                     miso=machine.Pin(self.miso))
-            X_Point = 240-((X_Point-540)*240.0/3270)
-            Y_Point = 320-((Y_Point-540)*320.0/3270)
-
-            Result_list = [X_Point,Y_Point]
-            return(Result_list)
-    def ctx_update_events(self,o):
-      touch=self.touch_get()
-      if(touch):
-          self.X_Point = touch[0]
-          self.Y_Point = touch[1]
-          if(self.X_Point>240):
-            self.X_Point = 240
-          elif self.X_Point<0:
-            self.X_Point = 0
-          if(self.Y_Point>320):
-            self.Y_Point = 320
-          elif self.Y_Point<0:
-            self.Y_Point = 0
-          if not self.pointer_down:
-            o.pointer_press(self.X_Point,self.Y_Point, 0, 0, 1)
-          else:
-            o.pointer_motion(self.X_Point,self.Y_Point, 0, 0, 1)
-          #print ("pointer " + str(self.X_Point) + ' ' + str (self.Y_Point))
-          self.pointer_down = True
-          return False # abort rendering if in slow refresh
-      else:
-          if self.pointer_down:
-            o.pointer_release(self.X_Point,self.Y_Point, 0, 0, 1)
-          self.pointer_down = False
-          return False
-
-
-class ST7789(ST77xx):
-    def init(self, *, color_mode=ColorMode_65K | ColorMode_16bit):
-        super().init()
-        self._set_color_mode(color_mode)
-        delay_ms(50)
-        self._set_mem_access_mode(4, True, True, False)
-        self.inversion_mode(True)
-        delay_ms(10)
-        self.write(ST77XX_NORON)
-        delay_ms(10)
-        self.fill(0)
-        self.write(ST77XX_DISPON)
-        delay_ms(500)
-
-lcd = False
diff --git a/usermodule/uctx/examples/uimui.py b/usermodule/uctx/examples/uimui.py
deleted file mode 100755
index 0491271140..0000000000
--- a/usermodule/uctx/examples/uimui.py
+++ /dev/null
@@ -1,492 +0,0 @@
-#!/usr/bin/env uctx
-
-import ctx
-import gc
-
-pointer_x = 0
-pointer_y = 0
-down = False
-was_down = False
-text_edit_preview = ''
-
-cursor_pos=[0,0]
-widget_no = 0
-grab_no = 0
-text_edit_no = 0
-text_edit_font_size = 0
-text_edit_copy = None
-text_edit_done = False
-
-import canvas
-
-o = canvas.ctx
-
-try:
-    font_size_vh
-except NameError:
-    if o.width < o.height:
-      font_size_vh = 0.05
-    else:
-      font_size_vh = 0.06
-
-widget_fs=0.1
-widget_height_fs=2.0
-
-#o.flags = o.HASH_CACHE | o.RGB332 | o.INTRA_UPDATE
-o.flags = o.HASH_CACHE|o.RGB332
-wallpaper_bg=(0,0,0)
-widget_font_size_vh = font_size_vh
-widget_bg=(80/255,80/255,80/255)
-widget_fg=(1.0,1.0,1.0)
-widget_marker=(163/255,100/255,180/255)
-button_bg=widget_bg
-button_fg=widget_fg
-button_bg_active=(225/255,35/255,90/255)
-
-widget_x=0
-widget_y=0
-widget_width=0
-widget_height=0
-
-edge_left = o.height * font_size_vh * 8
-edge_right = o.width - edge_left
-
-def add_widget(x, y, w, h):
-    global widget_no
-    widget_no += 1
-    return widget_no
-def get_ctx():
-    return o
-  
-def inside_rect(u,v,x,y,w,h):
-    if u >= x and  u < x + w and v >= y and v < y + h:
-      return True
-    return False
-
-def slider_sized(x, y, w, h, label, value, min, max):
-    global grab_no
-    add_widget(x, y, w, h)
-    o.font_size = o.height * widget_font_size_vh # why do we need this override
-    o.rgb(*widget_bg).rectangle(x, y, w, h - 2).fill()
-    o.rgb(*widget_marker).rectangle(x + (value-min)/(max-min)*w, y, 0.1*o.font_size, h).fill()     
-    o.rgb(*widget_fg)
-    o.move_to(x + o.font_size*0.1, y + o.font_size*0.8)
-    o.text(label)
-    o.save()
-    o.text_align=o.RIGHT
-    o.move_to(x+w,y+o.font_size*0.8)
-    o.text(str(value))
-    o.restore()
-    
-    if text_edit_no != 0:
-      return value
-    
-    if down and text_edit_no==0:
-      if inside_rect(pointer_x,pointer_y,x,y,w,h) or\
-         grab_no == widget_no:
-        if was_down == False:
-          grab_no = widget_no
-        if grab_no == widget_no:
-          value = ((pointer_x - x) / w) * (max-min) + min
-          if value < min:
-            value = min
-          if value > max:
-            value = max
-    else:
-      grab_no = 0
-    o.begin_path()
-    return value
-
-def label_sized(x, y, w, h, label):
-    global down, was_down
-    add_widget(x,y,w,h)
-    o.font_size = o.height * widget_font_size_vh # why do we need this override
-    o.rgb(*button_fg)
-    o.move_to(x + o.font_size/8, y + h/2 + o.font_size/3).text(label)
-
-
-def button_sized(x, y, w, h, label):
-    global down, was_down
-
-    add_widget(x,y,w,h)
-    result = False
-    o.font_size = o.height * widget_font_size_vh # why do we need this override
-    lwidth = o.text_width (label)
-    o.rectangle(x, y, w, h)
-    o.rgb(*button_bg)
-    if text_edit_no == 0 and down and was_down == False and inside_rect(pointer_x,pointer_y,x,y,w,h):
-      result = True
-      o.rgb(*button_bg_active)    
-    o.fill()
-    o.rgb(*button_fg)
-    o.move_to(x + w/2-lwidth/2, y + h/2 + o.font_size/3).text(label)
-    
-
-    return result
-
-def toggle_sized(x, y, w, h, label, value):
-    global down, was_down
-    add_widget(x,y,w,h)
-    result = value
-
-    o.font_size = o.height * widget_font_size_vh # why do we need this override
-    
-    if text_edit_no == 0 and down and was_down == False and inside_rect(pointer_x,pointer_y,x,y,w,h):
-      result = not value
-      o.rectangle(x, y, w, h).rgb(*button_bg_active).fill()
-
-    o.rgb(*widget_fg)
-    o.move_to(x + o.font_size*0.1, y + o.font_size*0.8)
-    o.text(label)
-    o.save()
-    o.text_align=o.RIGHT
-    o.move_to(x+w,y+o.font_size*0.8)
-    if value:
-        o.text("on")
-    else:
-        o.text("off")
-    o.restore()
-    
-    if text_edit_no != 0:
-       result = value
-    
-    return result
-
-
-def entry_sized(x, y, w, h, label, value, default_value):
-    global down, was_down, cursor_pos, text_edit_no, text_edit_font_size, text_edit_done, text_edit_copy
-    widget_no=add_widget(x,y,w,h)
-    result = value
-    o.font_size = o.height * widget_font_size_vh # why do we need this override
-    
-    o.rgb(*widget_fg)
-    o.move_to(x + o.font_size*0.1, y + o.font_size*0.8)
-    o.text(label)
-    
-    o.save()
-    #o.text_align=o.RIGHT
-    #o.move_to(x+w,y+o.font_size*0.8)
-    #if value:
-    if text_edit_no == widget_no:
-      o.text(text_edit_copy)
-    else:
-      o.text(value)
-    
-    if text_edit_no == 0 and down and was_down == False and inside_rect(pointer_x,pointer_y,x,y,w,h):
-      #result = "baah"#not value
-      #o.rectangle(x, y, w, h).rgb(*button_bg_active).fill()
-      text_edit_copy = value
-      text_edit_no = widget_no
-      text_edit_font_size = o.font_size
-      
-    if text_edit_no == widget_no:
-       cursor_pos=[o.x,o.y]
-       o.move_to(cursor_pos[0],cursor_pos[1])
-
-       o.rgb(1.0,1.0,1.0).text(text_edit_preview)
-       o.rectangle(x, y, w, h).rgb(*button_bg_active).stroke()
-       o.rectangle(cursor_pos[0],cursor_pos[1]-o.font_size,3, o.font_size * 1.1).fill()
-       #o.move_to(cursor_pos[0],cursor_pos[1])
-        
-    if text_edit_done:
-        text_edit_done = False # we only do this once
-        text_edit_no = 0
-        o.restore()
-
-        return text_edit_copy
-    o.restore()
-    return None
-
-def init_geom(x,y,width,height):
-    absolute=True
-    if x==None or y==None:
-      x = edge_left #o.x
-      y = o.y
-      absolute=False
-    if height==None:
-      height = o.height * widget_font_size_vh * widget_height_fs
-    if width==None:
-      width = edge_right-edge_left #o.width
-
-    # convert to integer and drop least signifcant
-    # bit, this makes 2x2 preview renders avoid
-    # rectangle AA
-    x = int(x) & ~1
-    y = int(y) & ~1
-    width = int(width) & ~1
-    height = int(height) & ~1
-      
-    return (x,y,width,height,absolute)
-
-
-def slider(label, value, min, max, x=None, y=None, width=None, height=None):
-    tup = init_geom(x,y,width,height)
-    x=tup[0];y=tup[1];width=tup[2];height=tup[3];absolute=tup[4]
-
-    retval = slider_sized (x, y, width, height, label, value, min, max)
-
-    if not absolute:
-      o.move_to (x, y + height)
-
-    return retval
-
-
-def toggle(label, value, x=None, y=None, width=None, height=None):
-    tup = init_geom(x,y,width,height)
-    x=tup[0];y=tup[1];width=tup[2];height=tup[3];absolute=tup[4]
-
-    retval = toggle_sized (x, y, width, height, label, value)
-
-    if not absolute:
-      o.move_to (x, y + height)
-
-    return retval
-
-
-def button(string, x=None, y=None, width=None, height=None):
-    tup = init_geom(x,y,width,height)
-    x=tup[0];y=tup[1];width=tup[2];height=tup[3];absolute=tup[4]
-    
-    retval = button_sized (x, y, width, height * 0.98, string)
-    if not absolute:
-      o.move_to (x, y + height)
-    return retval
-
-def label(string, x=None, y=None, width=None, height=None):
-    tup = init_geom(x,y,width,height)
-    x=tup[0];y=tup[1];width=tup[2];height=tup[3];absolute=tup[4]
-
-    label_sized (x, y, width, height * 0.98, string)
-    if not absolute:
-      o.move_to (x, y + height)
-    
-def entry(label,string,default_string,x=None,y=None,width=None,height=None):
-    tup = init_geom(x,y,width,height)
-    x=tup[0];y=tup[1];width=tup[2];height=tup[3];absolute=tup[4]
-    string = entry_sized (x, y, width, height * 0.98, label, string, default_string)
-    if not absolute:
-      o.move_to (x, y + height)
-    return string
-
-def coords_press(x, y):
-    global pointer_x, pointer_y, down
-    pointer_x = x
-    pointer_y = y
-    down = True
-
-def coords_motion(x, y):
-    global pointer_x, pointer_y
-    pointer_x = x
-    pointer_y = y
-
-def coords_release(x, y):
-    global pointer_x, pointer_y, down
-    pointer_x = x
-    pointer_y = y
-    down = False
-
-exit = False
-
-KEYs = (
-        (
-            ('q','w','e','r','t','y','u','i','o','p'),
-            ('a','s','d','f','g','h','j','k','l','⏎'),
-            ('z','x','c','v','b','n','m',',','.'),
-            ('ABC',' ',' ',' ',' ',' ',' ',' ',' ','⌫')
-        ),
-        (
-            ('Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P',),
-            ('A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '⏎'),
-            ('Z', 'X', 'C', 'V', 'B', 'N', 'M', ':', '?'),
-            ('123', ' ',' ', ' ', ' ', ' ', ' ', '!',' ','⌫')
-        ),
-        (
-            ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '|'),
-            ('@', '#', '$', '%', '^', '&', '*', '(', ')', '⏎'),
-            ('+','-','=','_','"','\'','[',']'),
-            ('æøå', ' ', '~', '/', '\\', '{','}','`',' ','⌫')
-        ),
-        (
-            ('pu','é', 'ñ', 'ß', 'ü', 'Ü', 'æ', 'ø', 'å', '|'),
-            ('pd', '€', '®', '©', 'Æ', 'Ø', 'Å',' ', ' ', '⏎'),
-            ('ctr' ,'alt', ' ',' ↑', ' ', 'ö','Ö','Å'),
-            ('abc', ' ','←','↓','→', ' ',' ',' ',' ','⌫')
-        )
-
-        
-        # add a layout with cursor keys and modifiers, return space tab escape
-        # home, end insert delta page up page down .. and even some F keys?
-    )
-
-osk_layout=0
-
-def start_frame():
-    global widget_no
-    widget_no = 0
-    o.start_frame()
-    o.rgb(*wallpaper_bg).paint()
-    o.rectangle(0,0,o.width, o.height)#,o.height)
-    o.listen(o.PRESS, lambda e:coords_press(e.x, e.y))
-    o.listen(o.MOTION, lambda e:coords_motion(e.x, e.y))
-    o.listen(o.RELEASE, lambda e:coords_release(e.x, e.y))
-    o.fill()
-
-import math
-
-keyboard_bg=(70/255,70/255,90/255)
-keyboard_fg=(1.0,1.0,1.0)
-
-
-def keyboard(x,y,width,height):
-    global text_edit_copy, cursor_pos, text_edit_preview, osk_layout, text_edit_done
-    o.rectangle(x,y,width,height)
-    #o.listen_stop_propagate(o.PRESS|o.MOTION, lambda e:update_coords(e.x, e.y, True))
-    #o.listen_stop_propagate(o.RELEASE, lambda e:update_coords(e.x, e.y, False))
-    o.rgb(*keyboard_bg).fill()
-    cell_width = width /11.0;
-    cell_height = height / 4.0;
-    o.font_size = cell_height;
-    row_no=0
-    o.save()
-    o.text_align=o.CENTER
-    o.rgb(*keyboard_fg)
-    
-    nearest = False
-    best_dist = 1000
-    
-    for row in KEYS[osk_layout]:
-        col_no = 0
-        for key in row:
-          keyx = x + (col_no+0.5 + row_no/4.0) * cell_width
-          keyy = y + row_no * cell_height + cell_height * 0.5
-
-          dist = math.sqrt((pointer_x-keyx)*(pointer_x-keyx)+ (pointer_y-keyy)*(pointer_y-keyy))
-          if dist < best_dist:
-              best_dist = dist
-              nearest = key
-          o.move_to(keyx, keyy + cell_height * 0.3)
-          label = str(key)
-          label = {'\b':'bs','\n':'nl'}.get(label,label)
-          o.text(label)
-          col_no += 1
-        row_no += 1
-    o.restore()
-    if inside_rect(pointer_x,pointer_y,x,y,width,height):
-      if down:
-        text_edit_preview = nearest
-      else:
-        text_edit_preview = ''
-      if not down and was_down:
-        
-        o.font_size = text_edit_font_size
-        if nearest == '⏎':
-          text_edit_done = True
-        elif nearest == '⌫':
-          if len(text_edit_copy)>0:
-            cursor_pos[0] -= o.text_width (text_edit_copy[-1])
-            text_edit_copy = text_edit_copy[0:-1]
-        elif nearest == 'ABC':
-            osk_layout=1
-        elif nearest == '123':
-            osk_layout=2
-        elif nearest == '<>{':
-            osk_layout=3
-        elif nearest == 'æøå':
-            osk_layout=3
-        elif nearest == 'abc':
-            osk_layout=0
-        else:
-          text_edit_copy += nearest
-          #cursor_pos[0] += o.text_width (nearest)
-          text_edit_preview = ''
-    else:
-       text_edit_preview = ''
-
-def end_frame():
-    global was_down, down, text_edit_no
-    
-    if text_edit_no > 0:
-        keyboard(0,o.height/2,o.width,o.height/2)
-    
-    
-    was_down = down # must happen after all the buttons    
-    gc.collect()
-    o.end_frame()
-    
-
-
-
-
-    
-def nearest_in_list(needle,list):
-    best_score=400000
-    best=needle
-    for i in list:
-        score = abs(i-needle)
-        if score < best_score:
-            best_score = score
-            best=i
-    return best
-
-def choice(label, chosen, choices):
-    return chosen
-
-if __name__=='__main__':
-  exit = 0
-  constrain_332 = False
-  string = ""
-  red = widget_bg[0]
-  green = widget_bg[1]
-  blue = widget_bg[2]
-  chosen = "foo"
-  
-  start_frame()
-  end_frame()
-  gc.collect()
- 
-  while exit < 4: # a hack to let the ui re-settle, makes
-                  # switching apps slower though
-    start_frame()
-    edited_string = entry ("entry: ", string, "default")
-    if edited_string:
-        string = edited_string
-
-    chosen = choice ("among", chosen, ("foo","bar","baz"))
-        
-    label (chosen)
-        
-    constrain_332 = toggle ("RGB332", constrain_332)
-    red  = int(slider("red", red, 0, 255))
-    green  = int(slider("green", green, 0, 255))
-    blue = int(slider("blue", blue, 0, 255))
-
-    o.rectangle (o.x+o.width/2,o.y - o.font_size * 4,o.width * 0.15, o.height * 0.15)
-    o.rgb(red/255,green/255,blue/255).fill()
-    o.rectangle (o.x+o.width/2,o.y - o.font_size * 4,o.width * 0.15, o.height * 0.15)
-    o.rgb(1.0,1.0,1.0).stroke()
-
-    if constrain_332:
-      valid_red=[0,40,80,140,174,209,233,255]  # 176
-      valid_green=[0,40,80,140,174,209,233,255]  # 176
-      valid_blue=[0,80,170,255]    
-      red = nearest_in_list(red, valid_red)
-      green = nearest_in_list(green, valid_green)
-      blue = nearest_in_list(blue, valid_blue)
-
-    if button ("done"):
-        exit = True
-
-    if button("x", x=40, y=40, width=50, height=50):
-        exit = True
-
-    if False:
-      widget_bg[0] = red
-      widget_bg[1] = green
-      widget_bg[2] = blue
-        
-    
-    end_frame()
-    gc.collect()
-    if exit > 0:
-        exit += 1
-
diff --git a/usermodule/uctx/uctx/micropython.cmake b/usermodule/uctx/uctx/micropython.cmake
deleted file mode 100644
index d89ff82860..0000000000
--- a/usermodule/uctx/uctx/micropython.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-add_library(usermod_ctx INTERFACE)
-
-target_sources(usermod_ctx INTERFACE
-    ${CMAKE_CURRENT_LIST_DIR}/uctx.c
-)
-
-target_include_directories(usermod_ctx INTERFACE
-    ${CMAKE_CURRENT_LIST_DIR}
-    ${CMAKE_CURRENT_LIST_DIR}/../fonts
-)
-
-target_link_libraries(usermod INTERFACE usermod_ctx)
diff --git a/usermodule/uctx/uctx/micropython.mk b/usermodule/uctx/uctx/micropython.mk
deleted file mode 100644
index c9c838e78e..0000000000
--- a/usermodule/uctx/uctx/micropython.mk
+++ /dev/null
@@ -1,6 +0,0 @@
-CTX_MOD_DIR := $(USERMOD_DIR)
-SRC_USERMOD += $(addprefix $(CTX_MOD_DIR)/, \
-	uctx.c \
-)
-CFLAGS_USERMOD += -I$(CTX_MOD_DIR) -DMODULE_CTX_ENABLED=1 -I$(CTX_MOD_DIR)/../fonts
-# CFLAGS_USERMOD += -DEXPOSE_EXTRA_METHODS=1
-- 
GitLab