diff --git a/components/ctx/ctx_config.h b/components/ctx/ctx_config.h
index 2da210588b2300b20109b059ee869544542da622..33864b1069afcb1ed5fad0664f5f99a1b4de6689 100644
--- a/components/ctx/ctx_config.h
+++ b/components/ctx/ctx_config.h
@@ -20,6 +20,7 @@
 #define CTX_TVG_STDIO 0
 #define CTX_DITHER    1
 
+#define CTX_ST3M_FB_INTERNAL_RAM      0
 #define CTX_PDF                       0
 #define CTX_PROTOCOL_U8_COLOR         1
 #define CTX_AVOID_CLIPPED_SUBDIVISION 0
@@ -28,7 +29,7 @@
 #define CTX_32BIT_SEGMENTS            0
 #define CTX_ENABLE_RGBA8              1
 #define CTX_ENABLE_RGB8               1
-#define CTX_ENABLE_RGB332             0
+#define CTX_ENABLE_RGB332             1
 #define CTX_ENABLE_RGB565             1
 #define CTX_ENABLE_RGB565_BYTESWAPPED 1
 #define CTX_ENABLE_CBRLE              0
diff --git a/components/flow3r_bsp/flow3r_bsp.h b/components/flow3r_bsp/flow3r_bsp.h
index e5e84f6c072fec73ed97b946d46e31cc9c499342..d75a16d2f9595ed20aa8eb367925a44ad16a96a2 100644
--- a/components/flow3r_bsp/flow3r_bsp.h
+++ b/components/flow3r_bsp/flow3r_bsp.h
@@ -25,9 +25,9 @@ void flow3r_bsp_display_init(void);
 // performed simultaneously.
 void flow3r_bsp_display_send_fb(void *fb_data, int bits);
 
-void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, void *osd_data,
-                                    int osd_x0, int osd_y0, int osd_x1,
-                                    int osd_y1);
+void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, int scale,
+                                    void *osd_data, int osd_x0, int osd_y0,
+                                    int osd_x1, int osd_y1);
 
 // Set display backlight, as integer percent value (from 0 to 100, clamped).
 // No-op if display hasn't been succesfully initialized.
diff --git a/components/flow3r_bsp/flow3r_bsp_display.c b/components/flow3r_bsp/flow3r_bsp_display.c
index 38983e1189ea86571f5481edc6c3cd4d99872ea0..9c78e1663c09024aee8347310e8cf732fd099b3f 100644
--- a/components/flow3r_bsp/flow3r_bsp_display.c
+++ b/components/flow3r_bsp/flow3r_bsp_display.c
@@ -36,16 +36,17 @@ void flow3r_bsp_display_init(void) {
     }
 }
 
-void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, void *osd_data,
-                                    int osd_x0, int osd_y0, int osd_x1,
-                                    int osd_y1) {
+void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, int scale,
+                                    void *osd_data, int osd_x0, int osd_y0,
+                                    int osd_x1, int osd_y1) {
     if (!gc9a01_initialized) {
         return;
     }
     static bool had_error = false;
 
-    esp_err_t ret = flow3r_bsp_gc9a01_blit_osd(&gc9a01, fb_data, bits, osd_data,
-                                               osd_x0, osd_y0, osd_x1, osd_y1);
+    esp_err_t ret =
+        flow3r_bsp_gc9a01_blit_osd(&gc9a01, fb_data, bits, scale, osd_data,
+                                   osd_x0, osd_y0, osd_x1, osd_y1);
     if (ret != ESP_OK) {
         if (!had_error) {
             ESP_LOGE(TAG, "display blit failed: %s", esp_err_to_name(ret));
@@ -60,7 +61,7 @@ void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, void *osd_data,
 }
 
 void flow3r_bsp_display_send_fb(void *fb_data, int bits) {
-    flow3r_bsp_display_send_fb_osd(fb_data, bits, NULL, 0, 0, 0, 0);
+    flow3r_bsp_display_send_fb_osd(fb_data, bits, 1, NULL, 0, 0, 0, 0);
 }
 
 void flow3r_bsp_display_set_backlight(uint8_t percent) {
diff --git a/components/flow3r_bsp/flow3r_bsp_gc9a01.c b/components/flow3r_bsp/flow3r_bsp_gc9a01.c
index 1ad9ed215f72d9cc2ca166ae7ede4e8ce66abc23..8b40e0dc6752b20054af2374abf29ebb00e579c9 100644
--- a/components/flow3r_bsp/flow3r_bsp_gc9a01.c
+++ b/components/flow3r_bsp/flow3r_bsp_gc9a01.c
@@ -106,6 +106,7 @@ typedef struct {
     int osd_y1;
     uint16_t *pal_16;
     int bits;
+    int scale;
     size_t left;
     size_t off;  // current pixel offset in blit
 
@@ -618,9 +619,12 @@ static inline uint16_t ctx_565_pack(uint8_t red, uint8_t green, uint8_t blue,
 
 #define U8_LERP(a, b, t) ((a) + ((((b) - (a)) * t + 256) >> 8))
 
+extern uint8_t st3m_pal[256 * 3];
+EXT_RAM_BSS_ATTR static uint16_t st3m_pal16[256];
+
 static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit,
                                  int pix_count) {
-    int scale = 1;
+    int scale = blit->scale;
     const uint8_t *fb = blit->fb;
     const uint8_t *osd_fb = blit->osd_fb;
     unsigned int start_off = blit->off;
@@ -631,37 +635,56 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit,
         /* XXX : this code has room for optimization */
         if (osd_fb && (start_off < blit->osd_y1 * 240)) switch (blit->bits) {
                 case 8:
+                case 9:
                     for (unsigned int i = start_off; i < end_off; i++) {
                         int x = i % 240;
                         int y = i / 240;
                         int j = ((y / scale) * 240) + x / scale;
-                        temp_blit[o++] = blit->pal_16[U8_LERP(
-                            fb[j], osd_fb[i * 4 + 1], osd_fb[i * 4 + 3])];
+                        int idx = fb[j];
+                        uint8_t r = (((idx >> 5) & 7) * 255) / 7;
+                        uint8_t g = (((idx >> 2) & 7) * 255) / 7;
+                        uint8_t b =
+                            ((((idx & 3) << 1) | ((idx >> 2) & 1)) * 255) / 7;
+
+                        uint8_t ya = osd_fb[j * 4 + 3];
+
+                        r = U8_LERP(r, osd_fb[j * 4 + 0], ya);
+                        g = U8_LERP(g, osd_fb[j * 4 + 1], ya);
+                        b = U8_LERP(b, osd_fb[j * 4 + 2], ya);
+
+                        idx = ((ctx_sadd8(r, 15) >> 5) << 5) |
+                              ((ctx_sadd8(g, 15) >> 5) << 2) |
+                              (ctx_sadd8(b, 15) >> 6);
+
+                        temp_blit[o++] = blit->pal_16[idx];
                     }
                     break;
                 case 24:
                     for (unsigned int i = start_off; i < end_off; i++) {
-                        uint8_t Y = osd_fb[i * 2];
-                        uint8_t ya = osd_fb[i * 2 + 1];
                         int x = i % 240;
                         int y = i / 240;
                         int j = ((y / scale) * 240) + x / scale;
-                        uint8_t r = U8_LERP(fb[j * 3 + 0], Y, ya);
-                        uint8_t g = U8_LERP(fb[j * 3 + 1], Y, ya);
-                        uint8_t b = U8_LERP(fb[j * 3 + 2], Y, ya);
+                        uint8_t Y = osd_fb[j * 2];
+                        uint8_t ya = osd_fb[j * 2 + 1];
+                        j *= 3;
+                        uint8_t r = U8_LERP(fb[j + 0], Y, ya);
+                        uint8_t g = U8_LERP(fb[j + 1], Y, ya);
+                        uint8_t b = U8_LERP(fb[j + 2], Y, ya);
                         temp_blit[o++] = ctx_565_pack(r, g, b, 1);
                     }
                     break;
                 case 32:
                     for (unsigned int i = start_off; i < end_off; i++) {
-                        uint8_t Y = osd_fb[i * 2];
-                        uint8_t Ya = osd_fb[i * 2 + 1];
                         int x = i % 240;
                         int y = i / 240;
                         int j = ((y / scale) * 240) + x / scale;
-                        uint8_t r = U8_LERP(fb[j * 4 + 0], Y, Ya);
-                        uint8_t g = U8_LERP(fb[j * 4 + 1], Y, Ya);
-                        uint8_t b = U8_LERP(fb[j * 4 + 2], Y, Ya);
+                        j *= 2;
+                        uint8_t Y = osd_fb[j];
+                        uint8_t Ya = osd_fb[j + 1];
+                        j *= 2;
+                        uint8_t r = U8_LERP(fb[j + 0], Y, Ya);
+                        uint8_t g = U8_LERP(fb[j + 1], Y, Ya);
+                        uint8_t b = U8_LERP(fb[j + 2], Y, Ya);
                         temp_blit[o++] = ctx_565_pack(r, g, b, 1);
                     }
                     break;
@@ -673,10 +696,11 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit,
                         uint32_t col =
                             ctx_565_unpack_32(((uint16_t *)fb)[j], 1);
                         uint8_t *rgba = (uint8_t *)&col;
-                        uint8_t sr = osd_fb[i * 4];
-                        uint8_t sg = osd_fb[i * 4 + 1];
-                        uint8_t sb = osd_fb[i * 4 + 2];
-                        uint8_t sa = osd_fb[i * 4 + 3];
+                        j *= 4;
+                        uint8_t sr = osd_fb[j];
+                        uint8_t sg = osd_fb[j + 1];
+                        uint8_t sb = osd_fb[j + 2];
+                        uint8_t sa = osd_fb[j + 3];
                         uint8_t dr = U8_LERP(rgba[0], sr, sa);
                         uint8_t dg = U8_LERP(rgba[1], sg, sa);
                         uint8_t db = U8_LERP(rgba[2], sb, sa);
@@ -695,6 +719,7 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit,
                     }
                     break;
                 case 8:
+                case 9:
                     for (unsigned int i = start_off; i < end_off; i++) {
                         int x = i % 240;
                         int y = i / 240;
@@ -724,18 +749,21 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit,
             // blit->osd_fb = NULL;
             // blit->fb += ((end_off*blit->bits)/8);
         }
-    } else {
+    }
+
+    else {  // not scaled
         if (osd_fb && (start_off < blit->osd_y1 * 240)) switch (blit->bits) {
-#if 0
-        case 1:
-            for (unsigned int i = 0; i < pix_count; i++)
-                temp_blit[o++] = blit->pal_16[(fb[i / 8] >> ((i & 7))) & 0x1];
-            break;
-        case 2:
-            for (unsigned int i = 0; i < pix_count; i++)
-                temp_blit[o++] =
-                    blit->pal_16[(fb[i / 4] >> ((i & 3) * 2)) & 0x3];
-            break;
+#if 1
+                case 1:
+                    for (unsigned int i = start_off; i < end_off; i++)
+                        temp_blit[o++] =
+                            blit->pal_16[(fb[i / 8] >> ((i & 7))) & 0x1];
+                    break;
+                case 2:
+                    for (unsigned int i = start_off; i < end_off; i++)
+                        temp_blit[o++] =
+                            blit->pal_16[(fb[i / 4] >> ((i & 3) * 2)) & 0x3];
+                    break;
 #endif
                 case 4:
                     for (unsigned int i = start_off; i < end_off; i++) {
@@ -748,6 +776,26 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit,
                         temp_blit[o++] = blit->pal_16[U8_LERP(
                             fb[i], osd_fb[i * 4 + 1], osd_fb[i * 4 + 3])];
                     break;
+                case 9:
+                    for (unsigned int i = start_off; i < end_off; i++) {
+                        int idx = fb[i];
+                        uint8_t r = (((idx >> 5) & 7) * 255) / 7;
+                        uint8_t g = (((idx >> 2) & 7) * 255) / 7;
+                        uint8_t b =
+                            ((((idx & 3) << 1) | ((idx >> 2) & 1)) * 255) / 7;
+                        uint8_t ya = osd_fb[i * 4 + 3];
+
+                        r = U8_LERP(r, osd_fb[i * 4 + 0], ya);
+                        g = U8_LERP(g, osd_fb[i * 4 + 1], ya);
+                        b = U8_LERP(b, osd_fb[i * 4 + 2], ya);
+
+                        idx = ((ctx_sadd8(r, 15) >> 5) << 5) |
+                              ((ctx_sadd8(g, 15) >> 5) << 2) |
+                              (ctx_sadd8(b, 15) >> 6);
+
+                        temp_blit[o++] = blit->pal_16[idx];
+                    }
+                    break;
                 case 24:
                     for (unsigned int i = start_off; i < end_off; i++) {
                         uint8_t y = osd_fb[i * 2];
@@ -810,6 +858,7 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit,
                     }
                     break;
                 case 8:
+                case 9:
                     for (unsigned int i = start_off; i < end_off; i++)
                         temp_blit[o++] = blit->pal_16[fb[i]];
                     break;
@@ -837,7 +886,9 @@ static esp_err_t flow3r_bsp_gc9a01_blit_next(flow3r_bsp_gc9a01_blit_t *blit) {
         size = SPI_MAX_DMA_LEN;
     }
     unsigned int pix_count = size / 2;
-    size_t osize = pix_count * blit->bits / 8;
+    int bits = blit->bits;
+    if (bits == 9) bits = 8;
+    size_t osize = pix_count * bits / 8;
 
     blit->gc9a01_tx.gc9a01 = blit->gc9a01;
     blit->gc9a01_tx.dc = 1;
@@ -875,9 +926,9 @@ static esp_err_t flow3r_bsp_gc9a01_blit_next(flow3r_bsp_gc9a01_blit_t *blit) {
 static esp_err_t flow3r_bsp_gc9a01_blit_start(flow3r_bsp_gc9a01_t *gc9a01,
                                               flow3r_bsp_gc9a01_blit_t *blit,
                                               const uint16_t *fb, int bits,
-                                              const void *osd_fb, int osd_x0,
-                                              int osd_y0, int osd_x1,
-                                              int osd_y1) {
+                                              int scale, const void *osd_fb,
+                                              int osd_x0, int osd_y0,
+                                              int osd_x1, int osd_y1) {
     memset(blit, 0, sizeof(flow3r_bsp_gc9a01_blit_t));
 
     blit->gc9a01 = gc9a01;
@@ -888,10 +939,11 @@ static esp_err_t flow3r_bsp_gc9a01_blit_start(flow3r_bsp_gc9a01_t *gc9a01,
     blit->osd_x1 = osd_x1;
     blit->osd_y0 = osd_y0;
     blit->osd_y1 = osd_y1;
+    blit->scale = scale;
     blit->left = 2 * 240 * 240;  // left in native bytes (16bpp)
     if (bits < 16) {
-        uint8_t *pal_24 = ((uint8_t *)fb) + 240 * 240 * 2 - 3 * 256;
-        blit->pal_16 = (uint16_t *)(pal_24 - 256 * 2);
+        uint8_t *pal_24 = st3m_pal;
+        blit->pal_16 = st3m_pal16;
         for (int i = 0; i < 256; i++)
             blit->pal_16[i] = ctx_565_pack(pal_24[i * 3 + 0], pal_24[i * 3 + 1],
                                            pal_24[i * 3 + 2], 1);
@@ -915,12 +967,12 @@ static esp_err_t flow3r_bsp_gc9a01_blit_wait_done(
 }
 
 esp_err_t flow3r_bsp_gc9a01_blit_osd(flow3r_bsp_gc9a01_t *gc9a01,
-                                     const void *fb, int bits,
+                                     const void *fb, int bits, int scale,
                                      const void *osd_fb, int osd_x0, int osd_y0,
                                      int osd_x1, int osd_y1) {
     flow3r_bsp_gc9a01_blit_t blit;
     esp_err_t res = flow3r_bsp_gc9a01_blit_start(
-        gc9a01, &blit, fb, bits, osd_fb, osd_x0, osd_y0, osd_x1, osd_y1);
+        gc9a01, &blit, fb, bits, scale, osd_fb, osd_x0, osd_y0, osd_x1, osd_y1);
     if (res != ESP_OK) {
         return res;
     }
@@ -940,5 +992,5 @@ esp_err_t flow3r_bsp_gc9a01_blit_osd(flow3r_bsp_gc9a01_t *gc9a01,
 
 esp_err_t flow3r_bsp_gc9a01_blit_full(flow3r_bsp_gc9a01_t *gc9a01,
                                       const void *fb, int bits) {
-    return flow3r_bsp_gc9a01_blit_osd(gc9a01, fb, bits, NULL, 0, 0, 0, 0);
+    return flow3r_bsp_gc9a01_blit_osd(gc9a01, fb, bits, 1, NULL, 0, 0, 0, 0);
 }
diff --git a/components/flow3r_bsp/flow3r_bsp_gc9a01.h b/components/flow3r_bsp/flow3r_bsp_gc9a01.h
index 6ad1d631648f144b8a043ad9820eb0b6eef61e50..dfc2d197184c3ed059271cc1791d3dcb0de70a19 100644
--- a/components/flow3r_bsp/flow3r_bsp_gc9a01.h
+++ b/components/flow3r_bsp/flow3r_bsp_gc9a01.h
@@ -70,7 +70,7 @@ esp_err_t flow3r_bsp_gc9a01_init(flow3r_bsp_gc9a01_t *gc9a01,
 esp_err_t flow3r_bsp_gc9a01_blit_full(flow3r_bsp_gc9a01_t *gc9a01,
                                       const void *fb, int bits);
 esp_err_t flow3r_bsp_gc9a01_blit_osd(flow3r_bsp_gc9a01_t *gc9a01,
-                                     const void *fb, int bits,
+                                     const void *fb, int bits, int scale,
                                      const void *osd_fb, int osd_x0, int osd_y0,
                                      int osd_x1, int osd_y1);
 
diff --git a/components/micropython/usermodule/mp_sys_display.c b/components/micropython/usermodule/mp_sys_display.c
index 61f981a9e5b24350b44d4e96a8448cbd368766f3..806ed1ae1a9c2c277e7f76dace7bc84caa96a108 100644
--- a/components/micropython/usermodule/mp_sys_display.c
+++ b/components/micropython/usermodule/mp_sys_display.c
@@ -78,6 +78,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_ctx_obj, mp_ctx);
 STATIC mp_obj_t mp_fb(mp_obj_t mode_in) {
     int mode = mp_obj_get_int(mode_in);
     int size = 240 * 240 * st3m_gfx_bpp(mode) / 8;
+    if (mode == st3m_gfx_palette) size = 256 * 3;
     return mp_obj_new_bytearray_by_ref(size, st3m_gfx_fb(mode));
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_fb_obj, mp_fb);
@@ -122,6 +123,26 @@ STATIC const mp_rom_map_elem_t mp_module_sys_display_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&mp_set_palette_obj) },
     { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&mp_set_backlight_obj) },
     { MP_ROM_QSTR(MP_QSTR_overlay_clip), MP_ROM_PTR(&mp_overlay_clip_obj) },
+
+    { MP_ROM_QSTR(MP_QSTR_default), MP_ROM_INT((int)st3m_gfx_default) },
+    { MP_ROM_QSTR(MP_QSTR_rgb332), MP_ROM_INT((int)st3m_gfx_rgb332) },
+    { MP_ROM_QSTR(MP_QSTR_sepia), MP_ROM_INT((int)st3m_gfx_sepia) },
+    { MP_ROM_QSTR(MP_QSTR_cool), MP_ROM_INT((int)st3m_gfx_cool) },
+    { MP_ROM_QSTR(MP_QSTR_low_latency), MP_ROM_INT((int)st3m_gfx_low_latency) },
+    { MP_ROM_QSTR(MP_QSTR_direct_ctx), MP_ROM_INT((int)st3m_gfx_direct_ctx) },
+    { MP_ROM_QSTR(MP_QSTR_unset), MP_ROM_INT((int)st3m_gfx_unset) },
+    { MP_ROM_QSTR(MP_QSTR_force), MP_ROM_INT((int)st3m_gfx_force) },
+    { MP_ROM_QSTR(MP_QSTR_x2), MP_ROM_INT((int)st3m_gfx_2x) },
+    { MP_ROM_QSTR(MP_QSTR_x3), MP_ROM_INT((int)st3m_gfx_3x) },
+    { MP_ROM_QSTR(MP_QSTR_x4), MP_ROM_INT((int)st3m_gfx_4x) },
+    { MP_ROM_QSTR(MP_QSTR_bpp1), MP_ROM_INT((int)st3m_gfx_1bpp) },
+    { MP_ROM_QSTR(MP_QSTR_bpp2), MP_ROM_INT((int)st3m_gfx_2bpp) },
+    { MP_ROM_QSTR(MP_QSTR_bpp4), MP_ROM_INT((int)st3m_gfx_4bpp) },
+    { MP_ROM_QSTR(MP_QSTR_bpp8), MP_ROM_INT((int)st3m_gfx_8bpp) },
+    { MP_ROM_QSTR(MP_QSTR_bpp16), MP_ROM_INT((int)st3m_gfx_16bpp) },
+    { MP_ROM_QSTR(MP_QSTR_bpp24), MP_ROM_INT((int)st3m_gfx_24bpp) },
+    { MP_ROM_QSTR(MP_QSTR_osd), MP_ROM_INT((int)st3m_gfx_osd) },
+    { MP_ROM_QSTR(MP_QSTR_palette), MP_ROM_INT((int)st3m_gfx_palette) },
 };
 
 STATIC MP_DEFINE_CONST_DICT(mp_module_sys_display_globals,
diff --git a/components/st3m/st3m_gfx.c b/components/st3m/st3m_gfx.c
index 23bcfe09d7eba09f993b327a1ca3d097fa7caa41..89c42f52630d09a8ac46ffb1b046458073ba01db 100644
--- a/components/st3m/st3m_gfx.c
+++ b/components/st3m/st3m_gfx.c
@@ -26,7 +26,14 @@ static st3m_gfx_mode default_mode = ST3M_GFX_DEFAULT_MODE;
 
 // if the EXT_RAM_BSS_ATTR is removed 8bit and 16bit modes go
 // faster but it is not possible to enable wifi
+
+#if CTX_ST3M_FB_INTERNAL_RAM
+static uint16_t st3m_fb[240 * 240];
+uint8_t st3m_pal[256 * 3];
+#else
 EXT_RAM_BSS_ATTR static uint16_t st3m_fb[240 * 240];
+EXT_RAM_BSS_ATTR uint8_t st3m_pal[256 * 3];
+#endif
 
 // Get a free drawlist ctx to draw into.
 //
@@ -58,6 +65,7 @@ EXT_RAM_BSS_ATTR static uint8_t
 static Ctx *fb_GRAY8_ctx = NULL;
 static Ctx *fb_GRAYA8_ctx = NULL;
 static Ctx *fb_RGB565_BS_ctx = NULL;
+static Ctx *fb_RGB332_ctx = NULL;
 static Ctx *fb_RGBA8_ctx = NULL;
 static Ctx *fb_RGB8_ctx = NULL;
 
@@ -90,6 +98,19 @@ static TaskHandle_t graphics_task;
 
 static int _st3m_gfx_low_latency = 0;
 
+static int st3m_gfx_scale(void) {
+    st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode;
+    switch ((int)(set_mode & st3m_gfx_4x)) {
+        case st3m_gfx_4x:
+            return 4;
+        case st3m_gfx_3x:
+            return 3;
+        case st3m_gfx_2x:
+            return 2;
+    }
+    return 1;
+}
+
 ///////////////////////////////////////////////////////
 
 // get the bits per pixel for a given mode
@@ -99,11 +120,12 @@ int st3m_gfx_bpp(st3m_gfx_mode mode) {
         mode = set_mode;
     } else if (mode == st3m_gfx_osd) {
         if ((st3m_gfx_bpp(set_mode) == 16) || (st3m_gfx_bpp(set_mode) == 8))
-            return 4;
+            return 32;
         else
-            return 2;
+            return 16;
     }
-    return (mode & (4 | 8 | 16 | 24 | 32));
+    if ((mode & 0xf) == 4) return 4;
+    return (mode & (8 | 16 | 24 | 32));
 }
 
 static Ctx *st3m_gfx_ctx_int(st3m_gfx_mode mode) {
@@ -131,21 +153,35 @@ static Ctx *st3m_gfx_ctx_int(st3m_gfx_mode mode) {
     }
     return ctx;
 }
+
+void st3m_gfx_viewport_transform(Ctx *ctx) {
+    int scale = st3m_gfx_scale();
+    int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2 / scale;
+    int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2 / scale;
+    ctx_identity(ctx);  // this might break/need revisiting with tiled rendering
+    ctx_apply_transform(ctx, 1.0 / scale, 0, offset_x, 0, 1.0 / scale, offset_y,
+                        0, 0, 1);
+}
+
+void st3m_gfx_start_frame(Ctx *ctx) {
+    int scale = st3m_gfx_scale();
+    ctx_save(ctx);
+    st3m_gfx_viewport_transform(ctx);
+    if (scale) {
+        ctx_rectangle(ctx, -120, -120, 240, 240);
+        ctx_clip(ctx);
+    }
+}
+
 Ctx *st3m_gfx_ctx(st3m_gfx_mode mode) {
     Ctx *ctx = st3m_gfx_ctx_int(mode);
     if (mode == st3m_gfx_osd) {
         pthread_mutex_lock(&st3m_osd_mutex);
     }
+    st3m_gfx_start_frame(ctx);
     return ctx;
 }
 
-void st3m_gfx_viewport_transform(Ctx *ctx) {
-    int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2;
-    int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2;
-    ctx_identity(ctx);  // this might break/need revisiting with tiled rendering
-    ctx_apply_transform(ctx, 1, 0, offset_x, 0, 1, offset_y, 0, 0, 1);
-}
-
 // Attempt to receive from a queue forever, but log an error if it takes longer
 // than two seconds to get something.
 static void xQueueReceiveNotifyStarved(QueueHandle_t q, void *dst,
@@ -167,72 +203,109 @@ float st3m_gfx_fps(void) { return smoothed_fps; }
 void st3m_gfx_set_palette(uint8_t *pal_in, int count) {
     if (count > 256) count = 256;
     if (count < 0) count = 0;
-    uint8_t *pal = ((uint8_t *)st3m_fb) + sizeof(st3m_fb) - 256 * 3;
-    for (int i = 0; i < count * 3; i++) pal[i] = pal_in[i];
-}
-
-static void ega_palette(void) {
-    uint8_t pal[16 * 3];
-    int idx = 0;
-    for (int i = 0; i < 2; i++)
-        for (int r = 0; r < 2; r++)
-            for (int g = 0; g < 2; g++)
-                for (int b = 0; b < 2; b++) {
-                    pal[idx++] = (r * 127) * (i * 2);
-                    pal[idx++] = (g * 127) * (i * 2);
-                    pal[idx++] = (b * 127) * (i * 2);
-                }
-    st3m_gfx_set_palette(pal, 16);
+    for (int i = 0; i < count * 3; i++) st3m_pal[i] = pal_in[i];
 }
 
-static void gray_palette(void) {
-    uint8_t pal[256 * 3];
-    for (int i = 0; i < 256; i++) {
-        pal[i * 3 + 0] = i;
-        pal[i * 3 + 1] = i;
-        pal[i * 3 + 2] = i;
-    }
-    st3m_gfx_set_palette(pal, 256);
-}
-
-static void sepia_palette(void) {
-    uint8_t pal[256 * 3];
-    for (int i = 0; i < 256; i++) {
-        pal[i * 3 + 0] = i;
-        pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255;
-        pal[i * 3 + 2] = (i / 255.0) * (i / 255.0) * (i / 255.0) * 255;
+void st3m_gfx_set_default_mode(st3m_gfx_mode mode) {
+    if (mode & st3m_gfx_unset) {
+        if (mode & st3m_gfx_force)
+            default_mode &= ~st3m_gfx_force;
+        else if (mode & st3m_gfx_4x)
+            default_mode &= ~st3m_gfx_4x;
+        else if (mode & st3m_gfx_osd)
+            default_mode &= ~st3m_gfx_osd;
+        else if (mode & st3m_gfx_low_latency)
+            default_mode &= ~st3m_gfx_low_latency;
+        else if (mode & st3m_gfx_direct_ctx)
+            default_mode &= ~st3m_gfx_direct_ctx;
+    } else if (mode == st3m_gfx_2x) {
+        default_mode &= ~st3m_gfx_4x;
+        default_mode |= st3m_gfx_2x;
+    } else if (mode == st3m_gfx_3x) {
+        default_mode &= ~st3m_gfx_4x;
+        default_mode |= st3m_gfx_3x;
+    } else if (mode == st3m_gfx_4x) {
+        default_mode &= ~st3m_gfx_4x;
+        default_mode |= st3m_gfx_4x;
+    } else if (mode == st3m_gfx_2x + st3m_gfx_low_latency) {
+        default_mode |= st3m_gfx_2x;
+        default_mode |= st3m_gfx_low_latency;
+    } else if (mode == st3m_gfx_osd + st3m_gfx_low_latency) {
+        default_mode |= st3m_gfx_osd;
+        default_mode |= st3m_gfx_low_latency;
+    } else if (mode == st3m_gfx_osd) {
+        default_mode |= st3m_gfx_osd;
+    } else if (mode == st3m_gfx_low_latency) {
+        default_mode |= st3m_gfx_low_latency;
+    } else if (mode == st3m_gfx_force) {
+        default_mode |= st3m_gfx_force;
+    } else if (mode == st3m_gfx_direct_ctx) {
+        default_mode |= st3m_gfx_direct_ctx;
+    } else
+        default_mode = mode;
+
+    if (default_mode & st3m_gfx_force) {
+        default_mode &= ~st3m_gfx_force;
+        _st3m_gfx_mode = default_mode + 1;
+        st3m_gfx_set_mode(st3m_gfx_default);
+        default_mode |= st3m_gfx_force;
+    } else {
+        _st3m_gfx_mode = default_mode + 1;
+        st3m_gfx_set_mode(st3m_gfx_default);
     }
-    st3m_gfx_set_palette(pal, 256);
 }
 
-static void cool_palette(void) {
-    uint8_t pal[256 * 3];
-    for (int i = 0; i < 256; i++) {
-        pal[i * 3 + 0] = (i / 255.0) * (i / 255.0) * (i / 255.0) * 255;
-        pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255;
-        pal[i * 3 + 2] = i;
+static void st3m_gfx_init_palette(st3m_gfx_mode mode) {
+    switch (mode & 0xf) {
+        case 4: {
+            int idx = 0;
+            for (int i = 0; i < 2; i++)
+                for (int r = 0; r < 2; r++)
+                    for (int g = 0; g < 2; g++)
+                        for (int b = 0; b < 2; b++) {
+                            st3m_pal[idx++] = (r * 127) * (i * 2);
+                            st3m_pal[idx++] = (g * 127) * (i * 2);
+                            st3m_pal[idx++] = (b * 127) * (i * 2);
+                        }
+        } break;
+        case 8:  // grayscale
+            for (int i = 0; i < 256; i++) {
+                st3m_pal[i * 3 + 0] = i;
+                st3m_pal[i * 3 + 1] = i;
+                st3m_pal[i * 3 + 2] = i;
+            }
+            break;
+        case st3m_gfx_rgb332:
+            for (int i = 0; i < 256; i++) {
+                st3m_pal[i * 3 + 0] = (((i >> 5) & 7) * 255) / 7;
+                st3m_pal[i * 3 + 1] = (((i >> 2) & 7) * 255) / 7;
+                st3m_pal[i * 3 + 2] =
+                    ((((i & 3) << 1) | ((i >> 2) & 1)) * 255) / 7;
+            }
+            break;
+        case st3m_gfx_sepia:
+            for (int i = 0; i < 256; i++) {
+                st3m_pal[i * 3 + 0] = i;
+                st3m_pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255;
+                st3m_pal[i * 3 + 2] =
+                    (i / 255.0) * (i / 255.0) * (i / 255.0) * 255;
+            }
+            break;
+        case st3m_gfx_cool:
+            for (int i = 0; i < 256; i++) {
+                st3m_pal[i * 3 + 0] =
+                    (i / 255.0) * (i / 255.0) * (i / 255.0) * 255;
+                st3m_pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255;
+                st3m_pal[i * 3 + 2] = i;
+            }
+            break;
     }
-    st3m_gfx_set_palette(pal, 256);
 }
 
-static void red_palette(void) {
-    uint8_t pal[256 * 3];
-    for (int i = 0; i < 256; i++) {
-        pal[i * 3 + 0] = i < 64 ? (i * 4) : 255;
-        pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255;
-        pal[i * 3 + 2] = (i / 255.0) * (i / 255.0) * (i / 255.0) * 255;
+st3m_gfx_mode st3m_gfx_set_mode(st3m_gfx_mode mode) {
+    if ((mode == _st3m_gfx_mode) || (0 != (default_mode & st3m_gfx_force))) {
+        return (mode ? mode : default_mode);
     }
-    st3m_gfx_set_palette(pal, 256);
-}
-
-void st3m_gfx_set_default_mode(st3m_gfx_mode mode) {
-    default_mode = mode;
-    _st3m_gfx_mode = default_mode + 1;
-    st3m_gfx_set_mode(st3m_gfx_default);
-}
-
-void st3m_gfx_set_mode(st3m_gfx_mode mode) {
-    if (mode == _st3m_gfx_mode) return;
 
     memset(st3m_fb, 0, sizeof(st3m_fb));
     memset(st3m_osd_fb, 0, sizeof(st3m_osd_fb));
@@ -244,30 +317,9 @@ void st3m_gfx_set_mode(st3m_gfx_mode mode) {
     else if (mode == st3m_gfx_osd)
         mode = default_mode | st3m_gfx_osd;
 
-    switch (mode & 0xf) {
-        case 4:
-            ega_palette();
-            break;
-        case 8:
-            sepia_palette();
-            break;
-        case 9:
-            red_palette();
-            break;
-        case 10:
-            gray_palette();
-            break;
-        case 11:
-            cool_palette();
-            break;
-    }
+    st3m_gfx_init_palette(mode);
 
-    if (mode == default_mode)
-        _st3m_gfx_mode = st3m_gfx_default;
-    else if (mode == (default_mode + st3m_gfx_low_latency))
-        _st3m_gfx_mode = st3m_gfx_low_latency;
-    else
-        _st3m_gfx_mode = mode;
+    _st3m_gfx_mode = (mode == default_mode) ? st3m_gfx_default : mode;
 
     _st3m_gfx_low_latency = ((mode & st3m_gfx_low_latency) != 0);
     switch ((int)mode) {
@@ -278,13 +330,16 @@ void st3m_gfx_set_mode(st3m_gfx_mode mode) {
         case st3m_gfx_24bpp_direct_ctx:
             _st3m_gfx_low_latency = 1;
     }
+    return mode;
 }
 
 st3m_gfx_mode st3m_gfx_get_mode(void) { return _st3m_gfx_mode; }
 
 uint8_t *st3m_gfx_fb(st3m_gfx_mode mode) {
     st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode;
-    if (mode == st3m_gfx_default) {
+    if (mode == st3m_gfx_palette) {
+        return st3m_pal;
+    } else if (mode == st3m_gfx_default) {
         if (st3m_gfx_bpp(set_mode) <= 16) return (uint8_t *)st3m_fb;
         return st3m_osd_fb;
     } else if (mode == st3m_gfx_osd) {
@@ -310,6 +365,7 @@ static void st3m_gfx_task(void *_arg) {
         ctx_set_textureclock(fb_RGB565_BS_ctx,
                              ctx_textureclock(fb_RGB565_BS_ctx) + 1);
         ctx_set_textureclock(fb_RGBA8_ctx, ctx_textureclock(fb_RGB565_BS_ctx));
+        ctx_set_textureclock(fb_RGB332_ctx, ctx_textureclock(fb_RGB565_BS_ctx));
         ctx_set_textureclock(fb_RGB8_ctx, ctx_textureclock(fb_RGB565_BS_ctx));
         ctx_set_textureclock(fb_GRAY8_ctx, ctx_textureclock(fb_RGB565_BS_ctx));
         ctx_set_textureclock(fb_GRAYA8_ctx, ctx_textureclock(fb_RGB565_BS_ctx));
@@ -320,11 +376,16 @@ static void st3m_gfx_task(void *_arg) {
         void *user_fb = st3m_fb;
         void *osd_fb = st3m_osd_fb;
         int bits = st3m_gfx_bpp(set_mode);
+
         switch (bits) {
             case 4:
                 break;
             case 8:
-                user_target = fb_GRAY8_ctx;
+            case 9:
+                if ((set_mode & 0xf) == 9)
+                    user_target = fb_RGB332_ctx;
+                else
+                    user_target = fb_GRAY8_ctx;
                 break;
             case 24:
                 user_target = fb_RGB8_ctx;
@@ -337,14 +398,26 @@ static void st3m_gfx_task(void *_arg) {
                 osd_fb = st3m_fb;
                 break;
         }
+        if ((set_mode & 0xf) == st3m_gfx_rgb332) bits = 9;
+
+        int scale = st3m_gfx_scale();
+        static int prev_scale = -1;
+        if (prev_scale != scale) {
+            st3m_gfx_viewport_transform(fb_GRAY8_ctx);
+            st3m_gfx_viewport_transform(fb_GRAYA8_ctx);
+            st3m_gfx_viewport_transform(fb_RGB565_BS_ctx);
+            st3m_gfx_viewport_transform(fb_RGB332_ctx);
+            st3m_gfx_viewport_transform(fb_RGBA8_ctx);
+            st3m_gfx_viewport_transform(fb_RGB8_ctx);
+        }
 
         if ((set_mode & st3m_gfx_direct_ctx) == 0)
             ctx_render_ctx(drawlist->user_ctx, user_target);
 
-        if ((set_mode & st3m_gfx_osd) &&
-            (drawlist->osd_y0 != drawlist->osd_y1)) {
+        if (scale || ((set_mode & st3m_gfx_osd) &&
+                      (drawlist->osd_y0 != drawlist->osd_y1))) {
             pthread_mutex_lock(&st3m_osd_mutex);
-            flow3r_bsp_display_send_fb_osd(user_fb, bits, osd_fb,
+            flow3r_bsp_display_send_fb_osd(user_fb, bits, scale, osd_fb,
                                            drawlist->osd_x0, drawlist->osd_y0,
                                            drawlist->osd_x1, drawlist->osd_y1);
             pthread_mutex_unlock(&st3m_osd_mutex);
@@ -618,6 +691,9 @@ void st3m_gfx_init(void) {
     fb_GRAY8_ctx = ctx_new_for_framebuffer(
         st3m_fb, FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT,
         FLOW3R_BSP_DISPLAY_WIDTH, CTX_FORMAT_GRAY8);
+    fb_RGB332_ctx = ctx_new_for_framebuffer(
+        st3m_fb, FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT,
+        FLOW3R_BSP_DISPLAY_WIDTH, CTX_FORMAT_RGB332);
     fb_GRAYA8_ctx = ctx_new_for_framebuffer(
         st3m_fb, FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT,
         FLOW3R_BSP_DISPLAY_WIDTH * 2, CTX_FORMAT_GRAYA8);
@@ -635,6 +711,7 @@ void st3m_gfx_init(void) {
     assert(fb_RGB565_BS_ctx != NULL);
     assert(fb_RGBA8_ctx != NULL);
     assert(fb_RGB8_ctx != NULL);
+    assert(fb_RGB332_ctx != NULL);
 
     st3m_gfx_viewport_transform(fb_GRAY8_ctx);
     st3m_gfx_viewport_transform(fb_GRAYA8_ctx);
@@ -642,6 +719,8 @@ void st3m_gfx_init(void) {
     st3m_gfx_viewport_transform(fb_RGBA8_ctx);
     st3m_gfx_viewport_transform(fb_RGB8_ctx);
 
+    ctx_set_texture_source(fb_RGB332_ctx, fb_RGB565_BS_ctx);
+    ctx_set_texture_cache(fb_RGB332_ctx, fb_RGB565_BS_ctx);
     ctx_set_texture_source(fb_RGBA8_ctx, fb_RGB565_BS_ctx);
     ctx_set_texture_cache(fb_RGBA8_ctx, fb_RGB565_BS_ctx);
     ctx_set_texture_source(fb_RGB8_ctx, fb_RGB565_BS_ctx);
@@ -696,6 +775,7 @@ static void st3m_gfx_pipe_put(void) {
 
 static Ctx *st3m_gfx_ctx_int(st3m_gfx_mode mode);
 void st3m_gfx_end_frame(Ctx *ctx) {
+    ctx_restore(ctx);
     if (ctx == st3m_gfx_ctx_int(st3m_gfx_osd)) {
         pthread_mutex_unlock(&st3m_osd_mutex);
         return;
diff --git a/components/st3m/st3m_gfx.h b/components/st3m/st3m_gfx.h
index 038e072a94db4f7880ef33d26ce8f13b33bd4d36..cd9dcc1aa0672913e7cb9d0db1d6604c8a317168 100644
--- a/components/st3m/st3m_gfx.h
+++ b/components/st3m/st3m_gfx.h
@@ -17,13 +17,23 @@ typedef enum {
     // shallower pipeline, in the future might mean immediate mode
     st3m_gfx_low_latency = 512,
     st3m_gfx_unset = 1024,
+    st3m_gfx_force = 8192,
+    st3m_gfx_2x = 2048,
+    st3m_gfx_3x = 4096,
+    st3m_gfx_4x = 6144,
     // 4 and 8bpp modes use the configured palette, the palette resides
     // in video ram and is lost upon mode change
+    st3m_gfx_1bpp = 1,
+    st3m_gfx_2bpp = 2,
     st3m_gfx_4bpp = 4,
     // a flag for modes >4bpp requesting that ctx calls are direct, this is
     // slower since micropython cannot run in parallell with rasterization.
     st3m_gfx_8bpp = 8,
+    st3m_gfx_palette = 10,
     st3m_gfx_8bpp_osd = 8 + st3m_gfx_osd,
+    st3m_gfx_rgb332 = 9,
+    st3m_gfx_sepia = 10,
+    st3m_gfx_cool = 11,
     st3m_gfx_8bpp_direct_ctx = 8 + st3m_gfx_direct_ctx,
     st3m_gfx_8bpp_low_latency = 8 + st3m_gfx_low_latency,
     st3m_gfx_8bpp_osd_low_latency = 8 + st3m_gfx_osd + st3m_gfx_low_latency,
@@ -52,7 +62,7 @@ typedef enum {
 void st3m_gfx_set_default_mode(st3m_gfx_mode mode);
 
 // sets the current graphics mode
-void st3m_gfx_set_mode(st3m_gfx_mode mode);
+st3m_gfx_mode st3m_gfx_set_mode(st3m_gfx_mode mode);
 
 // gets the current graphics mode
 st3m_gfx_mode st3m_gfx_get_mode(void);
diff --git a/python_payload/st3m/run.py b/python_payload/st3m/run.py
index 6816ac113d3a30b46854e644fd0e4b7cd87c3e21..24ff5eab2ffc2ca2ede3ed6a98f44c91d4cab107 100644
--- a/python_payload/st3m/run.py
+++ b/python_payload/st3m/run.py
@@ -135,54 +135,6 @@ def run_app(klass):
     run_view(klass(ApplicationContext()))
 
 
-# 256 is overlay
-#
-
-
-def _8bpp() -> None:
-    sys_display.set_default_mode(8 + 256)
-
-
-def _8bpp_pal1() -> None:
-    sys_display.set_default_mode(9 + 256)
-
-
-def _8bpp_pal2() -> None:
-    sys_display.set_default_mode(10 + 256)
-
-
-def _8bpp_pal3() -> None:
-    sys_display.set_default_mode(11 + 256)
-
-
-def _8bpp_RGB332() -> None:
-    sys_display.set_default_mode(12 + 256)
-
-
-def _8bpp_3x() -> None:
-    sys_display.set_default_mode(8 + 256 + 4096)
-
-
-def _8bpp_low_latency() -> None:
-    sys_display.set_default_mode(8 + 256 + 512)
-
-
-def _16bpp_low_latency() -> None:
-    sys_display.set_default_mode(16 + 256 + 512)
-
-
-def _16bpp() -> None:
-    sys_display.set_default_mode(16 + 256)
-
-
-def _24bpp() -> None:
-    sys_display.set_default_mode(24 + 256)
-
-
-def _32bpp() -> None:
-    sys_display.set_default_mode(32 + 256)
-
-
 def _yeet_local_changes() -> None:
     os.remove("/flash/sys/.sys-installed")
     machine.reset()
@@ -216,17 +168,80 @@ def run_main() -> None:
     menu_gfx = SimpleMenu(
         [
             MenuItemBack(),
-            MenuItemForeground("Graphics Mode", menu_settings),
-            MenuItemAction("8bpp", _8bpp),
-            MenuItemAction("8bpp-low latency", _8bpp_low_latency),
-            # MenuItemAction("8bpp_3x", _8bpp_3x),
-            MenuItemAction("16bpp", _16bpp),
-            MenuItemAction("16bpp-low latency", _16bpp_low_latency),
-            MenuItemAction("24bpp", _24bpp),
-            MenuItemAction("8bpp Red", _8bpp_pal1),
-            MenuItemAction("8bpp Grayscale", _8bpp_pal2),
-            MenuItemAction("8bpp Cool", _8bpp_pal3),
-            MenuItemAction("8bpp RGB332", _8bpp_RGB332),
+            MenuItemAction(
+                "RGB565_BS", lambda: sys_display.set_default_mode(16 + sys_display.osd)
+            ),
+            MenuItemAction(
+                "RGB888", lambda: sys_display.set_default_mode(24 + sys_display.osd)
+            ),
+            MenuItemAction(
+                "RGB332",
+                lambda: sys_display.set_default_mode(
+                    sys_display.rgb332 + sys_display.osd
+                ),
+            ),
+            MenuItemAction(
+                "gray", lambda: sys_display.set_default_mode(8 + sys_display.osd)
+            ),
+            MenuItemAction(
+                "sepia",
+                lambda: sys_display.set_default_mode(
+                    sys_display.sepia + sys_display.osd
+                ),
+            ),
+            MenuItemAction(
+                "cool",
+                lambda: sys_display.set_default_mode(
+                    sys_display.cool + sys_display.osd
+                ),
+            ),
+            MenuItemAction(
+                "1x",
+                lambda: sys_display.set_default_mode(
+                    sys_display.unset + sys_display.x4
+                ),
+            ),
+            MenuItemAction("2x", lambda: sys_display.set_default_mode(sys_display.x2)),
+            MenuItemAction("3x", lambda: sys_display.set_default_mode(sys_display.x3)),
+            MenuItemAction("4x", lambda: sys_display.set_default_mode(sys_display.x4)),
+            MenuItemAction(
+                "osd on", lambda: sys_display.set_default_mode(sys_display.osd)
+            ),
+            MenuItemAction(
+                "osd off",
+                lambda: sys_display.set_default_mode(
+                    sys_display.unset + sys_display.osd
+                ),
+            ),
+            MenuItemAction(
+                "high fps",
+                lambda: sys_display.set_default_mode(
+                    sys_display.unset + sys_display.low_latency
+                ),
+            ),
+            MenuItemAction(
+                "low-latency",
+                lambda: sys_display.set_default_mode(sys_display.low_latency),
+            ),
+            MenuItemAction(
+                "drawlists",
+                lambda: sys_display.set_default_mode(
+                    sys_display.unset + sys_display.direct_ctx
+                ),
+            ),
+            MenuItemAction(
+                "direct ctx",
+                lambda: sys_display.set_default_mode(sys_display.direct_ctx),
+            ),
+            MenuItemAction(
+                "force mode", lambda: sys_display.set_default_mode(sys_display.force)
+            ),
+            MenuItemAction(
+                "force mode off",
+                lambda: sys_display.set_default_mode(
+                    sys_display.unset + sys_display.force
+                ),
+            ),
         ],
     )
     menu_system = SimpleMenu(